Gulp task dependency - javascript

I would like to run (and complete) my "clean" task before running the rest of my build task.
This currently works, although "run" is deprecated and I'd like to replace it:
gulp.task('build', ['clean'],function() {
gulp.run(['styles-nomaps','usemin','scripts','assets']);
});
What's the proper syntax?

You can use the run-sequence plugin.

You can use rimraf util to clean files, it can be run in sync mode:
clean.js:
var gulp = require('gulp');
var rimraf = require('rimraf');
gulp.task('clean', function(cb) {
rimraf.sync(paths.assets, cb); // Make sure you pass callback
});

Related

gulp tasks sharing a common setting without a global object

I have a number of gulp tasks each residing in its own file (using the require-dir module) rather than a monolithic file.
I am using modules for configuration settings instead of json files (which I prefer for comments and for derived values).
To keep things simple here is an example setup with a single key I need to share/set between the gulp tasks.
/config/index.js
var config = {}
config.buildType = ''; // set this to either 'dev' or 'dist'
module.exports = config;
here is default task for which I want to set config.buildType to 'dev'
default.js
var gulp = require('gulp');
var config = require('../config/');
gulp.task('default', ['build'], function(cb) {
});
here is a deploy task for which I want to set buildType to 'dist'
deploy.js
var gulp = require('gulp');
var config = require('../config/');
gulp.task('deploy-s3', ['build'], function() {
});
here is a build task that I want to change based on buildType
build.js
var gulp = require('gulp');
var runSequence = require('run-sequence');
var config = require('../config/');
gulp.task('build', function(cb) {
console.log('in build',config.buildType);
if (config.buildType == 'dev') runSequence('clean',['sass',config.htmlGenerator], 'watch', cb);
if (config.buildType == 'dist') runSequence('clean',['sass',config.htmlGenerator], cb);
});
So here is the issue If I set config.buildType in default.js or deploy.js outside gulp.task then since they are all lumped into essentially one file by require-dir the value is simply whichever file was loaded last. If I set it inside the gulp.task function I am confused about about the timing/scope of that setting.
Update: Found this related issue https://github.com/gulpjs/gulp/issues/193. It was pointed out in this issue the task function starts after all the queued tasks so that means I can't set something inside the task function and expect it to be executed before the listed tasks (in my case 'build')
one poster made a task to set a parameter like this
gulp.task('set-dist', function () {
config.buildType = 'dist';
});
gulp.task('deploy', ['set-dist', 'build']);
So some advice..... do I go the way of this "hack" or is there some better way to do this??
(fyi, I am just a couple months into learning node/javascript on my own so my experience is limited)
You can use process.env to hold config attributes for your project. Check this.
In your case you can do:
var gulp = require('gulp');
var runSequence = require('run-sequence');
gulp.task('build', function(cb) {
if (process.env.NODE_ENV === 'development') {
runSequence('clean',['sass',config.htmlGenerator], 'watch', cb);
} else {
runSequence('clean',['sass',config.htmlGenerator], cb);
}
});
gulp build NODE_ENV=production for production
or gulp build NODE_ENV=development.
This will play nicely with existing CI tools like Travis.
Decided to go with this dropping the 'build' task altogether. It will hopefully work in some similar form after gulp 4.0 is released. It allows me to modify any setting before calling other tasks. Can use it with gulpif in tasks like my 'sass' task which is a pipe only task. Still wondering if there is a "better" way.
var gulp = require('gulp');
var config = require('../config/');
var runSequence = require('run-sequence');
gulp.task('default', function(cb) {
config.buildType='dev'
config.url = 'http://localhost:' + config.localport;
runSequence('clean',['sass',config.htmlGenerator],'watch', cb);
});

Using node.js functions in gulp task

I'm looking to integrate more-css(https://github.com/army8735/more) into my gulp workflow. I've tried several different options. I'm not sure what the syntax to include a function of this type would be. Could someone clarify?
gulp.task('more-css', function () {
var moreCss = require('more-css');
return gulp.src('./in')
.pipe(moreCss.compress('paint.css', true))
.pipe(gulp.dest('./out'));
});
#Pradyumna's answer is not correct; gulp plugins are basically transform streams. It's not enough to use the node API directly, you have to wrap it in some streaming logic. Having had a brief look around on npm, there isn't a gulp plugin that you can use for more-css, so I made one. Install with:
npm install gulp-more-css --save-dev
And a code example:
var gulp = require('gulp');
var moreCSS = require('gulp-more-css');
gulp.task('default', function() {
return gulp.src('./in')
.pipe(moreCSS())
.pipe(gulp.dest('./out'));
});
https://github.com/ben-eb/gulp-more-css
var moreCss=require('more-css');
gulp.task('build', function(){
var cssFile='paint.css';//path to paint.css
gulp.src(cssFile)
.pipe(moreCss.compress(gulp.src(cssFile), true))
.pipe(gulp.dest('./out'));
});

