我一直看到的建议是将JS文件准备好并压缩,例如在Yeoman的grunt任务中这里。
默认情况下流程为:concat -> uglifyjs。
考虑到UglifyJS可以同时进行拼接和缩小,为什么您需要同时进行这两个操作呢?
谢谢。
我一直看到的建议是将JS文件准备好并压缩,例如在Yeoman的grunt任务中这里。
默认情况下流程为:concat -> uglifyjs。
考虑到UglifyJS可以同时进行拼接和缩小,为什么您需要同时进行这两个操作呢?
谢谢。
运行一个基本测试,以查看执行 concat
然后 uglify
与仅执行 uglify
之间是否存在性能差异。
package.json
{
"name": "grunt-concat-vs-uglify",
"version": "0.0.1",
"description": "A basic test to see if we can ditch concat and use only uglify for JS files.",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-uglify": "^0.6.0",
"load-grunt-tasks": "^1.0.0",
"time-grunt": "^1.0.0"
}
}
Gruntfile.js
module.exports = function (grunt) {
// Display the elapsed execution time of grunt tasks
require('time-grunt')(grunt);
// Load all grunt-* packages from package.json
require('load-grunt-tasks')(grunt);
grunt.initConfig({
paths: {
src: {
js: 'src/**/*.js'
},
dest: {
js: 'dist/main.js',
jsMin: 'dist/main.min.js'
}
},
concat: {
js: {
options: {
separator: ';'
},
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.js %>'
}
},
uglify: {
options: {
compress: true,
mangle: true,
sourceMap: true
},
target: {
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.jsMin %>'
}
}
});
grunt.registerTask('default', 'concat vs. uglify', function (concat) {
// grunt default:true
if (concat) {
// Update the uglify dest to be the result of concat
var dest = grunt.config('concat.js.dest');
grunt.config('uglify.target.src', dest);
grunt.task.run('concat');
}
// grunt default
grunt.task.run('uglify');
});
};
在src
文件夹中,我放置了许多JS文件,包括未压缩的jQuery源代码,复制了几次,并分散在子文件夹中。比通常网站/应用程序要多得多。concat
上使用sourceMap: true
选项时,情况就不同了(见下文)。grunt default : 6.2s (just uglify)
grunt default:true : 6s (concat and uglify)
值得注意的是,无论哪种情况下生成的 main.min.js
文件都是相同的。此外,uglify
在合并文件时会自动处理使用正确分隔符的问题。sourceMap:true
添加到 concat
选项中。这会在 main.js
文件旁边创建一个 main.js.map
文件,并导致以下结果:grunt default : 6.2s (just uglify)
grunt default:true : 13s (concat and uglify)
但是如果生产环境只加载min
版本,那么这个选项就没有用了。uglify
之前使用concat
有一个主要缺点。当JS文件中出现错误时,sourcemap
将链接到连接后的main.js
文件而不是原始文件。而当uglify
完成整个工作时,它会链接到原始文件。uglify
添加2个选项,将uglify
sourcemap链接到concat
sourcemap,从而处理我上面提到的"缺点"。 uglify: {
options: {
compress: true,
mangle: true,
sourceMap: true,
sourceMapIncludeSources: true,
sourceMapIn: '<%= paths.dest.js %>.map',
},
target: {
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.jsMin %>'
}
}
但这似乎是非常不必要的。
我认为可以得出结论,如果我们使用uglify
,我们可以放弃对JS文件使用concat
,并在需要时用于其他目的。
concat->uglify
)工作流来编译javascript
。据我所知,这种工作流选择与性能关系不大,我个人认为它只有在非常复杂的项目中才有意义。 - Wallace Sidhréeuglify
之前使用 concat
的好处是什么?也许是 concat
中的 process
选项? - Alex Ilyaevconcat
连接,然后使用uglify
进行压缩/混淆。{
concat: {
'.tmp/concat/js/app.js': [
'app/js/app.js',
'app/js/controllers/thing-controller.js',
'app/js/models/thing-model.js',
'app/js/views/thing-view.js'
]
},
uglifyjs: {
'dist/js/app.js': ['.tmp/concat/js/app.js']
}
}
使用以下方法也可以实现相同的效果:
{
uglifyjs: {
'dist/js/app.js': [
'app/js/app.js',
'app/js/controllers/thing-controller.js',
'app/js/models/thing-model.js',
'app/js/views/thing-view.js'
]
}
}
通常情况下,clean
任务会在写入临时文件夹(在本例中为concat
)的任务之后运行,并删除该文件夹中的所有内容。有些人还喜欢在像 compass
这样的任务之前运行 clean
,以删除诸如随机命名的图像精灵(每次任务运行时都会新生成)之类的东西。这将使即使对于最谨慎的人也能保持轮子转动。
这完全是个人偏好和工作流程问题,就像何时运行 jshint
一样。有些人喜欢在编译之前运行它,而其他人则更喜欢在编译后运行它。
具有大量 JavaScript 文件或越来越多的同行和贡献者的复杂项目可能会选择在 uglify
之外连接文件,只是为了保持更可读性和可维护性。我认为这是 Yeoman
的转换流选择背后的原因。
uglify
根据项目配置可能非常缓慢,所以将其与 concat
首先连接起来可能会有一些小的收益,但必须确认。
concat
还支持分隔符,而就 README.md
文件而言,uglify
并不支持。
concat: {
options: {
separator: ';',
}
}
concat
,但选择仅使用uglify
,因为它可以完成所有必要的工作 - 正如你所指出的那样。我猜有些人同时使用两者,要么是为了弥补他们项目的复杂性,要么是因为他们宁愿让uglify
只做除串联之外的事情。就我所知,concat
还允许使用分隔符,而uglify
则不行。 - Wallace Sidhrée