Grunt:加载依赖项需要几分钟
Grunt: Loading dependencies takes several minutes
我已经将一些非常标准的 grunt 任务与合理数量的依赖项放在一起,但由于某种原因,实际加载依赖项需要 1-3 分钟。我对 grunt 比较陌生,但是由于大多数其他关于极度缓慢加载 grunt 依赖项的问题都引用了几秒钟的时间,我猜我做错了什么。
这是我的 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"
}
这是我目前尝试过的方法:
- 使用 time-grunt 验证加载任务确实是问题所在。它是。实际上 运行 任务花费了非常合理的时间。
- 使用 jit-grunt。这没有明显的区别。
- npm 修剪。这实际上确实产生了相当大的差异(约 30 秒),但仍然让我处于完全不合理的任务加载时间。
- 删除和卸载一些依赖项(uglify、copy、cssmin)我在开始看到这个问题时添加了(最初,当我有 testing/linting 任务时,一切都很好并且快速地)。这也没有明显的区别。
所以。还有什么可能导致这种规模的缓慢?
感谢您的帮助!
我尝试了 运行 你的 Gruntfile 并手动安装了依赖项,Gruntfile 的加载时间约为 4 秒。不快,但不是你说的分钟。
我猜 grunt.file.expand 正在努力工作。也许 presentation/ui
文件夹太大了? 运行 tree presentation/ui | wc -l
你得到了什么?这显示了你在那里的文件数量。
否则,查看您的 package.json 和 npm ls
输出会很有帮助。
所以看起来这的根本原因是在 uglify 任务中一些低效的文件搜索。我完全忘记了我已经制作了那个巨大的疯狂和 IEF 斑点,这解释了为什么即使我不是 运行 丑化任务,我也会看到速度缓慢的原因。我想这也解释了为什么文件搜索的时间与加载任务混为一谈。
无论如何,罪魁祸首(可以预见)是我返回动态找到的脚本模块的 source/dest 路径的地方,这里:
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 秒。仍然需要改进,但至少现在我知道要改进什么了。
这个故事的寓意:
- 搜索文件时添加cwd
- 如果不需要,也许可以不搜索文件
我已经将一些非常标准的 grunt 任务与合理数量的依赖项放在一起,但由于某种原因,实际加载依赖项需要 1-3 分钟。我对 grunt 比较陌生,但是由于大多数其他关于极度缓慢加载 grunt 依赖项的问题都引用了几秒钟的时间,我猜我做错了什么。
这是我的 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"
}
这是我目前尝试过的方法:
- 使用 time-grunt 验证加载任务确实是问题所在。它是。实际上 运行 任务花费了非常合理的时间。
- 使用 jit-grunt。这没有明显的区别。
- npm 修剪。这实际上确实产生了相当大的差异(约 30 秒),但仍然让我处于完全不合理的任务加载时间。
- 删除和卸载一些依赖项(uglify、copy、cssmin)我在开始看到这个问题时添加了(最初,当我有 testing/linting 任务时,一切都很好并且快速地)。这也没有明显的区别。
所以。还有什么可能导致这种规模的缓慢?
感谢您的帮助!
我尝试了 运行 你的 Gruntfile 并手动安装了依赖项,Gruntfile 的加载时间约为 4 秒。不快,但不是你说的分钟。
我猜 grunt.file.expand 正在努力工作。也许 presentation/ui
文件夹太大了? 运行 tree presentation/ui | wc -l
你得到了什么?这显示了你在那里的文件数量。
否则,查看您的 package.json 和 npm ls
输出会很有帮助。
所以看起来这的根本原因是在 uglify 任务中一些低效的文件搜索。我完全忘记了我已经制作了那个巨大的疯狂和 IEF 斑点,这解释了为什么即使我不是 运行 丑化任务,我也会看到速度缓慢的原因。我想这也解释了为什么文件搜索的时间与加载任务混为一谈。
无论如何,罪魁祸首(可以预见)是我返回动态找到的脚本模块的 source/dest 路径的地方,这里:
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 秒。仍然需要改进,但至少现在我知道要改进什么了。
这个故事的寓意:
- 搜索文件时添加cwd
- 如果不需要,也许可以不搜索文件