2

我想要一个带有 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 文件列表是动态的,而不是手动添加每个文件。

根据这个答案grunt 应该已经支持这一点,但我不确定如何。

4

2 回答 2

1

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

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']);
};
于 2014-04-03T09:08:05.700 回答
0

我不确定你的问题的当前标题是什么意思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.app, files.vendor& files.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

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

于 2014-04-01T17:01:22.650 回答