Grunt:加载依赖项需要几分钟

时间:2016-12-22 15:24:58

标签: javascript node.js gruntjs

我已经将一些非常标准的grunt任务与合理数量的依赖项放在一起,但由于某种原因,实际加载依赖项需要1-3分钟。我是咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜咕噜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜

这是我的gruntfile的样子:

const path = require("path");

module.exports = function(grunt) {
    require('jit-grunt')(grunt);
    require('time-grunt')(grunt);

    const ignoredSourceScriptPatterns = ['!**/*.debug.js', '!**/*.min.js', '!scripts/*', '!**/*.map'],
        baseUIPath = 'presentation/ui',
        scripts = grunt.file.expand({filter: 'isFile',
            matchBase: true,
            cwd: baseUIPath},
        ['*.js', ...ignoredSourceScriptPatterns]);

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        copy: {
            build: {
                cwd: 'presentation/',
                src: 'ui/**',
                dest: path.join('presentation', 'static'),
                expand: true
            }
        },
        uglify: {
            options: {
                sourceMap: true,
                compress: false
            },
            build: {
                cwd: baseUIPath,
                files: function() {
                    var modules = grunt.file.expand({
                            filter: 'isDirectory',
                            expand: true,
                            cwd: 'presentation/ui/modules'
                        }, ['**', '!**/css', '!**/scripts', ...ignoredSourceScriptPatterns]),
                        components = grunt.file.expand({
                            filter: 'isFile',
                            expand: true,
                            cwd: 'presentation/ui'
                        }, ['components/!*.js', ...ignoredSourceScriptPatterns]),
                        files, componentFiles;

                    files = modules.map(function(path) {
                        var modulePath = `modules/${path}/scripts`,
                            moduleName = modulePath.split('/').reduce(function(result, next) {
                                var nameFragment;

                                switch(next) {
                                case "modules":
                                    nameFragment = "Poptart.";
                                    break;
                                case "scripts":
                                    nameFragment = "min.js";
                                    break;
                                default:
                                    nameFragment = `${next.charAt(0).toUpperCase() + next.slice(1)}.`;
                                    break;
                                }
                                return result + nameFragment;
                            }, "");

                        return {
                            src: grunt.file.expand({
                                filter: 'isFile'
                            }, [`${baseUIPath}/${modulePath}/*.js`, ...ignoredSourceScriptPatterns]).sort(
                                function(a, b) {
                                    return a.length - b.length;
                                }
                            ),
                            dest: `${baseUIPath}/${modulePath}/${moduleName}`
                        };
                    });

                    componentFiles = components.map(function(componentPath) {
                        return {
                            src: `${baseUIPath}/${componentPath}`,
                            dest: `${baseUIPath}/${componentPath.replace('.js', '.min.js')}`
                        };
                    });

                    files = [...files, ...componentFiles];

                    files.push({
                        src: grunt.file.expand({
                            filter: 'isFile'
                        }, [`${baseUIPath}/*.js`, ...ignoredSourceScriptPatterns]),
                        dest: `${baseUIPath}/poptart.min.js`
                    });

                    return files;
                }(),
                extDot: 'last',
                expand: true
            }
        },
        cssmin: {
            options: {
                sourceMap: true
            },
            build: {
                cwd: 'presentation/static/ui/',
                src: ['**/*.css', '!css/jquery-ui/**', '!css/ionicons/**', '!**/*.min.js'],
                dest: 'presentation/static/ui/',
                ext: '.min.css',
                expand: true
            }
        },
        eslint: {
            options: {
                configFile: 'presentation/build/eslint.json',
                ignorePath: 'presentation/build/.eslintignore'
            },
            target: ['presentation/**/*.js', '!presentation/ui/scripts/*', '!presentation/static/**']
        },
        shell: {
            test: {
                command: 'python manage.py test -p "*tests.py"',
                options: {
                    stdout: true,
                    failOnError: true
                }
            }
        },
        karma: {
            unit: {
                configFile: 'karma.conf.js',
                singleRun: true
            }
        },
        mochaTest: {
            unit: {
                options: {
                    reporter: 'spec'
                },
                src: ['presentation/test/server/*.js']
            }
        }
    });

    /*grunt.loadNpmTasks('grunt-shell');
    grunt.loadNpmTasks('grunt-eslint');
    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-mocha-test');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-newer');*/

    grunt.registerTask('default', ['lint', 'test']);
    grunt.registerTask('test', ['shell:test', 'mochaTest:unit', 'karma:unit']);
    grunt.registerTask('lint', ['eslint']);
    grunt.registerTask('build-static', ['uglify', 'copy', 'cssmin']);
};

