node.js Grunt:观看多个文件,仅编译已更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16788731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:37:39  来源:igfitidea点击:

Grunt: Watch multiple files, Compile only Changed

node.jscoffeescriptgruntjs

提问by justnorris

I'm new to Grunt, and so far I'm enjoying it very much. I want Grunt to compile only the changed files when running grunt watch

我是 Grunt 的新手,到目前为止我非常喜欢它。我希望 Grunt 在运行时只编译更改过的文件grunt watch

In my Grunfile.coffee I currently have (relevant parts).
Note: assets/javascript/app.coffee and assets/javascript/app.js are directories

在我的 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

There is probably a shorter way around, but I'm compiling app.coffee to app.js first, so that after I distribute my work, people who aren't comfortable with Coffeescript can browse the code in somewhat reasonable manner.

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

The problem with all this is that now that I save a Coffeescript file, I get too many steps ( I think ):

所有这一切的问题在于,现在我保存了一个 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...

Currently I'm just setting up my project, but I will have a lot more Coffeescript files, and I don't want Coffeescript to recompile all of the files, on each file change.

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

Furthermore, libs.js has no part in all of this at all, but I guess it is still compiled, because it also matches the "assets/*/.js" pattern.

此外,libs.js 根本没有参与所有这些,但我猜它仍然是编译的,因为它也匹配“assets/* /.js”模式。

Is there a way to make Grunt compile only the files that have changed ?

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

回答by justnorris

I've finally found a real solution!And it's super simple too!

我终于找到了真正的解决方案!而且也超级简单!

npm install grunt-newer --save-dev

npm install grunt-newer --save-dev

Then in your Gruntfile (after loading the task in grunt):

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

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

And that's it! The Awesome grunt-neweris awesome!

就是这样!The Awesome grunt-newer太棒了!

回答by Jamesgt

If you concat all .coffee sources into one .js file, then you will have to recompile it every time if any of your sources changes. Split it up to several .js files and make a releasetask where you only concat these .js files. This way you still only need to include one .js file.

如果您将所有 .coffee 源合并到一个 .js 文件中,那么如果您的任何源发生更改,则每次都必须重新编译它。将其拆分为多个 .js 文件,并在其中仅连接这些 .js 文件的位置执行发布任务。这样你仍然只需要包含一个 .js 文件。

See Using gruntjs, how do watch for changes in .coffee files?

请参阅使用 gruntjs,如何监视 .coffee 文件中的更改?

回答by Jof Arnold

The grunt.event.onevent detects changes in files, receiving an actionand filepathparameter.

grunt.event.on事件检测文件中的更改,接收一个actionandfilepath参数。

Here's an untested example based on one of my gruntfiles. In this case, all my source coffeescript files are kept in a directory called sources, and for previewing they are compiled and saved to an identical directory structure under a directory called dev

这是一个基于我的 gruntfiles 的未经测试的示例。在这种情况下,我所有的源代码 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"
)

Hope that helps.

希望有帮助。

EDIT:Probably not exactly what you want - because no doubt you want access to intermediary variables, actions and so forth - but you could use grunt to just run a shell coffee command. The grunt-shellnpm task does this, for example

编辑:可能不完全是你想要的——因为毫无疑问你想要访问中间变量、动作等等——但是你可以使用 grunt 来运行一个 shell coffee 命令。例如,grunt-shellnpm 任务就是这样做的

EDIT2:I've faced continued problems with grunt.watch.onnot working consistently in grunt 0.4.1 on OSX 10.8 and MacVim 7.3; for whatever reason, it stops watching. I've reverted back to just using the basic grunt initConfig object but with much more granularity so it only watches and compiles relatively small groups of files rather than the whole lot. This slows down the build time considerably, but it much more robust. Your mileage may very.

EDIT2:我一直面临着grunt.watch.on在 OSX 10.8 和 MacVim 7.3 上的 grunt 0.4.1 中无法持续工作的问题;无论出于何种原因,它都会停止观看。我已经恢复到只使用基本的 grunt initConfig 对象,但粒度要大得多,因此它只监视和编译相对较小的文件组,而不是整个文件组。这大大减慢了构建时间,但它更加健壮。你的里程可能会很大。

回答by Sebastian Hoitz

I've stumbled upon this, too and did not find any working versions that worked with the current version (0.4.1) But Jof Arnolds answer showed a good approach.

我也偶然发现了这一点,并没有找到任何适用于当前版本 (0.4.1) 的工作版本,但 Jof Arnolds 的回答显示了一个很好的方法。

This is what I came up with:

这就是我想出的:

# 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

I have a coffee section that looks somewhat like this:

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

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"
    ]