【问题标题】:How can Gulp be restarted upon each Gulpfile change?每次 Gulpfile 更改后如何重新启动 Gulp?
【发布时间】:2014-05-18 04:14:46
【问题描述】:

我正在开发Gulpfile。可以让它一改变就重新启动吗?我正在使用 CoffeeScript 开发它。 Gulp 是否可以监视 Gulpfile.coffee 以便在保存更改时重新启动?

【问题讨论】:

    标签: javascript node.js workflow gulp gulp-watch


    【解决方案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 使用 connectLiveReload 打开本地网络服务器。在旧进程被杀死之前,新的 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-newergulp-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】:

      我一直在处理同样的问题,我的解决方案实际上非常简单。两件事。

      1. npm install nodemon -g(如果您愿意,也可以在本地)
      2. 使用 cmd 运行或在包中创建脚本,如下所示:

        "dev": "nodemon --watch gulpfile.js --exec gulp"
        
      3. 只需输入npm run dev

      --watch 指定要关注的文件。 --exec 表示执行下一行,gulp 是您的默认任务。如果您想要非默认任务,只需传入参数即可。

      希望对您有所帮助。

      编辑:让它变得花哨;) 现在,虽然第一部分应该实现您所追求的,但在我的设置中,我需要添加更多内容以使其真正成为用户朋友。我想要的是

      1. 首先打开页面。
      2. 查找 gulpfile.js 中的更改,如果有任何更改,请重新启动 gulp
      3. 大吃一惊,密切关注文件、重建和热重载

      如果你只做我在第一部分所说的,它每次都会打开页面。要修复它,请创建一个将打开页面的 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,它将自动重新加载!

      【讨论】:

      【解决方案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://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;
        

        【讨论】:

          【解决方案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)跨度>
          猜你喜欢
          • 2015-08-27
          • 2017-08-25
          • 2012-03-06
          • 2023-04-04
          • 1970-01-01
          • 1970-01-01
          • 2014-09-14
          • 2016-09-15
          • 2018-01-28
          相关资源
          最近更新 更多