Grunt手表&少 - 如何让它更快? (仅编译已更改的文件)

时间:2015-10-09 18:51:53

标签: node.js gruntjs less grunt-contrib-less

我有一个使用LESS和grunt watch的基本应用程序来动态编译更改。

很长一段时间以来,我一直在抱怨当我更改任何LESS文件时,都会重新编译。浪费我的时间不能只编译所需的东西。但我希望它很聪明,所以如果有任何import,它也会编译受影响的文件,而不仅仅是被修改的文件。

今天我决定解决这个问题。这根本不容易。 Grunt手表不会照顾这一点,即使使用grunt-newer也没有解决,在这两种情况下都需要编写自定义规则。

最后,我没有使用https://github.com/tschaub/grunt-newer,因为它不能很好地与grunt-sync配合使用,但更重要的是,因为它不能满足我对LESS的需求,因为它无法处理LESS导入东西,所以它不会编译相关的文件,但只有已经更改的文件,它不是“智能”。

(可以自定义它以考虑那种东西,人们提供一些关于gist的脚本,但是没有任何官方的回购,所以很难找到你需要的东西,但绝对是值得一看。)

这是一个多次询问的问题,没有真正或简单的答案。参见:

How do you watch multiple files, but only run task on changed file, in Grunt.js?

Grunt watch: compile only one file not all

Grunt watch less on changed file only

Grunt: Watch multiple files, Compile only Changed

https://github.com/tschaub/grunt-newer/issues/29

https://gist.github.com/cgmartin/10328349

1 个答案:

答案 0 :(得分:0)

我的解决方案是一个自定义解决方案,特定于我的应用程序,但我希望它也可以用于你的!这很简单。

假设你有一个包含多个文件和目录(少)的styles文件夹,那么我的解决方案是定义一个白名单的文件夹,我不会编译所有较少的文件,但只有那些已被改变的人。

Grunt-less配置: https://gist.github.com/Vadorequest/bd46bb4d6c326e837710

Grunt-watch配置: https://gist.github.com/Vadorequest/b48bcfda2d0205ba3f95

文件夹架构: Folders architecture

到目前为止,处理此问题的“最简单”方法是覆盖grunt.watch事件,以便检查更改的文件是否可能影响其他文件。根据您自己的架构,有几种方法。我很简单,因为影响所有其他文件的文件位于styles文件夹的根目录或子文件夹内。所以我“只是”必须检查文件的filePath是否属于白名单。如果是这样,那么我会动态更新grunt配置,更改属性src以仅匹配更改的文件名。

grunt.event.on('watch', function(action, filePath, watchedTargetName) {
        switch(watchedTargetName){
            /*
            Compile only what is needed.
            Based on a white list of sub folders within the "styles" directory.
            White listed folders will not require to compile all LESS file, but only the changed ones.
            Others will require to compile everything.
             */
            case 'styles':
                // Root path from where the files are located.
                var rootPath = 'assets/linker/styles/';
                // Path of the file
                var filePathRelativeToRootPath = path.relative(rootPath, filePath);
                // Grunt task name (see less.js)
                var gruntTask = 'less';
                // Sub task to use.
                var subTaskName = 'dev';
                // List of folders that don't need to recompile everything.
                var whiteListFolders = [
                    'common',
                    'devices',
                    'layous',
                    'themes',
                    'views',
                ];

                if(action === 'changed'){
                    var isDir = path.dirname(filePath) !== '';
                    var dirName = filePathRelativeToRootPath.split(path.sep)[0];

                    // If the file is a directory and is belongs to the white list then we will override the grunt config on the fly to compile only that file.
                    if(isDir && _.contains(whiteListFolders, dirName)){
                        // We load the less config located at tasks/config/less.js
                        var config = grunt.config(gruntTask);

                        // Checks for any misconfiguration.
                        if(!config){
                            log.error('There is no config for the grunt task named ' + gruntTask);
                        }

                        if(!config[subTaskName]){
                            log.error('There is no sub task named ' + subTaskName + " for the the grunt task named " + gruntTask);
                        }

                        // Update the files.src to be the path to the modified file (relative to srcDir).
                        // Instead of updating all files, it will only update the one that has been changed.
                        config[subTaskName].files[0].src = filePathRelativeToRootPath;
                        grunt.config("less", config);
                        console.info('watcher LESS - The file ' + filePath + ' is in the white list and will be updated alone.');
                    }else{
                        console.info('watcher LESS - The file ' + filePath + ' is not is the white list, all LESS files will be updated.');
                    }
                }
                break;
        }
    } );

基本上,如果我在ayolan.less目录中更改名为themes的文件,那么当我更新它时,将在内存中设置该文件。 (见https://gist.github.com/Vadorequest/b48bcfda2d0205ba3f95#file-watch-js-L80-L81

{
    dev: {
        files: [{
            expand: true,
            cwd: 'assets/linker/styles/',
            src: 'themes/ayolan.less',// This has been changed in memory, for this specific watch event.
            dest: '.tmp/public/linker/styles/',
            ext: '.css'
        }]
    }
}

这允许我现在使用http://www.browsersync.io/,在我对LESS文件进行简单更改之后大约1秒钟更新浏览器,大约是5秒之前,因为它必须编译所有LESS文件并复制他们。 (我也做了其他的性能变化,但它确实有助于实现这个目标!)