Gulp 4, Tasks don't execute before calling watch - javascript

I am using Gulp 4 to compile my code from TypeScript to JavaScript and to build and serve the app.
I've come across one problem that I cannot solve.
I'd like to run the build, copy-html and copy-css tasks before some file gets changed.
According to Gulp documentation I just need to provide a config object with ignoreInitial set to false, but it doesn't work.
I've tried to call the three tasks before I initialize browserSync but for it also didn't work for me.
gulp.task("serve", function() {
// TODO Make a build before first serve
browserSync.init({
server: {
baseDir: "./dist/"
}
});
gulp
.watch(["src/**/*.ts", "src/**/*.html", "src/**/*.css"], {
ignoreInitial: false
})
.on(
"change",
gulp.series(
gulp.parallel("copy-html", "copy-css"),
build,
browserSync.reload
)
);
});

Instead of using calling .on() on the returned chokidar interface, add your tasks to the watch command.
gulp
.watch(
["src/**/*.ts", "src/**/*.html", "src/**/*.css"],
{ ignoreInitial: false },
gulp.series(
gulp.parallel("copy-html", "copy-css"),
build,
browserSync.reload
)
)
);

Related

Task never defined: browserSync.reload

I upgraded from Gulp 3.x.x to Gulp 4.0.2 and began editing my gulpfile to make it compatible, but I'm stuck on this error I get when I try to run gulp:
AssertionError [ERR_ASSERTION]: Task never defined: browserSync.reload
Here is what I believe is the relevant portion of my gulpfile:
gulp.task('browserSync', function() {
browserSync({
server: {
baseDir: 'app'
},
browser: 'Chrome'
})
})
gulp.task('sass', function() {
return gulp.src('app/styles/**/*.scss') // Gets all files ending with .scss in app/scss and children dirs
.pipe(sass().on('error', sass.logError)) // Passes it through a gulp-sass, log errors to console
.pipe(gulp.dest('app/styles')) // Outputs it in the css folder
.pipe(browserSync.reload({ // Reloading with Browser Sync
stream: true
}));
})
// Watchers
gulp.task('watch', function() {
gulp.watch('app/styles/**/*.scss', gulp.series('sass'));
gulp.watch('app/*.html', gulp.series('browserSync.reload'));
gulp.watch('app/js/**/*.js', gulp.series('browserSync.reload'));
})
I'm using node version 11.15.0. Later versions were giving me problems.
Your immediate error is a result of these two lines:
gulp.watch('app/*.html', gulp.series('browserSync.reload'));
gulp.watch('app/js/**/*.js', gulp.series('browserSync.reload'));
Simply remove the quotes around the browserSync.reload calls:
gulp.watch('app/*.html', gulp.series(browserSync.reload));
gulp.watch('app/js/**/*.js', gulp.series(browserSync.reload));
If those calls were calls to tasks then it would be correct to put them into quotes. But your calls are not to tasks but to your const browserSync = require('browser-sync) package.
So it is confusing and will probably lead to errors to use the same identifier - browserSync for both your package require name and the task name as it appears you did.
As can be seen here:
gulp.task('browserSync', function() {
browserSync({
server: {
baseDir: 'app'
},
browser: 'Chrome'
})
})
The first use of browserSync is as a task name. The second, in the function body, is a reference to the package name. And the second is ultimately the one used in your watch tasks and would not be quoted there because it is not a task name. So using browserSync both ways is definitely confusing - just pick a different name for one like:
gulp.task('bSync', function() {
browserSync.init({......
Also note the init added to the above code. You will need it.

Grunt build for production?

I have two grunt configurations as shown below
grunt.registerTask('default', ['copy','jade','sass','browserify']);
grunt.registerTask('dev',['copy','jade','sass','browserify','watch']);
Now because i am using grunt-contrib-watch, i need to add script below
script(src='//localhost:35729/livereload.js')
for live-reload to work. How can i optionally add the script based on production environment. Having two index.jade file is a option and that gets me through this part, but there are a lot of other variables like api root etc that depends on build environment. What is the best practice in this case to build for production and dev environment ?
Edit
Just to be sure. the above index.jade was just an example.Consider the following line in js code
RestangularProvider.setBaseUrl("http://localhost:3000");
The parameter needs to be separate for both dev and production. It would be totally illogical to have two copies of code for production and dev.
I prefer to use params like --build
index.jade
if env.debug
script(src='//localhost:35729/livereload.js')
Gruntfile
module.exports = function(grunt) {
var DEBUG = grunt.option('build') === 'dev';
// Configure Jade to conditionally render livereload.js
// with DEBUG === true
grunt.initConfig({
pug: {
options: {
data: function() {
return {
env: {
debug: DEBUG
}
};
}
}
}
});
}
Use it like
grunt dev --build=dev
You can pass any env specific data via Grunt
grunt --build=dev \
--api-endpoint=/api/foo

How should project-level bundling be handled for non SPA use?

I am learning browserify and I am trying to do two basic things with it:
Transform (via shim) non-CommonJS modules for ease-of-use and dependency tracking
Bundle the libraries that are project-specific
I've found a working process for how to do all of this and automate it with Gulp. This works and produces the right output but, I am curious if it could be made simpler. It seems like I have to duplicate a lot of configuration on the project-based bundles. Here is the working example:
package.json
invalid comments added for clarification
{
//project info and dependencies omitted
//https://github.com/substack/node-browserify#browser-field
"browser": { //tell browserify about some of my libraries and where they reside
"jquery": "./bower_components/jquery/dist/jquery.js",
"bootstrap": "./bower_components/bootstrap/dist/js/bootstrap.js"
},
"browserify": {
//https://github.com/substack/node-browserify#browserifytransform
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
//shim the modules defined above as needed
"jquery": {
"exports": "$"
},
"bootstrap": {
"depends": "jquery:$"
}
}
}
config.js
contains all task-runner related configuration settings
module.exports = {
browserify: {
// Enable source maps and leave un-ulgified
debug: true,
extensions: [],
//represents a separate bundle per item
bundleConfigs: [
{
//I really want to refer to the bundles here made in the package.json but
//if I do, the shim is never applied and the dependencies aren't included
entries: ['/bundles/shared-bundle.js'],
dest: '/dist/js',
outputName: 'shared.js'
}
]
},
//...
};
shared-bundle.js
acts as a bundling file where node loads the dependencies and at this point, the shim has been applied
require('bootstrap');
browserify-task.js
contains the browserify bundling gulp task
//module requires omitted
gulp.task('browserify', function (callback) {
var bundleQueue = config.bundleConfigs.length;
var browserifyBundle = function (bundleConfig) {
var bundler = browserify({
entries: bundleConfig.entries,
extensions: config.extensions,
debug: config.debug,
});
var bundle = function () {
return bundler.bundle()
// Use vinyl-source-stream to make the stream gulp compatible
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.on('end', reportFinished);
};
var reportFinished = function () {
if (bundleQueue) {
bundleQueue--;
if (bundleQueue === 0) {
// If queue is empty, tell gulp the task is complete
callback();
}
}
};
return bundle();
};
config.bundleConfigs.forEach(browserifyBundle);
});
In config.js where the first bundleConfig item's entries is a source to a file that has the require() modules, I'd like replace those with module names of modules defined in the package.json browser key.
In the config.js, if I change the bundle configuration to:
bundleConfigs: [
{
entries: ['bootstrap'],
dest: '/dist/js',
outputName: 'shared.js'
}
]
and run the gulp task, it will include bootstrap.js but it doesn't run the shim transformation. jQuery is not being included at all.
This leaves me with a few questions:
Is there a better way to be bundling my js for use in a non-SPA application (ie am I going about this the wrong way)?
If not, is there a way to ensure the shim transformation is run prior to the bundling so that I can have my bundle configuration in one place?
Certainly, you just have to tell your gulp file that it should shim first. Looks like you can add your own shim object when calling browserify from your gulp file. Check out this example
If you want to ensure everything is shimmed before you bundle them, use the deps array: "An array of tasks to be executed and completed before your task will run."
It would look something like this:
gulp.task('shim', function() {
// ...
});
gulp.task('browserify', ['shim'], function(){
// ...
});

Grunt plugins not found using load-grunt-config

I've split out my grunt plugins into their own files and I'm using the load-grunt-config (https://github.com/firstandthird/load-grunt-config) to call them:
module.exports = function (grunt) {
'use strict';
require('load-grunt-config')(grunt);
};
I've got sass, autoprefixer, cssmin and watch tasks working but I'm also using Browsersync and px-to-rem these two plugins return:
Warning: Task "remify" not found. Use --force to continue.
and
Warning: Task "browsersync" not found. Use --force to continue.
when called individually or as part of a bigger task.
I've followed the syntax for the separate.js files for these two plugin so I'm at a loss. For example the remify.js file which is called when running grunt is written like this
module.exports = {
dist: {
options: {
base: 16,
fallback: true,
fallback_existing_rem: true,
ignore: []
},
files: {
'css/style.css': 'css/style.css'
}
}
};
Any ideas where this is going wrong?
I've also set up a gist of the example code, include package.json and a aliases.yml
https://gist.github.com/sturobson/f88258fd010e901e24d9
You have to call the grunt plugin exactly what it is. So where I've got remify I should be using px_to_rem and where I've got browsersync and I should have browserSync.
Silly me.
you can pass a second argument to load-grunt-config to provide some options where you could also define some pattern which can be used by load-grunt-tasks which is used internally.
if you don't pass a second argument, it uses the default-pattern of load-grunt-tasks which is grunt-*.
so if you want to load all devDependencies without defining them seperatly, do it like this:
require('load-grunt-config')(grunt, {
loadGruntTasks: {
pattern: '*',
scope: 'devDependencies'
}
});

Gulp watch quits when failing task uses streamqueue

I'm watching for changes on files like this:
gulp.watch(['./src/js/**/*', './src/templates/**/*', config.vendor.js], ['js']);
Part of my build process involves using the "angular-filesort" module (don't think this is important though). If I implement the task as follows and use plumber, when filesort fails gulp doesn't quit and "watch" will keep checking for updates which is what I want:
gulp.task('js', function() {
gulp.src('./src/js/**/*.js').pipe(plumber()).pipe(angularFilesort());
});
However, if I wrap up this process in a streamqueue, gulp will exit when filesort fails which I don't want:
gulp.task('js', function() {
streamqueue({
objectMode: true
},
gulp.src('./src/js/**/*.js').pipe(plumber()).pipe(angularFilesort())
)
});
How can I fix this?
Specifically, I'm doing something like this to process 3 different sets of JavaScript files then concating them:
streamqueue({
objectMode: true
},
gulp.src(config.vendor.js),
gulp.src('./src/js/**/*.js').pipe(angularFilesort()),
gulp.src(['src/templates/**/*.html']).pipe(templateCache({
module: mainAngularModuleName
})))
.pipe(sourcemaps.init())
.pipe(concat('app.js'))
etc.
Is there perhaps a way I can do the above without streamqueue to work around this issue?
I had a similar issue and switching from streamqueue to stream-series resolved it for me. It's also cleaner than streamqueue because you don't need to specify the object mode.
I found reinstalling node and upgrading all my packages fixed this.

Categories

Resources