Webpack rebuilds even if there's no changed files in watch mode - javascript

I'm want to use webpack in watch mode (or with a dev server), but for some reason webpack rebuilds even if there's no changed files. I can't even imagine the reasons for this behavior, since the webpack doesn't say what exactly triggers the build.
class WatchRunPlugin {
apply(compiler) {
compiler.hooks.watchRun.tap('WatchRun', (comp) => {
if (comp.modifiedFiles) {
const changedFiles = Array.from(comp.modifiedFiles, (file) => `\n ${file}`).join('');
console.log('===============================');
console.log('FILES CHANGED:', changedFiles);
console.log('===============================');
}
});
}
}
module.exports = {
// ...
plugins: [
new WatchRunPlugin(),
// ...
],
watchOptions: {
aggregateTimeout: 500,
poll: 20000,
ignored: ['**/static', '**/node_modules'],
},
};
And here's the output:
===============================
FILES CHANGED:
/mnt/c/Users/Yoskutik/project/DesktopAccountDisabledPage.tsx
===============================
// Build info...
webpack 5.74.0 compiled successfully in 8875 ms
===============================
FILES CHANGED:
===============================
// Build info...
webpack 5.74.0 compiled successfully in 5100 ms
It builds once with the changed file, but for some reason after this build, it does it again with no changed files.
Could you suggest any ideas how to debug it?

Related

Gulpfile not compiling Scss & JS properly

I am trying to create a gulpfile.js to compile scss to css and JS components to a main JS file. But it's not working properly.
The issues i am facing, when I run the command gulp:
It doesn't compile JS components to a main JS file.
It compiles SCSS but when i save any file, the git-bash terminal executing files infinitely, here is the screenshot:
Here is my gulpfile.js:
"use strict";
const source = 'assets/';
// Load Modules
const { src, dest, watch, series } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const cssnano = require('cssnano');
const terser = require('gulp-terser');
const browsersync = require('browser-sync').create();
// Scss Task
function scssTask() {
return src(`${source}/scss/zaincss.scss`)
.pipe(sass())
.pipe(postcss([cssnano()]))
.pipe(dest(`${source}/css`));
}
// Javascript Task
function jsTask() {
return src(`${source}/js/scripts/*.js`)
.pipe(terser())
.pipe(dest(`${source}/js/scripts/`));
}
// BrowserSync Tasks
function browserSyncServe(done) {
browsersync.init({
server: {
baseDir: '.'
},
injectChanges: true
});
done()
}
function browserSyncReload(done) {
browsersync.reload();
done();
}
// Watch Task
function watchTask() {
watch('*.html', browserSyncReload);
watch(['assets/scss/**/*.scss', 'assets/js/**/*.js'], series(scssTask, jsTask, browserSyncReload));
}
// Default Gulp Task
exports.default = series(
scssTask, jsTask, browserSyncServe, watchTask
);
I have googled a lot, but i am stuck. Please help me.
Part of the problem is you are watching the same directory that you are storing your js files in:
// Javascript Task
function jsTask() {
return src(`${source}/js/scripts/*.js`)
.pipe(terser())
.pipe(dest(`${source}/js/scripts/`));
}
So you send the files to ${source}/js/scripts/ but you are watching that location in your watch task: 'assets/js/**/*.js'. So any change in that location starts the process all over again.
Store you minified js files someplace else than the same directory you are watching for changes.

Gulp 4 & BrowserSync: Style Injection?

