如何使用grunt-contrib-watch和grunt-contrib-coffee只在需要时编译CoffeeScript?

10

我希望只对我保存的单个文件运行咖啡渣检查和咖啡渣编译。我的项目中有数百个 CoffeeScript 文件,编译所有这些文件需要太多时间。

这是我的 Gruntfile:

module.exports = (grunt) ->

  grunt.initConfig

    pkg: grunt.file.readJSON 'package.json'

    coffee:
      all:
        expand: true
        bare: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'

    coffeelint:
      all: ['src/coffeescript/**/*.coffee']

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['coffeelint', 'coffee']
        options:
          spawn: false

  grunt.event.on 'watch', (action, filepath) ->
    grunt.config(['coffeelint', 'all'], filepath)
    grunt.config(['coffee', 'all'], filepath)

  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-watch'

  grunt.registerTask 'default', ['coffeelint', 'coffee', 'watch']

coffeelint任务仅在更改的文件上成功运行。

即使grunt表示正常运行,咖啡编译也不会产生任何JS文件。

以下是保存单个coffee文件后的输出:

OK
>> File "src/coffeescript/app.coffee" changed.


Running "coffeelint:all" (coffeelint) task
>> 1 file lint free.

Running "coffee:all" (coffee) task

Running "watch" task
Completed in 0.009s at Sat Feb 01 2014 13:10:07 GMT-0600 (CST) - Waiting...

这里有什么问题?非常感谢任何帮助!

更新:

这是一个可行的例子:

module.exports = (grunt) ->

  fs = require 'fs'
  isModified = (filepath) ->
    now = new Date()
    modified =  fs.statSync(filepath).mtime
    return (now - modified) < 10000

  grunt.initConfig

    coffee:
      options:
        sourceMap: true
        bare: true
        force: true # needs to be added to the plugin
      all:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'
      modified:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        dest: 'public/js/compiled'
        ext: '.js'
        filter: isModified

    coffeelint:
      options:
        force: true
      all:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
      modified:
        expand: true
        cwd: 'src/coffeescript/'
        src: '**/*.coffee'
        filter: isModified

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['coffeelint:modified', 'coffee:modified']

  grunt.loadNpmTasks 'grunt-coffeelint'
  grunt.loadNpmTasks 'grunt-contrib-coffee'
  grunt.loadNpmTasks 'grunt-contrib-watch'

  grunt.registerTask 'default', ['coffeelint:all', 'coffee:all', 'watch']
4个回答

10
你可以使用grunt-newer 当源文件比其编译输出的时间戳更新时,才重新编译这些文件。

安装方法:

npm install grunt-newer --save-dev

然后稍微修改一下你的coffeescript任务。如果你到Grunt.js文档中的“动态构建文件对象”部分,你会发现你需要将与文件位置和已编译输出位置相关的信息存储在一个files数组中,以使任务正确执行。

然后可以使用选项对象指定其他选项,例如bare: true

因此,对于你的coffee任务,请这样做:

   coffee:
      all:
        files: [{
          expand: true
          cwd: 'src/coffeescript/'
          src: '**/*.coffee'
          dest: 'public/js/compiled'
          ext: '.js'
        }]
        options:
          bare: true
          spawn: false

那么在您的观察任务中使用新版本,就像这样:

    watch:
      coffeescript:
        files: ['src/**/*.coffee']
        tasks: ['newer:coffeelint:all', 'newer:coffee:all']
        options:
          spawn: false

较新的文件将只编译那些比它们编译版本更晚的文件。


这只编译已更改的咖啡文件,但它在所有咖啡文件上运行咖啡链接 :-( - Eric the Red
是的,我也有同样的问题。 - svlada

4

尝试在您的C任务中添加类似以下内容的代码:

 coffee:
  all:
    filter: (filepath) ->
        fs = require('fs')
        now = new Date()
        modified =  fs.statSync(filepath).mtime
        return (now - modified) < 10000 # or another difference in millyseconds

请参阅文档以了解更多相关的IT技术信息。


0

这里有两个问题。

第一个问题:

Grunt生成的更改文件路径是src/coffeescript/some_file.coffee,但在你的coffee任务中,你已经将cwd定义为src/coffeescript

所以,coffee任务实际上只期望得到some_file.coffee,但它却得到了src/coffeescript/some_file.coffee,然后将其扩展为src/coffeescript/src/coffeescript/some_file.coffee O_o

你的coffeelint任务没有任何cwd,所以它可以成功运行完整的文件路径。

相应地调整文件路径,或从coffee配置中删除cwd

grunt.config(['coffee', 'all'], filepath.replace("src/coffeescript", ""))

第二点:

这是一个小问题,可能不是必须的,但也要注意一下。

grunt.event.on 'watch', (action, filepath) ->
  grunt.config(['coffeelint', 'all'], filepath)
  grunt.config(['coffee', 'all'], filepath)
  ^^^^^^^ You might have to change above line to:
  grunt.config(['coffee', 'all', 'src'], filepath)

在您的coffeelint任务中,源直接设置在all下。但是在您的coffee任务中,源设置在all -> src下。反映相同的设置可能也很有用。
编辑:小附加说明

首先:>> 文件 "src/coffeescript/app.coffee" 已更改。 正在运行 "coffeelint:files" (coffeelint) 任务 >> 1 个文件无需代码检查。 正在运行 "coffee:files" (coffee) 任务 警告:无法读取 "undefined" 文件(错误代码:ENOENT)。 - Eric the Red
第二点:不会创建任何JavaScript文件。 - Eric the Red

0

不要使用任意的时间阈值,可以将每个修改时间存储在一个映射中:

fs = require 'fs'
mtimes = {}
isModified = (filepath) ->
    mtime = fs.statSync(filepath).mtime
    if mtimes[filepath]?
        return mtimes[filepath] < mtime
    else
        mtimes[filepath] = mtime
        return yes

可惜的是,grunt没有将目标文件路径作为第二个参数提供给过滤函数。这将使得可以简单地检查生成的文件是否存在且比源文件旧... Make已经默认提供了这个功能...


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