每次 Gulpfile 更改后如何重新启动 Gulp?
Posted
技术标签:
【中文标题】每次 Gulpfile 更改后如何重新启动 Gulp?【英文标题】:How can Gulp be restarted upon each Gulpfile change? 【发布时间】:2014-05-18 04:14:46 【问题描述】:我正在开发Gulpfile
。可以让它一改变就重新启动吗?我正在使用 CoffeeScript 开发它。 Gulp
是否可以监视 Gulpfile.coffee
以便在保存更改时重新启动?
【问题讨论】:
【参考方案1】:您可以创建一个task
,它将gulp.watch
用于gulpfile.js
和简单的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');
);
我使用yargs
来接受“主要任务”在我们需要重新启动时运行。所以为了运行它,你会调用:
gulp auto-reload --task watching-task
要进行测试,请致电touch gulpfile.js
或touch a.css
以查看日志。
【讨论】:
这是一个不错的技巧。我很想做的一件事是将任务命名为auto-reload
,并像gulp auto-reload --task foo
一样运行它,否则你可能会得到一个fork-bomb 以递归方式启动默认任务。
好建议@OverZealous。应用更改以避免未来读者出现此问题。
这似乎复杂,我希望它像it is with Grunt 一样简单
这个方法也有很多副作用,比如偶尔的错误(2014-07-29 11:48 gulp[74366] (CarbonCore.framework) FSEventStreamStart: register_with_server: ERROR: f2d_register_rpc() => (null) (-21)
),例如localhost:3000
使用 BrowserSync 时端口号递增
Om Windows 比 require('child_process') 更好用 require('child-proc')【参考方案2】:
我创建了gulper,它是 gulp.js cli 包装器,用于在 gulpfile 更改时重新启动 gulp。
您可以简单地将 gulp 替换为 gulper。
$ gulper <task-name>
【讨论】:
非常简单优雅的解决方案。 希望我早点看到这个。现在我坚持自己的实现:github.com/samvv/node-galop 真丢脸,自从我第一次看到这个答案以来,我已经使用了一年,现在我才发现我没有支持它。感谢您提供有用的工具! 适用于 Linux 和 Mac,但在 Windows 上失败 - 它尝试将 gulp 的 CMD 作为 JS 启动 你是明星伴侣 :)【参考方案3】:为此,我使用了一个小的 shell 脚本。这也适用于 Windows。
按Ctrl+C
停止脚本。
// gulpfile.js
gulp.task('watch', function()
gulp.watch('gulpfile.js', process.exit);
);
Bash shell 脚本:
# watch.sh
while true; do
gulp watch;
done;
Windows 版本:watch.bat
@echo off
:label
cmd /c gulp watch
goto label
【讨论】:
简单,易于理解(至少对我来说),当然没有泄漏。 这是唯一对我有用的,因为 gulper 在 Windows 上会出错。【参考方案4】:我在 Caio Cunha 的回答中遇到了一堆 EADDRINUSE
错误。我的 gulpfile 使用 connect 和 LiveReload 打开本地网络服务器。在旧进程被杀死之前,新的 gulp 进程似乎与旧进程短暂共存,因此即将死亡的进程仍在使用这些端口。
这是一个解决共存问题的类似解决方案,(主要基于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']);
);
效果很好,但有一个相当严重的副作用:最后一个 gulp 进程与终端断开连接。 所以当gulp watch
退出时,一个孤立的 gulp 进程仍在运行。我无法解决这个问题,可以手动终止额外的 gulp 进程,或者只是将语法错误保存到 gulpfile.js。
【讨论】:
重启任何任务:process.argv.shift(); spawn(process.argv.shift(), process.argv, stdio: 'inherit'); process.exit()
【参考方案5】:
另一个解决方案是刷新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);
);
);
【讨论】:
编辑:最好使用once
否则你可能会有内存泄漏
这仍然泄漏:(节点)警告:检测到可能的 EventEmitter 内存泄漏。添加了 11 个更改侦听器。使用emitter.setMaxListeners() 增加限制
我稍微修改了一下。问题是,即使你使用一次,观察者仍然在那里,所以你也必须end
它
最终我的解决办法是停止使用 gulp heh【参考方案6】:
我知道这是一个非常古老的问题,但它是 Google 上的热门评论,因此仍然非常相关。
这是一种更简单的方法,如果您的源 gulpfile.js 与正在使用的目录在不同的目录中。 (这很重要!)它使用 gulp 模块 gulp-newer 和 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() ;
) )
;
) ;
它是这样工作的:
技巧 1:gulp-newer 仅在源文件比当前文件更新时执行以下管道。这样我们就可以确保没有重启循环。 while 循环 会从命令字符串中删除 gulp 命令之前(包括 gulp 命令)之前的所有内容,因此我们可以传递任何参数。 child_process.spawn 生成一个新的 gulp 进程,将输入输出和错误传递给父进程。 技巧 2:process.exit 杀死当前进程。但是,该进程将等待死亡,直到子进程完成。还有许多其他方法可以将重启功能插入管道。 无论如何,我只是碰巧在我的每个 gulpfile 中都使用了 gulp-data。随意评论您自己的解决方案。 :)
【讨论】:
【参考方案7】:我一直在处理同样的问题,我的解决方案实际上非常简单。两件事。
npm install nodemon -g
(如果您愿意,也可以在本地)
使用 cmd 运行或在包中创建脚本,如下所示:
"dev": "nodemon --watch gulpfile.js --exec gulp"
只需输入npm run dev
--watch
指定要关注的文件。 --exec
表示执行下一行,gulp
是您的默认任务。如果您想要非默认任务,只需传入参数即可。
希望对您有所帮助。
编辑:让它变得花哨;) 现在,虽然第一部分应该实现您所追求的,但在我的设置中,我需要添加更多内容以使其真正成为用户朋友。我想要的是
-
首先打开页面。
查找 gulpfile.js 中的更改,如果有任何更改,请重新启动 gulp
大吃一惊,密切关注文件、重建和热重载
如果你只做我在第一部分所说的,它每次都会打开页面。要修复它,请创建一个将打开页面的 gulp 任务。像这样:
gulp.task('open', function()
return gulp
.src(config.buildDest + '/index.html')
.pipe(plugins.open(
uri: config.url
));
然后在我的主要任务中:
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);
);
然后将你的 npm 脚本修改为
"dev": "gulp open & nodemon --watch gulpfile.js --watch webpack.config.js --exec gulp dev"
会给你你想要的。首先打开页面,然后继续实时重新加载。顺便说一句,对于 livereload,我使用 connect 附带的那个,它总是使用相同的端口。希望它对你有用,享受吧!
【讨论】:
Nodemon 正是我所需要的。我完全忘记了它的存在。真可惜。 我推荐原始解决方案,而不是“花哨”添加,有两个建议:1)在 package.json 中将nodemon
添加到 optionalDependencies
和 2)在自述文件中提及【参考方案8】:
这是@CaioToOn 的另一个版本的重载代码,它更符合正常的 Gulp 任务过程。它也不依赖于yargs
。
需要生成并初始化进程变量(不需要yargs
):
var spawn = require('child_process').spawn;
var p;
默认的 gulp 任务是 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');
);
你的 watch 任务可能是你默认的 gulp 任务。将其重命名为 watch
并添加 gulp.watch()
用于查看您的 gulpfile 并在更改时运行 default
任务:
gulp.task('watch', ['sass'], function ()
gulp.watch("scss/*.scss", ['sass']);
gulp.watch('gulpfile.js', ['default']);
);
现在,只需运行 gulp
,如果您更改 gulpfile,它将自动重新加载!
【讨论】:
此答案未解决可能导致错误的打开连接。有关问题的解决方案,请参见此处:***.com/a/27477988/747749【参考方案9】:试试这段代码(仅限win32平台)
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');
);
);
【讨论】:
这是唯一适用于 Windows 的解决方案。但它仍然没有杀死前一个进程,最后我必须手动杀死所有产生的进程。 另外,如果你使用connect.reload()
,你需要在进程处理之前运行connect.serverClose()
。否则端口不会被释放并引发更多错误。【参考方案10】:
适用于 Windows 的一个很好的解决方案,它也适用于 Visual Studio 任务运行程序。
/// <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' );
);
与其他答案相比的主要变化:
使用 child-proc,因为 child_process 在 Windows 上失败。 看门狗会在文件更改时自行退出,因为在 Windows 中,gulp 调用包含在批处理脚本中。终止批处理脚本不会终止 gulp 本身,从而导致随着时间的推移产生多个手表。 基于更改构建:通常 gulpfile 更改也需要重新构建项目。【讨论】:
【参考方案11】:全局安装nodemon:npm i -g nodemon
并在您的 .bashrc(或 .bash_profile 或 .profile)中添加一个别名:
alias gulp='nodemon --watch gulpfile.js --watch gulpfile.babel.js --quiet --exitcrash --exec gulp'
这将监视文件 gulpfile.js 和 gulpfile.babel.js 的变化。 (见Google)
P.S. 这对于无休止的任务(如watch
)可能会有所帮助,但对于单次运行的任务则无济于事。我的意思是它使用 watch 所以即使在 gulp 任务完成后它也会继续处理。 ;)
【讨论】:
更好:将nodemon
添加到package.json中的"optionalDependencies"
,在package.json的"scripts"
中包含"dev":"nodemon --watch gulpfile.js --exec gulp dev"
,最后在项目README中提及。【参考方案12】:
这是一个简单易懂的简短版本,您可以将其设置为默认任务,因此您只需键入“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']);
【讨论】:
这对于 Windows 来说是什么?虽然是真的;部分返回'虽然不被识别为内部或外部命令..'【参考方案13】:我花了一整天的时间尝试在 Windows / Gulp 4.0.2 上完成这项工作,我(终于)成功了...
我使用了本页和另一页上人们提供的一些解决方案。这些都在 cmets 中......
“allTasks”内任何函数的任何更改都会在 gulpfile.js(或其他监视的文件)保存时生效...
还有一些没用的 cmets 和 console.logs,请随意删除它们... ;)
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://***.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;
【讨论】:
【参考方案14】:安装 gulp-restart
npm install gulp-restart
此代码对您有用。
var gulp = require('gulp');
var restart = require('gulp-restart');
gulp.task('watch', function()
gulp.watch(['gulpfile.js'], restart);
)
它会在你对 gulpfile.js 进行更改的地方重新启动 gulp
【讨论】:
gulp 4.0 on MacOs: TypeError: stdin.setRawMode is not a function at Object. (/.../node_modules/gulp-restart/index.js:18:7)跨度>以上是关于每次 Gulpfile 更改后如何重新启动 Gulp?的主要内容,如果未能解决你的问题,请参考以下文章
Gulp Browsersync会在每次文件更改时导致多次重新加载