I'm attempting to use browser-sync with Gulp 4, but bs is not preserving state, and instead does a full refresh. This is not very useful. It seems bs no longer supports true injection. I filed an issue on GH if you want to contribute.
Here is the pertinent code:
// styles:dev task
gulp.task('styles:dev', function() {
return gulp.src(config.src)
.pipe(sourcemaps.init())
.pipe(postcss(config.postcss.dev))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(config.dest.dev))
.pipe(browserSync.stream());
});
// browserSync task
gulp.task('browserSync', function(cb) {
browserSync.init(config, cb);
});
// Watch task:
gulp.task('watch:styles', function() {
return gulp.watch(config.paths.css,
gulp.series('styles:dev'));
});
gulp.task('watch', gulp.parallel('watch:styles'));
// default task
gulp.task('default',
gulp.series('clean:dev',
gulp.parallel('copy:dev', 'styles:dev'), 'browserSync', 'watch')
);
Thanks in advance.
Fixed. Here's where I went wrong:
The browser-sync constructor takes an options object, which can include a files array. Most of the tutorials I've read, including the gulpfile for Google's very own Web Starter Kit, do not include this. As it turns out, this is required for style injection to preserve state.
Furthermore, do not pass .stream() or .reload() as the final pipe in your styles task. It is not needed, and will short circuit style injection, forcing a full refresh.
Finally, the browserSync process must not be terminated, and watch and browserSync tasks must execute in parallel in order for live style injection to take place.
Hope this helps anybody facing this issue.
I also closed the corresponding github issue, and posted my gulpfile
Almost 3 years later Gulp 4 now looks a little bit different, see https://gulpjs.com/docs/en/getting-started/creating-tasks
To have a complete Gulp 4 kickstart example, see https://gist.github.com/leymannx/8f6a75e8ad5055276a71d2901813726e
// Requires Gulp v4.
// $ npm uninstall --global gulp gulp-cli
// $ rm /usr/local/share/man/man1/gulp.1
// $ npm install --global gulp-cli
// $ npm install
const { src, dest, watch, series, parallel } = require('gulp');
const browsersync = require('browser-sync').create();
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const sourcemaps = require('gulp-sourcemaps');
const plumber = require('gulp-plumber');
const sasslint = require('gulp-sass-lint');
const cache = require('gulp-cached');
// Compile CSS from Sass.
function buildStyles() {
return src('scss/ix_experience.scss')
.pipe(plumber()) // Global error listener.
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'compressed' }))
.pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7']))
.pipe(sourcemaps.write())
.pipe(dest('css/'))
.pipe(browsersync.reload({ stream: true }));
}
// Watch changes on all *.scss files, lint them and
// trigger buildStyles() at the end.
function watchFiles() {
watch(
['scss/*.scss', 'scss/**/*.scss'],
{ events: 'all', ignoreInitial: false },
series(sassLint, buildStyles)
);
}
// Init BrowserSync.
function browserSync(done) {
browsersync.init({
proxy: 'blog.localhost', // Change this value to match your local URL.
socket: {
domain: 'localhost:3000'
}
});
done();
}
// Init Sass linter.
function sassLint() {
return src(['scss/*.scss', 'scss/**/*.scss'])
.pipe(cache('sasslint'))
.pipe(sasslint({
configFile: '.sass-lint.yml'
}))
.pipe(sasslint.format())
.pipe(sasslint.failOnError());
}
// Export commands.
exports.default = parallel(browserSync, watchFiles); // $ gulp
exports.sass = buildStyles; // $ gulp sass
exports.watch = watchFiles; // $ gulp watch
exports.build = series(buildStyles); // $ gulp build

How to set React to production mode when using Gulp

