使用grunt-contrib-watch进行两个目录的深度单向同步。代码可以工作,但是grunt-contrib-watch重新初始化的时间太慢。

14

我有两个目录srccompiled,我想使用Grunt Watch来确保从srccompiled的单向数据同步。作为中间步骤,我还想编译*.less文件以及一些使用ES6语法编写的*.js文件子集。

我已成功编写了所需任务:

// NOTE: Spawn must be disabled to keep watch running under same context in order to dynamically modify config file.
watch: {
  // Compile LESS files to 'compiled' directory.
  less: {
    options: {
      interrupt: true,
      spawn: false,
      cwd: 'src/less'
    },
    files: ['**/*.less'],
    tasks: ['less']
  },
  // Copy all non-ES6/LESS files to 'compiled' directory. Include main files because they're not ES6. Exclude LESS because they're compiled.
  copyUncompiled: {
    options: {
      event: ['added', 'changed'],
      spawn: false,
      cwd: 'src'
    },
    files: ['**/*', '!**/background/**', '!**/common/**', '!contentScript/youTubePlayer/**/*', '!**/foreground/**', '!**/test/**', '!**/less/**', '**/main.js'],
    tasks: ['copy:compileSingle']
  },
  // Compile and copy ES6 files to 'compiled' directory. Exclude main files because they're not ES6.
  copyCompiled: {
    options: {
      event: ['added', 'changed'],
      spawn: false,
      cwd: 'src/js'
    },
    files: ['background/**/*', 'common/**/*', 'contentScript/youTubePlayer/**/*', 'foreground/**/*', 'test/**/*', '!**/main.js'],
    tasks: ['babel:compileSingle']
  },
  // Whenever a file is deleted from 'src' ensure it is also deleted from 'compiled'
  remove: {
    options: {
      event: ['deleted'],
      spawn: false,
      cwd: 'src'
    },
    files: ['**/*'],
    tasks: ['clean:compiledFile']
  }
}

  grunt.event.on('watch', function(action, filepath, target) {
    // Determine which task config to modify based on the event action.
    var taskTarget = '';
    if (action === 'deleted') {
      taskTarget = 'clean.compiledFile';
    } else if (action === 'changed' || action === 'added') {
      if (target === 'copyCompiled') {
        taskTarget = 'babel.compileSingle';
      } else if (target === 'copyUncompiled') {
        taskTarget = 'copy.compileSingle';
      }
    }

    if (taskTarget === '') {
      console.error('Unable to determine taskTarget for: ', action, filepath, target);
    } else {
      // Drop src off of filepath to properly rely on 'cwd' task configuration.
      grunt.config(taskTarget + '.src', filepath.replace('src\\', ''));
    }
  });

这些任务监视相应的文件。事件处理程序动态修改clean copybabel任务,使它们适用于被添加 / 更改 / 删除的文件。

然而,我正在观察数千个文件,观察任务需要非常长的时间来初始化。在我的高端开发电脑上初始化需要6秒以上的时间。这个问题恶化了事实,观察任务在每个任务之后都会重新初始化

这意味着如果我有两个文件fileAfileB,我修改fileA并保存,那么将有一个6秒以上的时间段,其中观察无法检测到对fileB的修改。这导致我的两个目录之间出现不同步。

我在GitHub上找到了与我的问题相关的问题,但它仍然未解决:https://github.com/gruntjs/grunt-contrib-watch/issues/443

Github 上的讨论指出当spawn: false已设置时可能会出现此问题,但是根据 Grunt Watch 文档

如果需要动态修改配置,则必须禁用 spawn 选项,以使观察在同一上下文中运行。

因此,我认为我需要继续使用spawn: false

我必须假定这是 Grunt 任务的一个相当标准的过程。我是否忽略了显而易见的事情?Watch 任务是否不适合此目的?其他选择?


你有看过grunt-newer吗?听起来像是这个插件正好做了lowkay在打开的问题中提到的事情。 - DavidDomain
过去一两个小时一直在使用grunt-newer玩耍。对于编译代码它的效果不错,但是如果文件从“src”复制到“compiled”而又没有被更改,那么文件的“最后修改”时间就不会被更新。这将导致每次任务运行时都包括该文件。如果我能找到解决办法,那么grunt-newer将足够好用。 - Sean Anderson
1
你使用 jit-grunt 吗?这将有助于加快监视任务的速度。 - Prayag Verma
我会去看看!谢谢你的建议。我不知道它的存在。 - Sean Anderson
你是否有所有函数的详细日志,以了解每个函数所需的时间?明确一下,每次发生什么事情时,您是复制整个目录吗?而不仅仅是受影响的文件? - romuleald
1个回答

4

好的,我有一个可行的解决方案,但它并不美观。

最终我使用了grunt-newer来辅助解决问题。不幸的是,它与grunt-contrib-copy不兼容,因为复制文件不会更新其最后修改时间,所以grunt-newer将始终执行。

因此,我fork了grunt-contrib-copy并添加了一个选项来允许更新最后修改时间:https://github.com/MeoMix/grunt-contrib-copy

有了这个,现在我可以写:

// NOTE: Spawn must be disabled to keep watch running under same context in order to dynamically modify config file.
watch: {
  // Compile LESS files to 'compiled' directory.
  less: {
    options: {
      interrupt: true,
      cwd: 'src/less'
    },
    files: ['**/*.less'],
    tasks: ['less']
  },
  // Copy all non-ES6/LESS files to 'compiled' directory. Include main files because they're not ES6. Exclude LESS because they're compiled.
  copyUncompiled: {
    options: {
      event: ['added', 'changed'],
      cwd: 'src'
    },
    files: ['**/*', '!**/background/**', '!**/common/**', '!contentScript/youTubePlayer/**/*', '!**/foreground/**', '!**/test/**', '!**/less/**', '**/main.js'],
    tasks: ['newer:copy:compiled']
  },
  // Compile and copy ES6 files to 'compiled' directory. Exclude main files because they're not ES6.
  copyCompiled: {
    options: {
      event: ['added', 'changed'],
      cwd: 'src/js'
    },
    files: ['background/**/*', 'common/**/*', 'contentScript/youTubePlayer/**/*', 'foreground/**/*', 'test/**/*', '!**/main.js'],
    tasks: ['newer:babel:compiled']
  },
  // Whenever a file is deleted from 'src' ensure it is also deleted from 'compiled'
  remove: {
    options: {
      event: ['deleted'],
      spawn: false,
      cwd: 'src'
    },
    files: ['**/*'],
    tasks: ['clean:compiledFile']
  }
}

grunt.event.on('watch', function(action, filepath) {
  if (action === 'deleted') {
    // Drop src off of filepath to properly rely on 'cwd' task configuration.
    grunt.config('clean.compiledFile.src', filepath.replace('src\\', ''));
  }
});

现在,只有当“src”比“dest”新的情况下,才会复制ES6文件以及非LESS /非ES6文件。

不幸的是,grunt-newer并没有真正支持从“src”删除时进行同步删除操作。因此,我继续使用我的先前代码来处理“delete”操作。这仍然存在相同的缺陷,在删除后,观察任务会在一段时间内失效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接