每次 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.jstouch 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 中......

“allTask​​s”内任何函数的任何更改都会在 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 & nodemon 导致的内存泄漏

如何让 Sinatra 在每次更改后自动重新加载文件?

每次我需要进行 React 更改时如何避免重新启动服务器?

Gulp Browsersync会在每次文件更改时导致多次重新加载

如何在修改 gulpfile.js 文件后自动重启 gulp?

每次重新启动计算机时 Main.storyboard 都会更改视图