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?
问题:
回答1:
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.
回答2:
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>
回答3:
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
回答4:
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.
回答5:
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);
});
});
回答6:
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. :)
回答7:
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!
回答8:
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'});
}
}
});
});
回答9:
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.
回答10:
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. ;)
回答11:
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!
回答12:
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']);
回答13:
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