为什么build议使用concat,然后uglify时,后者可以做到这一点?

我不断看到build立JS文件准备生产的build议是concat然后uglify。

例如在这里 ,在Yeoman的咕噜声的任务。

默认情况下,stream程是:concat – > uglifyjs。

考虑到UglifyJS可以同时进行连接和缩小,为什么你会同时需要两个?

谢谢。

运行一个基本的testing,看看执行concatuglify之间是否存在性能差异,而不仅仅是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: trueconcat options
这会在main.js.map旁边创build一个main.js文件,结果如下:

 grunt default : 6.2s (just uglify) grunt default:true : 13s (concat and uglify) 

但是,如果生产站点仅加载min版本,则此选项无用。

uglify之前,我确实发现了使用concat一个主要缺点
当其中一个JS文件发生错误时, sourcemap将链接到连接的main.js文件,而不是原始文件。 而当uglify完成整个工作时,它链接到原始文件。

更新:
我们可以给uglify添加两个选项,将uglify源代码映射到concat源代码映射,从而处理上面提到的“缺点”。

  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 ugl /

 { 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和工作stream程jshint 。 有些人喜欢在编译之前运行它,有些人则喜欢在编译的文件上运行它。

具有令人难以置信的JavaScript文件量的复杂项目(或者越来越多的同行和贡献者)可能会select在uglify之外连接文件,以保持可读性和可维护性。 我认为这是Yeomanselect转型stream程的推理。

根据项目的configuration, uglify可能会非常慢,所以可能会有一些小小的优势,首先将它与concat连接起来,但是这将会得到证实。

concat也支持分隔符, README.mdREADME.md文件README.md

 concat: { options: { separator: ';', } } 
Interesting Posts