I need to run React in production mode, which presumably entails defining the following somewhere in the enviornment:
process.env.NODE_ENV = 'production';
The issue is that I'm running this behind Tornado (a python web-server), not Node.js. I also use Supervisord to manage the tornado instances, so it's not abundantly clear how to set this in the running environment.
I do however use Gulp to build my jsx files to javascript.
Is it possible to somehow set this inside Gulp? And if so, how do I check that React is running in production mode?
Here is my Gulpfile.js:
'use strict';
var gulp = require('gulp'),
babelify = require('babelify'),
browserify = require('browserify'),
browserSync = require('browser-sync'),
source = require('vinyl-source-stream'),
uglify = require('gulp-uglify'),
buffer = require('vinyl-buffer');
var vendors = [
'react',
'react-bootstrap',
'jquery',
];
gulp.task('vendors', function () {
var stream = browserify({
debug: false,
require: vendors
});
stream.bundle()
.pipe(source('vendors.min.js'))
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('build/js'));
return stream;
});
gulp.task('app', function () {
var stream = browserify({
entries: ['./app/app.jsx'],
transform: [babelify],
debug: false,
extensions: ['.jsx'],
fullPaths: false
});
vendors.forEach(function(vendor) {
stream.external(vendor);
});
return stream.bundle()
.pipe(source('build.min.js'))
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('build/js'));
});
gulp.task('watch', [], function () {
// gulp.watch(['./app/**/*.jsx'], ['app', browserSync.reload]);
gulp.watch(['./app/**/*.jsx'], ['app']);
});
gulp.task('browsersync',['vendors','app'], function () {
browserSync({
server: {
baseDir: './',
},
notify: false,
browser: ["google chrome"]
});
});
gulp.task('default',['browsersync','watch'], function() {});
2017 - Edit: anyone trying to set up React in Gulp for a new project: Just use create-react-app
Step I: Add the following to your gulpfile.js somewhere
gulp.task('apply-prod-environment', function() {
process.env.NODE_ENV = 'production';
});
Step II: Add it to your default task (or whichever task you use to serve/build your app)
// before:
// gulp.task('default',['browsersync','watch'], function() {});
// after:
gulp.task('default',['apply-prod-environment', 'browsersync','watch'], function() {});
OPTIONAL: If you want to be ABSOLUTELY CERTAIN that you are in prod mode, you can create the following slightly enhanced task instead of the one in Step I:
gulp.task('apply-prod-environment', function() {
process.stdout.write("Setting NODE_ENV to 'production'" + "\n");
process.env.NODE_ENV = 'production';
if (process.env.NODE_ENV != 'production') {
throw new Error("Failed to set NODE_ENV to production!!!!");
} else {
process.stdout.write("Successfully set NODE_ENV to production" + "\n");
}
});
Which will throw the following error if NODE_ENV is ever not set to 'production'
[13:55:24] Starting 'apply-prod-environment'...
[13:55:24] 'apply-prod-environment' errored after 77 μs
[13:55:24] Error: Failed to set NODE_ENV to production!!!!
Similar to the other answers, but hopefully gives someone a starting point:
var vendorList = ['react', 'react-dom'];
gulp.task('vendor-dev', function() {
browserify()
.require(vendorList)
.bundle()
.on('error', handleErrors)
.pipe(source('vendor.js'))
.pipe(gulp.dest('./build/dev/js'));
});
gulp.task('vendor-production', function() {
process.env.NODE_ENV = 'production';
browserify()
.require(vendorList)
.bundle()
.on('error', handleErrors)
.pipe(source('vendor.js'))
.pipe(buffer())
.pipe(uglify({ mangle: false }))
.pipe(gulp.dest('./build/production/js'));
});
The main difference is I am explicitly setting the NODE_ENV prior to bundling the vendor libraries. Gulp tasks aren't guaranteed to run in order.
Am I running in production mode?
If you remove the uglify line (and prior buffer) you will notice that both the dev and production builds are near identical in size - and match in line count.
The difference is the production version will be littered with:
"production" !== "production" ? [show dev error] : [no nothing]
Most reputable minify'ers (I believe) will strip out deadend code, such as the above, which will always result in false.
But really how do I tell?
Easiest method to be sure, would be goto the console of your running application and type:
React.createClass.toString();
The output should be:
"function (e){var t=function(e,t,n){this.__reactAutoBindMap&&c(this),"[....and more and more]
If you find the createClass in the react source, you will see:
createClass: function (spec) {
var Constructor = function (props, context, updater) {
// This constructor is overridden by mocks. The argument is used
// by mocks to assert on what gets mounted.
if ("production" !== 'production') {
"production" !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: react-legacyfactory') : undefined;
}
// Wire up auto-binding
if (this.__reactAutoBindMap) {
bindAutoBindMethods(this);
}
Notice how the console output skips straight through to this.__reactAutobind, because you are running in production mode, and using an minify'er, all the !== 'production' warngins and checks have been skipped over.
Unfortunately none of the above answers work, because setting process.env.NODE_ENV has no effect in Browserify. The resulting bundle still has process.env.NODE_ENV references in it and hence
Browserify will not require() the React production version modules,
the minifier will not be able to remove dead code, and
the application will still be running in debug mode.
This is unfortunately not the only place where this approach is offered as the correct answer :-(
The correct approach can be found in e.g.
https://github.com/hughsk/envify/issues/15#issuecomment-62229101
https://reactjs.org/docs/optimizing-performance.html#browserify
You need to switch the envify transform to be a global one, e.g.
# note the "-g" instead of the usual "-t"
$ browserify ... -g [ envify --NODE_ENV production ] ....
or in gulpfile.js
browserify(...)
...
.transform('envify', {
global: true, // also apply to node_modules
NODE_ENV: debug ? 'development' : 'production',
})
...
.bundle()
...
.pipe(gulpif(!debug, babelMinify())) // my example uses gulp-babel-minify
...
To set React in production mode you need to set your NODE_ENV variable to production and uglify your JS as an extra step.
You're already taking care of the uglification, for setting your NODE_ENV variable :
Set the variable while running the gulp task :
NODE_ENV='production' gulp
OR set it from inside your gulpfile by doing something like this :
gulp.task('set-production-env', function() {
return process.env.NODE_ENV = 'production';
});
Also you may use handy way with gulp-environments:
var environments = require('gulp-environments');
var production = environments.production;
gulp.src(paths.js)
.pipe(concat("app.js"))
// only minify the compiled JS in production mode
.pipe(production(uglify()))
.pipe(gulp.dest("./public/app/js/"));
To run gulp in production mode:
gulp build --env=production

Gruntfile.js error on windows

I am following this tutorial Link. I am using a windows PC
My SASS version is 3.4.16
This is my Gruntfile.js
module.exports = function(grunt) {
// Read package.json
grunt.file.readJSON('package.json');
//Initialize grunt
grunt.initConfig({
// Sass task
sass: {
// Sass development options
dev: {
options: {
style: 'expanded',
},
files: {
'css/main.css': 'css/sass/dev.scss'
}
},
// Sass distribution options
dist: {
options: {
style: 'compressed'
},
files: {
'css/main.css': 'css/sass/main.scss'
}
}
},
});
// Load tasks
grunt.loadNpmTasks('grunt-contrib-sass');
// Create Default Task
grunt.registerTask('dev', [
'sass:dev' // Compile Sass with dev settings
]);
// Create Distribution Task
grunt.registerTask('dist', [
'sass:dist' // Compile Sass with distribution settings
]);
}
When I reun this code i get an error as
Running "sass:dist" (sass) task Errno::ENOENT: No such file or
directory # rb_sysopen - undefined Use --trace for backtrace.
Warning: Exited with error code 1 Use --force to continue.
Could someone please help me with this.

Using grunt as a service

I am trying to build custom themes for my users. They do so by changing some less variables. I then store these to do and grunt there theme into a css which is then uploaded to server.
My problem is with the less grunting. Here is my code:
Gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-less');
};
In nodejs
module.exports.test = function(req,res){
grunt.initConfig({
globalConfig: {
id: req.insertId
},
less: {
default: {
options: {
modifyVars: req.body.less
},
'files': {
"/tmp/theme<%= globalConfig.id %>.css": "templates/app.less"
}
}
}
});
grunt.tasks(['less']);
});
The problem is that in my console
Running "less:default" (less) task File /tmp/theme26.css created: 0 B
→ 9.22 kB
Done, without errors.
worker undefined died. spawning a new process...
Why does grunt kill my process? How can I prevent this?

Categories

Resources