【问题标题】:Grunt watch less on changed file onlyGrunt 仅在更改的文件上少看
【发布时间】:2014-05-12 04:32:12
【问题描述】:

我想要一个包含 2 个任务的 gruntfile:less(编译所有 less 文件)和 watch(监听更改并重新编译更改的文件)。

我有以下 Gruntfile.js:

module.exports = function(grunt) {
    var files = [
        {
            expand: true,
            cwd: 'media/less',
            src: ['*.less'],
            dest: 'media/css/',
            ext: '.css'
        },
        {
            expand: true,
            cwd: 'media/less/vendor',
            src: ['*.less'],
            dest: 'media/css/vendor/',
            ext: '.css'
        },
        {
            expand: true,
            cwd: 'media/admin/less',
            src: ['*.less'],
            dest: 'media/admin/css/',
            ext: '.css'
        }
    ];

    grunt.initConfig({
        less: {
            development: {
                options: {
                    compress: false,
                    yuicompress: true,
                    optimization: 2
                },
                files: files
            },
            production: {
                options: {
                    compress: true,
                    yuicompress: true,
                    optimization: 2
                },
                files: files
            }
        },
        watch: {
            styles: {
                files: ['media/**/*.less'],
                tasks: ['less:development'],
                options: {
                    nospawn: true
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('default', ['less:development']);
};

less 任务运行正常,没有任何问题。但是,watch 任务会侦听更改,但会在更改时重新编译所有文件。我怀疑这与我设置 less 任务的方式有关,因为我希望我的 less 文件列表是动态的,而不是手动添加每个文件。

根据this answer grunt 应该已经支持这个,但我不确定如何。

【问题讨论】:

    标签: gruntjs grunt-contrib-watch


    【解决方案1】:

    最终使用了watch 事件并覆盖了less 任务的files 属性。这是我的最终代码:

    module.exports = function(grunt) {
        var files = [
            {
                expand: true,
                cwd: 'media/less',
                src: ['*.less'],
                dest: 'media/css/',
                ext: '.css',
                extDot: 'last'
            },
            {
                expand: true,
                cwd: 'media/less/vendor',
                src: ['*.less'],
                dest: 'media/css/vendor/',
                ext: '.css',
                extDot: 'last'
            },
            {
                expand: true,
                cwd: 'media/admin/less',
                src: ['*.less'],
                dest: 'media/admin/css/',
                ext: '.css',
                extDot: 'last'
            }
        ];
    
        grunt.initConfig({
            less: {
                development: {
                    options: {
                        compress: false,
                        yuicompress: true,
                        optimization: 2
                    },
                    files: files
                },
                production: {
                    options: {
                        compress: true,
                        yuicompress: true,
                        optimization: 2
                    },
                    files: files
                }
            },
            watch: {
                styles: {
                    files: ['media/**/*.less'],
                    tasks: ['less:development'],
                    options: {
                        nospawn: true
                    }
                }
            }
        });
    
        grunt.event.on('watch', function(action, filepath){
            // ignore include files, TODO: have naming convention
            // if an include file has been changed, all files will be re-compiled
            if(filepath.indexOf('.inc.') > -1)
                return true;
    
            // might not be the most efficient way to do this
            var srcDir = filepath.split('/');
            var filename = srcDir[srcDir.length - 1];
            delete srcDir[srcDir.length - 1];
            srcDir = srcDir.join('/');
            var destDir = srcDir.replace(/less/g, 'css');
    
            grunt.config('less.development.files', [{
                src: filename,
                dest: destDir,
                expand: true,
                cwd: srcDir,
                ext: '.css',
                extDot: 'last'
            }]);
        });
    
        grunt.loadNpmTasks('grunt-contrib-less');
        grunt.loadNpmTasks('grunt-contrib-watch');
    
        grunt.registerTask('default', ['less:development']);
    };
    

    【讨论】:

      【解决方案2】:

      我不确定你的问题当前标题是什么意思Grunt watch less on changed file only。你的意思是这有问题吗?这是watch 任务的预期行为,它将监视指定的文件以进行更改并运行您指定的任务——在本例中为LESS 编译。

      我对您的文件做了一些更改。其中一些进行了简化,一些进行了更改,以保持脚本的灵活性和可扩展性。

      首先安装 underscore 作为依赖,通过运行:

      npm install underscore --save-dev
      

      然后对您的Gruntfile.js 进行以下更改:

      module.exports = function(grunt) {
      
          var _ = require('underscore');
      
          var files = {
              app : {
                  '<%= path.styles.css %>/styles.css' : '<%= path.styles.less %>/*.less'
              },
              vendor : {
                  '<%= path.styles.css %>/styles-vendor.css' : '<%= path.styles.vendor %>/*.less'
              },
              admin : {
                  '<%= path.styles.css %>/styles-admin.css' : '<%= path.styles.admin %>/*.less'
              }
          }
      
          function all() {
              'use strict';
              var allfiles = {},
                  i = {};
      
              for (i in files) {
                  _.extend(allfiles, files[i]);
              }
              return allfiles;
          }
      
          grunt.initConfig({
              path : {
                  media : 'media',
                  styles : {
                      css: 'media/css',
                      less: 'media/less',
                      admin: 'media/admin/less',
                      vendor: '<%= path.styles.less %>/vendor'                
                  }
              },
              less: {
                  development: {
                      options: {
                          compress: false,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: (all())
                  },
                  production: {
                      options: {
                          compress: true,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: (all())
                  }
              },
              watch: {
                  styles: {
                      files: ['<%= path.media %>/**/*.less'],
                      tasks: ['less:development'],
                      options: {
                          nospawn: true
                      }
                  }
              }
          });
      
          grunt.loadNpmTasks('grunt-contrib-less');
          grunt.loadNpmTasks('grunt-contrib-watch');
      
          // run several tasks as default (handy for complex projects)
          grunt.registerTask('dist', [ // run with 'grunt dist'
              'less:production'
          ]);
          grunt.registerTask('dev', [ // default, will run with 'grunt' only
              'less:development'
          ]);
      
          grunt.registerTask('default', 'dev');
      };
      

      如果您想要单独实际编译文件集(files.appfiles.vendorfiles.admin),您可能需要进一步拆分任务,如下所示:

              less: {
                  app: {
                      options: {
                          compress: false,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: files.app
                  },
                  vendor: {
                      options: {
                          compress: true,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: files.vendor
                  },
                  admin: {
                      options: {
                          compress: true,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: files.admin
                  },
                  development: {
                      options: {
                          compress: false,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: (all())
                  },
                  production: {
                      options: {
                          compress: true,
                          yuicompress: true,
                          optimization: 2
                      },
                      files: (all())
                  }
              },
              watch: {
                  all: {
                      files: ['<%= path.media %>/**/*.less'],
                      tasks: ['less:development'],
                      options: {
                          nospawn: true
                      }
                  },
                  app : {
                      files: ['<%= path.styles.less %>/*.less'],
                      tasks: ['less:app'],
                      options: {
                          nospawn: true
                      }
                  },
                  vendor : {
                      files: ['<%= path.styles.vendor %>/*.less'],
                      tasks: ['less:vendor'],
                      options: {
                          nospawn: true
                      }
                  },
                  admin : {
                      files: ['<%= path.styles.admin %>/*.less'],
                      tasks: ['less:admin'],
                      options: {
                          nospawn: true
                      }
                  }
              }
      

      然后您可以运行以下任何一个:

      grunt watch:app
      grunt watch:vendor
      grunt watch:admin
      

      您始终可以选择直接运行任务一次:

      grunt less:app
      grunt less:vendor
      grunt less:admin
      

      希望这会有所帮助!请注意,我没有对此进行测试。

      【讨论】:

      • 不是我想要的,虽然不远。所以所需的流程:我更改了一个文件,该文件被编译。当前流程:我更改了一个文件,所有文件都重新编译。使用您的解决方案(第二个),less:development 任务和less:app 任务都运行。另外,我也不想将 LESS 文件捆绑到一个 CSS 文件中,我想保持文件结构相同。
      • 我已经复制了您的设置,但无法解决难题。您提到的 SO 指出了在不同项目中提出的两个问题,它们试图处理相同的问题 [1] 和 [2],但尚未 100% 解决。在这一点上,我认为LESS 任务是基于文件夹的,Compass 任务(对于SASS)也是如此。对于Compass,他们甚至明确提到on their readme
      • 设法解决它。花了大约 3 个小时,但希望它现在可以正常工作。看看我的回答,看看我做了什么。
      猜你喜欢
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-04
      • 1970-01-01
      • 2018-08-22
      • 1970-01-01
      相关资源
      最近更新 更多