UglifyJS: 合并和压缩,还是先压缩再合并?

19

我正在编写一个应用程序,它使用了许多JS文件:Underscore、Backbone、jQuery、用于滑块的jQuery插件,以及几个文件用于模型、路由器、集合和视图。

在我的开发机上,我单独加载每个文件,但在生产环境中,我只使用一个JS文件(经过缩小、gzip、少http请求等处理)。

在我的构建过程中,每个文件都会被UglifyJS压缩,然后连接到prod.js中。这是构建该文件的正确方式吗?还是应该将每个文件连接到prod.js中,然后再使用UglifyJS进行压缩?

非常感谢!


这取决于所使用的算法,但通常我会先进行连接,然后再进行缩小。 - Christoph
6个回答

23

我使用Gulp测试了每种方法的输出。

测试设置

我使用了9个JavaScript文件,总共19.15 kB(未缩小)进行拼接。每个文件都以'use strict';语句开头。

结果:

  • 拼接 => 压缩: 7.993 kB
  • 压缩 => 拼接: 8.093 kB
  • 差异: 0.1 kB

注释:

  • 拼接 => 压缩会去掉9个中的8个 'use strict';语句
  • 压缩 => 拼接会保留所有的'use strict';语句
  • 单个'use strict';语句为13个字节。8 × 13 字节 = 104 字节,这就解释了0.1 kB 的差异。

最终想法:

使用你喜欢的任何顺序。

这两个过程之间的差异是微不足道的。如果以下两个条件均满足,则拼接 => 压缩可以(理论上)产生(几乎不可察觉的)更小的文件:

  • 几个单独的文件以'use strict';语句开头
  • 许多单独的文件

这是我用的gulpfile.js

var gulp = require('gulp'),
  concat = require('gulp-concat'),
  uglify = require('gulp-uglify');

var files = [
  '!app/scripts/**/*Spec.js', // Exclude test files
  'app/scripts/**/*.js'
];

// Register tasks
gulp.task('concat-min', function() {
  return gulp.src(files)
    .pipe(concat('script.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest('dist'));
});

gulp.task('min-concat', function() {
  return gulp.src(files)
    .pipe(uglify())
    .pipe(concat('script.min.js'))
    .pipe(gulp.dest('dist'));
});

2
虽然测试很棒,但在实际世界中,您永远不应该有全局“Use Strict”语句,这会给处理带来很大的麻烦。我考虑从Concat+Uglify转向Uglify+Concat,因为当我遇到语法错误时,如果错误消息只读“意外标记,第19257行”,那么找到错误是很麻烦的。 - Ray Foss

2
我会很惊讶,如果两种方式对用户请求的开销有显著差异。

我还建议将所有这些框架串联成一个文件可能实际上会增加每个用户的开销。

为什么?

当使用流行/常用的框架,例如jQuery等时,将其托管在CDN上,例如Google,以从缓存文件中受益是有意义的——如果用户访问过使用jQuery的网站,它们根本不需要下载它!更不用说地理延迟减少了。

因此,通过创建自己独特的文件,您正在使用户更有可能要下载整个文件。


我宁愿选择先合并。出于RichardJ和HotHeadMartin提到的原因,或者说更简单地说,这样更安全、更有效。至于CDN,我不会把太多指望放在它上面。 - Saulius
1
此外,使用CDN时可以建立更多的并行连接。在我的情况下,我正在使用webview,因此文件不可能被预缓存。我先进行拼接再进行压缩,但为了避免语法错误,我认为先进行压缩再进行拼接是更好的选择。 - Ray Foss

1

我强烈建议您使用requirejs,使用该库,您可以制作包或一个最小化和统一的文件。请阅读优化工具

然而,正如Widor告诉您的那样,将所有文件合并为一个文件并不是一个好主意。如果您始终在线使用应用程序,则使用谷歌API(CDN)可以使这些库中的许多表现更好。


1

我通常会将它们全部放在一起,然后进行缩小。

我开始做的一件事是先通过http://www.javascriptobfuscator.com/运行它,我知道这听起来有些违反直觉,但它所做的事情之一是将所有字符串存储在一个数组中,虽然是一个丑陋的数组,但可以防止字符串重复,然后当您进行缩小时,我使用Google Closure编译器,它会整理字符串,您通常会得到更好的缩小文件


我尝试在UglifyJS中实现这种技术(我是指将字符串单独存储以避免重复),并注意到在gzip之后,压缩文件的大小比不处理字符串时要大。 - mishoo

0

这不会有太大的影响,因为顶层语句(以及变量等)不会被修改。

然而,当使用--lift-vars选项时,情况可能会改变。这严重取决于您的代码。


0

假设您没有太多全局变量,顺序并不重要。文件大小差异非常小。我个人更喜欢先进行合并,然后再进行压缩,这样可以生成更好和更准确的源映射而不是反过来。(这是因为每次转换都会改变源映射)。我想知道的是,在压缩较小的文件然后进行连接的目的是什么。基本上,由您决定,取决于您的选择。合并和压缩似乎更令人满意,错误也更少。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接