32 votes

Grunt : Surveiller plusieurs fichiers, compiler uniquement les fichiers modifiés

Je suis nouveau sur Grunt, et jusqu'à présent, j'apprécie beaucoup. Je veux que Grunt compile uniquement les fichiers modifiés lors de l'exécution grunt watch

Dans mon Grunfile.coffee j'ai actuellement (parties pertinentes).
Note: assets/javascript/app.coffee et assets/javascript/app.js sont des répertoires

    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

Il y a probablement un moyen plus court, mais je compile d'abord app.coffee en app.js, afin que lorsque je distribue mon travail, les gens qui ne sont pas à l'aise avec Coffeescript puissent parcourir le code de manière raisonnable.

Le problème avec tout cela, c'est qu'une fois que j'enregistre un fichier Coffeescript, je trouve qu'il y a trop d'étapes (je pense) :

>> Fichier "assets/javascript/app.coffee/browse.coffee" modifié.

Exécution de la tâche "coffee:default" (coffee)
Fichier assets/javascript/app.js/browse.js créé.
Fichier assets/javascript/app.js/filters.js créé.

Terminé, sans erreurs.
Terminé en 0,837s le Mar Mai 28 2013 12:30:18 GMT+0300 (EEST) - En attente...
OK
>> Fichier "assets/javascript/app.js/browse.js" modifié.
>> Fichier "assets/javascript/app.js/filters.js" modifié.

Exécution de la tâche "uglify:dev" (uglify)
Fichier "js/app.js" créé.
Fichier "js/libs.js" créé.

Terminé, sans erreurs.
Terminé en 0,831s le Mar Mai 28 2013 12:30:19 GMT+0300 (EEST) - En attente...
OK
>> Fichier "js/app.js" modifié.
>> Fichier "js/libs.js" modifié.

Terminé en 0,000s le Mar Mai 28 2013 12:30:19 GMT+0300 (EEST) - En attente...

Actuellement, je suis en train de configurer mon projet, mais j'aurai beaucoup plus de fichiers Coffeescript, et je ne veux pas que Coffeescript recompile tous les fichiers à chaque modification de fichier.

De plus, libs.js n'a aucun lien avec tout cela, mais je suppose qu'il est toujours compilé, car il correspond également au motif "assets/*/.js".

Y a-t-il un moyen de faire en sorte que Grunt compile uniquement les fichiers qui ont été modifiés?

59voto

Norris Points 1206

J'ai enfin trouvé une vraie solution! Et c'est super simple aussi!

npm install grunt-newer --save-dev

Ensuite, dans votre Gruntfile (après avoir chargé la tâche dans grunt):

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

Et c'est tout! L'incroyable grunt-newer est génial!

2voto

Jamesgt Points 96

Si vous concaténez toutes les sources .coffee dans un fichier .js unique, vous devrez le recompiler à chaque fois qu'une de vos sources change. Divisez-le en plusieurs fichiers .js et créez une tâche release où vous ne concaténez que ces fichiers .js. De cette façon, vous n'avez toujours besoin d'inclure qu'un seul fichier .js.

Voir Utilisation de gruntjs, comment surveiller les changements dans les fichiers .coffee ?

1voto

Jof Arnold Points 1

L'événement grunt.event.on détecte les changements dans les fichiers, recevant un paramètre action et filepath.

Voici un exemple non testé basé sur l'un de mes gruntfiles. Dans ce cas, tous mes fichiers source coffeescript sont conservés dans un répertoire appelé sources, et pour l'aperçu, ils sont compilés et enregistrés dans une structure de répertoire identique sous un répertoire appelé 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) ->
  # Déterminer le répertoire complet du fichier modifié
  wdi = filepath.lastIndexOf '/'
  wd =  filepath.substring 0,wdi

  # supprimer le préfixe 'sources' de ce répertoire
  fpath = wd.replace(SOURCES_DIR,'') + '/'

  # déterminer le nom du fichier
  fnamei = filepath.lastIndexOf '.'
  fname = filepath.substring wdi+1,fnamei # NOTE: this breaks the case where in same dir

  # concaténer fpath et fname avec le répertoire dans lequel il doit être compilé
  deststr = "#{DEV_DIR}#{fpath}#{fname}.coffee"

  # définir la valeur de coffee.dev.files dans la tâche coffee pour avoir une entrée de la forme {"destination":"source"}
  obj = {}
  obj[deststr] = filepath
  grunt.config "coffee.dev.files", obj

  # lancer la tâche coffee
  grunt.task.run "coffee"
)

J'espère que cela vous aidera.

EDIT: Probablement pas exactement ce que vous voulez - car sans aucun doute vous voulez accéder à des variables intermédiaires, des actions, et ainsi de suite - mais vous pourriez utiliser grunt pour simplement exécuter une commande shell coffee. La tâche npm grunt-shell le fait, par exemple

EDIT2: J'ai rencontré des problèmes continus avec grunt.watch.on ne fonctionnant pas de manière cohérente dans grunt 0.4.1 sur OSX 10.8 et MacVim 7.3; pour une raison quelconque, il cesse d'observer. Je suis revenu à simplement utiliser l'objet grunt initConfig de base mais avec beaucoup plus de granularité pour qu'il ne surveille et compile que des groupes de fichiers relativement petits plutôt que le tout. Cela ralentit considérablement le temps de construction, mais c'est beaucoup plus robuste. À votre guise.

0voto

Sebastian Hoitz Points 4533

J'ai aussi rencontré ce problème et je n'ai trouvé aucune version fonctionnelle compatible avec la version actuelle (0.4.1) Mais la réponse de Jof Arnold a montré une bonne approche.

Voici ce que j'ai trouvé:

# recompiler uniquement les fichiers modifiés
grunt.event.on "watch", (action, filepath) ->
  # notez que nous devons changer manuellement le nom du fichier cible 
  # pour le format souhaité
  targetName = filepath.replace(/\/(client|shared)/, "")
    .replace(".coffee", ".js")
    .replace("app/", "")

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

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

J'ai une section "coffee" qui ressemble un peu à ceci:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X