Как я могу использовать grunt-contrib-watch и grunt-contrib-coffee для компиляции CoffeeScript только по мере необходимости?

Я бы хотел запустить кофейный линт и кофе, чтобы скомпилировать только один файл, который я сохраняю. В моем проекте сотни файлов 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 выполняется успешно только в измененном файле.

Компиляция кофе не создает никаких JS файлов, хотя хрюкает, что она работает.

Здесь вывод после сохранения одного файла кофе:

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...

Что здесь не так? Любая помощь будет принята с благодарностью!

Update:

Вот рабочий пример:

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

Ответ 1

Попробуйте добавить что-то подобное к вашей задаче 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

Подробнее в документации

Ответ 2

Вы можете использовать grunt-newer только для компиляции файлов, когда источник является более новым, чем его скомпилированный вывод.

Установите его с помощью:

npm install grunt-newer --save-dev

Затем немного измените задачу coffeescript. Если вы перейдете в раздел "Построение объекта файлов динамически" в Grunt.js docs, вы увидите, что вам нужно провести соответствующую информацию указать местоположение и местоположение скомпилированного вывода в массиве files для правильной работы задачи.

Дополнительные параметры, такие как bare: true, могут быть указаны с помощью объекта options.

Итак, для вашей задачи 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

Затем Newer только компилирует файлы, которые являются более поздними, чем их скомпилированные версии.

Ответ 3

Здесь есть две проблемы.

Во-первых:

Grunt создает измененный путь к файлу как src/coffeescript/some_file.coffee, но в вашей задаче coffee вы определили cwd как src/coffeescript.

Итак, задача на кофе действительно ожидает только some_file.coffee, но она получает src/coffeescript/some_file.coffee, а затем расширяет ее до src/coffeescript/src/coffeescript/some_file.coffee O_o

В вашей задаче coffeelint нет cwd, поэтому она успешно запускается с полным пути к файлу.

Соответственно отредактируйте путь к файлу или удалите 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. Также может быть полезно отразить то же самое.

РЕДАКТИРОВАТЬ: Незначительное дополнение

Ответ 4

Вместо использования произвольного порога продолжительности вы можете сохранить каждое время модификации на карте:

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

Это слишком плохо, хотя этот хрюканье не предоставляет путь к файлу назначения в качестве второго аргумента функции фильтра. Это позволило бы простой проверке увидеть, существует ли сгенерированный файл и старше источника... Make делает это из коробки...