Running existing task with gulp-watch

I've got some tasks already defined in gulpfile.js and I want to use gulp-watch plugin (to run tasks on new files). My question is, because I couldn't find anything, can I run my existing tasks while running watch (from plugin) function?
var gulp = require('gulp'),
watch = require('gulp-watch'),
...;
gulp.task('lint', function () {
return gulp.src(path.scripts)
.pipe(jshint())
.pipe(jshint.reporter(stylish));
});
gulp.task('watch', function () {
watch({ glob: 'app/**/*.js' }); // Run 'lint' task for those files
});
Because I don't want to include watch() task in every task I have. I would like to have only 1 task - watch, which will combine all "watches".
----- EDIT ----
(as I probably didn't quite get my point):
I need to run task from inside of gulp('watch') task. for example:
like I did it with gulp.watch:
gulp.task('watch', function () {
gulp.watch('files', ['task1', 'task2']);
});
I need to do the same but with gulp-watch plugin, something like (I know it wouldn't work):
var watch = require('gulp-watch');
gulp.task('watch', function () {
watch({ glob: 'files' }, ['task1', 'task2']);
});
I have also run into the problem of wanting to use gulp-watch (not gulp.watch), needing to use the callback form, and having trouble finding a suitable way to run a task in the callback.
My use case was that I wanted to watch all stylus files, but only process the main stylus file that includes all the others. Newer versions of gulp-watch may address this but I'm having problems with 4.3.x so I'm stuck on 4.2.5.
gulp.run is deprecated so I don't want to use that.
gulp.start works well, but is also advised against by the gulp author, contra.
The run-sequence plugin works well and lets you define a run
order, but it is a self-proclaimed hack:
https://www.npmjs.com/package/run-sequence
Contra suggest writing plain old functions and calling
those. This is a new idea to me, but I think the example below captures the idea. https://github.com/gulpjs/gulp/issues/505
Take your pick.
var gulp = require('gulp'),
watch = require('gulp-watch'), // not gulp.watch
runSequence = require('run-sequence');
// plain old js function
var runStylus = function() {
return gulp.src('index.styl')
.pipe(...) // process single file
}
gulp.task('stylus', runStylus);
gulp.task('watch', function() {
// watch many files
watch('*.styl', function() {
runSequence('stylus');
OR
gulp.start('stylus');
OR
runStylus();
});
});
All of these are working for me without warnings, but I'm still unsure about getting the "done" callback from the 4.2.x version of gulp-watch.
You will most likely want to run specific tasks related to the files you are watching -
gulp.task('watch',['lint'], function () {
gulp.watch('app/**/*.js' , ['lint']);
});
You can also use the ['lint'] portion to run any required tasks when watch first gets called, or utilize the tasks to run async with
gulp.task('default', ['lint','watch'])
You can just call one task, that then includes both task
gulp.task('default', ['lint','watch'])
so here you would just call 'gulp'
gulp.task('watch', function() {
watch(files, function() {
gulp.run(['task1', 'task2']);
});
});
work fine, except a warning

Gulp Watch is not working

I'm new Gulp user, and I try simple script to watch compass, but it didn't work. But when I just run gulp compass gulp can compile it. Any ideas? Here my script:
var gulp = require('gulp'),
compass = require('gulp-compass'),
// Compass
gulp.task('compass', function() {
gulp.src('./assets/scss/*.scss')
.pipe(compass({
config_file: './config.rb',
css: './assets/css',
sass: './assets/scss'
}))
.pipe(gulp.dest('./assets/css'));
});
// Default task
gulp.task('default', function() {
gulp.start('compass');
});
// Watch
gulp.task('watch', function() {
// Watch .scss files
gulp.watch('./assets/scss/*.scss', ['compass']);
});
You've neglected to actually call the "watch" task, which is not the same thing as gulp.watch. Your default gulp task should instead look like:
gulp.task('default', function() {
gulp.start('compass');
gulp.start('watch');
});
but it should really just look like:
gulp.task('default', ['compass', 'watch']);
I changed gulp.watch source to ./assets/**/*.scss
IN GULP 4.X
You have to pass a function. The customary way of doing this in gulp 4.x is to pass a gulp.series() invocation with only one task name. This returns a function that only executes the specified task.
gulp.task('watch', function() {
gulp.watch('./assets/scss/*.scss', gulp.series('compass'))
});

How can Gulp be restarted upon each Gulpfile change?

I am developing a Gulpfile. Can it be made to restart as soon as it changes? I am developing it in CoffeeScript. Can Gulp watch Gulpfile.coffee in order to restart when changes are saved?
You can create a task that will gulp.watch for gulpfile.js and simply spawn another gulp child_process.
var gulp = require('gulp'),
argv = require('yargs').argv, // for args parsing
spawn = require('child_process').spawn;
gulp.task('log', function() {
console.log('CSSs has been changed');
});
gulp.task('watching-task', function() {
gulp.watch('*.css', ['log']);
});
gulp.task('auto-reload', function() {
var p;
gulp.watch('gulpfile.js', spawnChildren);
spawnChildren();
function spawnChildren(e) {
// kill previous spawned process
if(p) { p.kill(); }
// `spawn` a child `gulp` process linked to the parent `stdio`
p = spawn('gulp', [argv.task], {stdio: 'inherit'});
}
});
I used yargs in order to accept the 'main task' to run once we need to restart. So in order to run this, you would call:
gulp auto-reload --task watching-task
And to test, call either touch gulpfile.js or touch a.css to see the logs.
I created gulper that is gulp.js cli wrapper to restart gulp on gulpfile change.
You can simply replace gulp with gulper.
$ gulper <task-name>
I use a small shell script for this purpose. This works on Windows as well.
Press Ctrl+C to stop the script.
// gulpfile.js
gulp.task('watch', function() {
gulp.watch('gulpfile.js', process.exit);
});
Bash shell script:
# watch.sh
while true; do
gulp watch;
done;
Windows version: watch.bat
#echo off
:label
cmd /c gulp watch
goto label
I was getting a bunch of EADDRINUSE errors with the solution in Caio Cunha's answer. My gulpfile opens a local webserver with connect and LiveReload. It appears the new gulp process briefly coexists with the old one before the older process is killed, so the ports are still in use by the soon-to-die process.
Here's a similar solution which gets around the coexistence problem, (based largely on this):
var gulp = require('gulp');
var spawn = require('child_process').spawn;
gulp.task('gulp-reload', function() {
spawn('gulp', ['watch'], {stdio: 'inherit'});
process.exit();
});
gulp.task('watch', function() {
gulp.watch('gulpfile.js', ['gulp-reload']);
});
That works fairly well, but has one rather serious side-effect: The last gulp process is disconnected from the terminal. So when gulp watch exits, an orphaned gulp process is still running. I haven't been able to work around that problem, the extra gulp process can be killed manually, or just save a syntax error to gulpfile.js.
I've been dealing with the same problem and the solution in my case was actually very simple. Two things.
npm install nodemon -g (or locally if you prefer)
run with cmd or create a script in packages like this:
"dev": "nodemon --watch gulpfile.js --exec gulp"
The just type npm run dev
--watch specifies the file to keep an eye on. --exec says execute next in line and gulp is your default task. Just pass in argument if you want non default task.
Hope it helps.
EDIT : Making it fancy ;)
Now while the first part should achieve what you were after, in my setup I've needed to add a bit more to make it really user friend. What I wanted was
First open the page.
Look for changes in gulpfile.js and restart gulp if there are any
Gulp it up so keep an eye on files, rebuild and hot reload
If you only do what I've said in the first part, it will open the page every time. To fix it, create a gulp task that will open the page. Like this :
gulp.task('open', function(){
return gulp
.src(config.buildDest + '/index.html')
.pipe(plugins.open({
uri: config.url
}));
Then in my main tasks I have :
gulp.task('default', ['dev-open']);
gulp.task('dev-open', function(done){
plugins.sequence('build', 'connect', 'open', 'watch', done);
});
gulp.task('dev', function(done){
plugins.sequence('build', 'connect', 'watch', done);
});
Then modifying your npm scripts to
"dev": "gulp open & nodemon --watch gulpfile.js --watch webpack.config.js --exec gulp dev"
Will give you exactly what you want. First open the page and then just keep live reloading. Btw for livereload I use the one that comes with connect which always uses the same port. Hope it works for you, enjoy!
Another solution for this is to refresh the require.cache.
var gulp = require('gulp');
var __filenameTasks = ['lint', 'css', 'jade'];
var watcher = gulp.watch(__filename).once('change', function(){
watcher.end(); // we haven't re-required the file yet
// so is the old watcher
delete require.cache[__filename];
require(__filename);
process.nextTick(function(){
gulp.start(__filenameTasks);
});
});
I know this is a very old question, but it's a top comment on Google, so still very relevant.
Here is an easier way, if your source gulpfile.js is in a different directory than the one in use. (That's important!) It uses the gulp modules gulp-newer and gulp-data.
var gulp = require('gulp' )
, data = require('gulp-data' )
, newer = require('gulp-newer' )
, child_process = require('child_process')
;
gulp.task( 'gulpfile.js' , function() {
return gulp.src( 'sources/gulpfile.js' ) // source
.pipe( newer( '.' ) ) // check
.pipe( gulp.dest( '.' ) ) // write
.pipe( data( function(file) { // reboot
console.log('gulpfile.js changed! Restarting gulp...') ;
var t , args = process.argv ;
while ( args.shift().substr(-4) !== 'gulp' ) { t=args; }
child_process.spawn( 'gulp' , args , { stdio: 'inherit' } ) ;
return process.exit() ;
} ) )
;
} ) ;
It works like this:
Trick 1: gulp-newer only executes the following pipes, if the source file is newer than the current one. This way we make sure, there's no reboot-loop.
The while loop removes everything before and including the gulp command from the command string, so we can pass through any arguments.
child_process.spawn spawns a new gulp process, piping input output and error to the parent.
Trick 2: process.exit kills the current process. However, the process will wait to die until the child process is finished.
There are many other ways of inserting the restart function into the pipes.
I just happen to use gulp-data in every of my gulpfiles anyway. Feel free to comment your own solution. :)
Here's another version of #CaioToOn's reload code that is more in line with normal Gulp task procedure. It also does not depend on yargs.
Require spawn and initilaize the process variable (yargs is not needed):
var spawn = require('child_process').spawn;
var p;
The default gulp task will be the spawner:
gulp.task('default', function() {
if(p) { p.kill(); }
// Note: The 'watch' is the new name of your normally-default gulp task. Substitute if needed.
p = spawn('gulp', ['watch'], {stdio: 'inherit'});
});
Your watch task was probably your default gulp task. Rename it to watch and add a gulp.watch()for watching your gulpfile and run the default task on changes:
gulp.task('watch', ['sass'], function () {
gulp.watch("scss/*.scss", ['sass']);
gulp.watch('gulpfile.js', ['default']);
});
Now, just run gulp and it will automatically reload if you change your gulpfile!
try this code (only win32 platform)
gulp.task('default', ['less', 'scripts', 'watch'], function(){
gulp.watch('./gulpfile.js').once('change' ,function(){
var p;
var childProcess = require('child_process');
if(process.platform === 'win32'){
if(p){
childProcess.exec('taskkill /PID' + p.id + ' /T /F', function(){});
p.kill();
}else{
p = childProcess.spawn(process.argv[0],[process.argv[1]],{stdio: 'inherit'});
}
}
});
});
A good solution for Windows, which also works well with Visual Studio task runner.
/// <binding ProjectOpened='auto-watchdog' />
const spawn = require('child-proc').spawn,
configPaths = ['Gulpconfig.js', 'bundleconfig.js'];
gulp.task('watchdog', function () {
// TODO: add other watches here
gulp.watch(configPaths, function () {
process.exit(0);
});
});
gulp.task('auto-watchdog', function () {
let p = null;
gulp.watch(configPaths, spawnChildren);
spawnChildren();
function spawnChildren() {
const args = ['watchdog', '--color'];
// kill previous spawned process
if (p) {
// You might want to trigger a build as well
args.unshift('build');
setTimeout(function () {
p.kill();
}, 1000);
}
// `spawn` a child `gulp` process linked to the parent `stdio`
p = spawn('gulp', args, { stdio: 'inherit' });
}
});
Main changes compared to other answers:
Uses child-proc because child_process fails on Windows.
The watchdog exits itself on changes of files because in Windows the gulp call is wrapped in a batch script. Killing the batch script wouldn't kill gulp itself causing multiple watches to be spawned over time.
Build on change: Usually a gulpfile change also warrants rebuilding the project.
Install nodemon globally: npm i -g nodemon
And add in your .bashrc (or .bash_profile or .profile) an alias:
alias gulp='nodemon --watch gulpfile.js --watch gulpfile.babel.js --quiet --exitcrash --exec gulp'
This will watch for file gulpfile.js and gulpfile.babel.js changes. (see Google)
P.S. This can be helpful for endless tasks (like watch) but not for single run tasks. I mean it uses watch so it will continue process even after gulp task is done. ;)
Here's a short version that's easy to understand that you can set as a default task so you just need to type "gulp":
gulp.task('watch', function() {
const restartingGulpProcessCmd = 'while true; do gulp watch2 --colors; done;';
const restartingGulpProcess = require('child_process').exec(restartingGulpProcessCmd);
restartingGulpProcess.stdout.pipe(process.stdout);
restartingGulpProcess.stderr.pipe(process.stderr);
});
gulp.task('watch2', function() {
gulp.watch(['config/**.js', 'webpack.config.js', './gulpfile.js'],
() => {
console.log('Config file changed. Quitting so gulp can be restarted.');
process.exit();
});
// Add your other watch and build commands here
}
gulp.task('default', ['watch']);
I spent a whole day trying to make this work on Windows / Gulp 4.0.2, and I (finally) made it...
I used some solutions from people on this page and from one other page. It's all there in the comments...
Any change in any function inside "allTasks" will take effect on gulpfile.js (or other watched files) save...
There are some useless comments and console.logs left, feel free to remove them... ;)
const { gulp, watch, src, dest, series, parallel } = require("gulp");
const spawn = require('child_process').spawn;
// This function contains all that is necessary: start server, watch files...
const allTasks = function (callback) {
console.log('==========');
console.log('========== STARTING THE GULP DEFAULT TASK...');
console.log('========== USE CTRL+C TO STOP THE TASK');
console.log('==========');
startServer();
// other functions (watchers) here
// *** Thanks to Sebazzz ***
// Stop all on gulpfile.js change
watch('gulpfile.js', function (callback) {
callback(); // avoid "task didn't complete" error
process.exit();
});
callback(); // avoid "task didn't complete" error
}
// Restart allTasks
// ********************************************
// CALL GULPDEFAULT WITH THE GULP DEFAULT TASK:
// export.default = gulpDefault
// ********************************************
const gulpDefault = function (callback) {
let p = null;
watch('gulpfile.js', spawnChildren);
// *** Thanks to Sphinxxx: ***
// New behavior in gulp v4: The watcher function (spawnChildren()) is passed a callback argument
// which must be called after spawnChildren() is done, or else the auto-reload task
// never goes back to watching for further changes (i.e.the reload only works once).
spawnChildren(callback);
function spawnChildren(callback) {
/*
// This didn't do anything for me, with or without the delay,
// so I left it there, but commented it out, together with the console.logs...
// kill previous spawned process
if (p) {
// You might want to trigger a build as well
//args.unshift('build');
setTimeout(function () {
console.log('========== p.pid before kill: ' + p.pid); // a random number
console.log('========== p before kill: ' + p); // [object Object]
p.kill();
console.log('========== p.pid after kill: ' + p.pid); // the same random number
console.log('========== p after kill: ' + p); // still [object Object]
}, 1000);
}
*/
// `spawn` a child `gulp` process linked to the parent `stdio`
// ['watch'] is the task that calls the main function (allTasks):
// exports.watch = allTasks;
p = spawn('gulp', ['watch'], { stdio: 'inherit', shell: true });
// *** Thanks to people from: ***
// https://stackoverflow.com/questions/27688804/how-do-i-debug-error-spawn-enoent-on-node-js
// Prevent Error: spawn ENOENT
// by passing "shell: true" to the spawn options
callback(); // callback called - thanks to Sphinxxx
}
}
exports.default = gulpDefault;
exports.watch = allTasks;
Install gulp-restart
npm install gulp-restart
This code will work for you.
var gulp = require('gulp');
var restart = require('gulp-restart');
gulp.task('watch', function() {
gulp.watch(['gulpfile.js'], restart);
})
it will restart gulp where you do changes on the gulpfile.js

Categories

Resources