我的开发依赖来自package.json:

  "devDependencies": {
    "chai": "^3.5.0",
    "chai-jquery": "^2.0.0",
    "eslint": "^3.7.1",
    "grunt": "^1.0.1",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-cssmin": "^1.0.2",
    "grunt-contrib-uglify": "^2.0.0",
    "grunt-eslint": "^19.0.0",
    "grunt-karma": "^2.0.0",
    "grunt-mocha-test": "^0.13.2",
    "grunt-newer": "^1.2.0",
    "grunt-shell": "^1.3.1",
    "jit-grunt": "^0.10.0",
    "jquery": "^3.1.1",
    "karma": "^1.3.0",
    "karma-chai": "^0.1.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-cli": "^1.0.1",
    "karma-jquery-chai": "^0.1.3",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-sinon": "^1.0.5",
    "mocha": "^3.2.0",
    "sinon": "^1.17.6",
    "sinon-chai": "^2.8.0",
    "time-grunt": "^1.4.0"
  }

这是我迄今为止所做的尝试:

  1. 使用time-grunt验证加载任务实际上是问题所在。它是。实际上正在运行的任务花费了非常合理的时间。
  2. 使用jit-grunt。这没有明显区别。
  3. npm prune。这实际上确实产生了相当大的(约30秒)差异,但仍然让我处于完全无理的任务加载时间。
  4. 删除和卸载我开始看到这个问题的时候添加的一些依赖项(uglify,copy,cssmin)(最初,当我刚接受测试/ linting任务时,一切都运行良好而快速)。这也没有明显的区别。
  5. 因此。还有什么可能导致这种规模的缓慢?

    感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

因此,看起来这样做的根本原因是在uglify任务中进行了一些低效的文件搜索。我完全忘记了我已经制造了那个巨大的疯狂和IEF,这解释了为什么即使我没有运行uglify任务我也看到了缓慢。我想这也解释了为什么文件搜索的时间与加载任务混在一起。

无论如何,主要的罪魁祸首是(可预测)我返回动态发现的脚本模块的源/目标路径,在这里:

                    return {
                        src: grunt.file.expand({
                            filter: 'isFile'
                        }, [`${baseUIPath}/${modulePath}/*.js`, ...ignoredSourceScriptPatterns]).sort(
                            function(a, b) {
                                return a.length - b.length;
                            }
                        ),
                        dest: `${baseUIPath}/${modulePath}/${moduleName}`
                    };

不令人惊讶,因为它处于循环中。无论如何,我注意到它错过了一个cwd。添加它可将时间缩短至7秒。仍然需要改进,但至少现在我知道要改进什么。

这个故事的道德:

  1. 在搜索文件时添加cwd
  2. 如果您不需要
  3. ,也许只是不搜索文件

答案 1 :(得分:1)

我尝试运行您的Gruntfile并手动安装依赖项,Gruntfile的加载时间约为4秒。不快,但不是你谈的分钟。

我的猜测是grunt.file.expand正在努力工作。也许presentation/ui文件夹太大了?运行tree presentation/ui | wc -l会得到什么?这显示了你在那里的文件数量。

否则,看看你的package.json和npm ls输出会很有帮助。