Grunt:监视多个文件,只编译更改的文件

42

我刚开始使用Grunt,到目前为止我非常喜欢它。我希望在运行grunt watch时,只编译已更改的文件。

在我的 Grunfile.coffee 文件中,我目前有以下相关部分。
注意:assets/javascript/app.coffee 和 assets/javascript/app.js 是目录。

    coffee:
        default:
            expand: true
            cwd: "assets/javascript/app.coffee"
            src: ["*.coffee"]
            dest: "assets/javascript/app.js"
            ext: ".js"

    uglify:
        dev:
            options:
                beautify: true
                compress: false
                mangle: false
                preserveComments: 'all'

            files: 
                "js/app.js": "assets/javascript/app.js/*.js"
                "js/libs.js": "assets/javascript/libs/*.js"

    watch:
        coffeescript:
            files: 'assets/javascript/**/*.coffee'
            tasks: ["coffee"]

        javascript:
            files: "assets/**/*.js"
            tasks: ["uglify:dev"]
        livereload:
            files: ["Gruntfile.coffee", "js/*.js", "*.php", "css/*.css", "images/**/*.{png,jpg,jpeg,gif,webp,svg}", "js/*.js", ]
            options:
                livereload: true

可能有更简短的方法,但我首先将app.coffee编译为app.js,这样在我分发作品后,不熟悉Coffeescript的人可以以比较合理的方式浏览代码。

问题在于现在当我保存Coffeescript文件时,我需要执行太多步骤(我认为):

>> File "assets/javascript/app.coffee/browse.coffee" changed.

Running "coffee:default" (coffee) task
File assets/javascript/app.js/browse.js created.
File assets/javascript/app.js/filters.js created.

Done, without errors.
Completed in 0.837s at Tue May 28 2013 12:30:18 GMT+0300 (EEST) - Waiting...
OK
>> File "assets/javascript/app.js/browse.js" changed.
>> File "assets/javascript/app.js/filters.js" changed.

Running "uglify:dev" (uglify) task
File "js/app.js" created.
File "js/libs.js" created.

Done, without errors.
Completed in 0.831s at Tue May 28 2013 12:30:19 GMT+0300 (EEST) - Waiting...
OK
>> File "js/app.js" changed.
>> File "js/libs.js" changed.

Completed in 0.000s at Tue May 28 2013 12:30:19 GMT+0300 (EEST) - Waiting...

目前我正在设置我的项目,但我将有更多的Coffeescript文件,我不希望Coffeescript在每次文件更改时重新编译所有文件。

此外,libs.js对此毫无作用,但我猜测它仍然会被编译,因为它也符合“assets/*/.js”模式。

有没有办法让Grunt只编译已更改的文件?


4个回答

75

我终于找到了一个真正的解决方案!而且它也非常简单!

npm install grunt-newer --save-dev

然后在您的Gruntfile中(在grunt加载任务之后):

watch:
    coffeescript:
        files: 'assets/javascript/**/*.coffee'
        tasks: ["newer:coffee"]

就是这样啦!grunt-newer 很棒!


1
太好了,正是我所需要的!我甚至不需要阅读任何文档或说明 - 它只是工作。 - Nick Perkins
1
grunt-newer有它的问题。例如,它不能与grunt-contrib-copy一起使用。这里是讨论链接https://github.com/tschaub/grunt-newer/issues/39 - svlada
1
“…这正是我所需要的!我甚至不需要阅读任何文档或说明书...” 一位经验丰富的开发人员会评论说,即使它可以直接在没有额外配置的情况下运行,但其文档也非常出色。scnr - try-catch-finally

2
如果您将所有的 .coffee 源代码合并到一个 .js 文件中,那么每次源代码发生变化时都需要重新编译。把它分成几个 .js 文件,并创建一个“发布”任务,只合并这些 .js 文件。这样您仍然只需要包含一个 .js 文件。
请参阅:Using gruntjs, how do watch for changes in .coffee files?

看,问题就在这里。我将每个Coffeescript文件编译为单独的JavaScript文件,因此编译器实际上不应触及其他coffeescript文件。然后将这些Javascript文件串联到app.js中,但这是一个单独的任务,也会意外地触发压缩libs.js的过程,这也是不必要的。 - pyronaur
然后,只需使用“!js/libs.js”从监视中排除lib.js。也许你可以编写自己的自定义过滤器,或者请求一个类似的功能 - Jamesgt
这实际上是最明智的解决方案,我会坚持它直到找到更好的东西... - pyronaur

1

grunt.event.on 事件检测文件的更改,接收actionfilepath参数。

以下是基于我的一个gruntfile的未经测试的示例。在这种情况下,所有源coffeescript文件都保存在一个名为sources的目录中,为了预览它们会被编译并保存到一个名为dev的目录下的相同目录结构中。

SOURCES_DIR = 'sources'
DEV_DIR = 'dev'

grunt.initConfig
  watch :
    all :
      files : ["**/*.coffee"]
  coffee :
    dev :
      files :
        dest : "app.js"
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-contrib-coffee'

grunt.registerTask 'build', ['coffee:dev']

grunt.event.on('watch', (action,filepath) ->
  # Determine the full directory of the changed file
  wdi = filepath.lastIndexOf '/'
  wd =  filepath.substring 0,wdi

  # remove `sources` prefix from that directory
  fpath = wd.replace(SOURCES_DIR,'') + '/'

  # determine the filename
  fnamei = filepath.lastIndexOf '.'
  fname = filepath.substring wdi+1,fnamei # NOTE: this breaks the case where in same dir

  # concatenate fpath and fname with the dir to be compiled into
  deststr = "#{DEV_DIR}#{fpath}#{fname}.coffee"


  # set coffee.dev.files value in the coffee task to have am entry of form {"destination":"source"}
  obj = {}
  obj[deststr] = filepath
  grunt.config "coffee.dev.files", obj

  # fire the coffee task
  grunt.task.run "coffee"
)

希望能有所帮助。
编辑:可能不完全符合您的要求,因为您无疑想要访问中间变量、操作等等,但是您可以使用grunt来运行shell coffee命令。例如,npm任务grunt-shell就可以实现这一点。
编辑2:我在OSX 10.8和MacVim 7.3上使用grunt 0.4.1时持续遇到grunt.watch.on不稳定的问题;由于某种原因,它停止了监视。我已经回归到只使用基本的grunt initConfig对象,但是具有更多的细节,因此它只监视和编译相对较小的文件组,而不是整个文件。这会显著减慢构建时间,但更加健壮。您的收益可能会有所不同。

谢谢,这看起来确实是我正在寻找的东西。稍后我会仔细研究它。 - pyronaur

0

我也遇到了这个问题,但没有找到任何适用于当前版本(0.4.1)的工作版本。但是Jof Arnold的答案提供了一个很好的方法。

这是我想出来的:

# only recompile changed files
grunt.event.on "watch", (action, filepath) ->
  # note that we have to manually change the target file name to 
  # our desired format
  targetName = filepath.replace(/\/(client|shared)/, "")
    .replace(".coffee", ".js")
    .replace("app/", "")

  options =
    src: filepath
    dest: "public/javascripts/#{targetName}"

  grunt.config ["coffee", "client"], options

我有一个咖啡部分,看起来有点像这样:

coffee:
  client:
    options:
      sourceMap: false
    files: [
      expand: true
      cwd: "app"
      src: ["*/client/**/*.coffee", "helpers/{client,shared}/*.coffee"]
      dest: "public/javascripts"
      rename: (folder, name) ->
        name = name.replace(/\/(client|shared)/, "")

        [folder, name].join path.sep
      ext: ".js"
    ]

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