刘贵学博客

将静态资源压缩10倍+

背景

目前JS框架很多,发展很快,但是使用 Angularjs(ionic) 或 React 框架,合并的js源码动辄 几兆,浏览器首次加载太吃力,使用较多的是使用 uglify,minify 等工具后,静态文件能通常压缩2-3倍,很多情况下这还是不够,如何进一步压缩呢?

服务器Nginx原生支持 gzip on/off 的功能,此功能的意思是,自动为浏览器的所有文件实时压缩,可以节省传输带宽,提供传输速度。但对每次请求实时压缩,同时会增加了服务CPU的负荷,有时,反而得不偿失,所谓鱼和熊掌不可兼得。

有没有方案既吃鱼又啃熊掌吗?即:利用gzip节省带宽,又不多消耗CPU。

答案是: static gzip!

方案

实时压缩对于请求大于 1K 动态资源还是很有用处的。

对于静态资源来讲,我们需要的只是压缩,不要针对每次一请求实时处理。

如果我们需要压缩的文件(例如 all.js), 在部署的时候就产生了一份压缩好的文件,(如 all.js.gz),只需要在服务器请求 *.gz 文件的时候加上, http响应头:

Accept-Encoding:gzip, deflate

告诉浏览器,*.gz 是压缩文件,要解压缩,就可以啦。

这就是,static gzip,所以问题的解决在于,需要解决两个小步骤:

  • Step1:部署前使用工具将大的资源文件 gzip,添加.gz后缀;
  • Step2:服务器查找文件时,先查找是否有同名gz文件,如有优先读取gz文件。

Gzip Step1 部署前统一压缩

gulp

安装

npm install -save-dev gulp-gzip
gzip = require('gulp-gzip');


gulp.task('gzip', function() {
    //js gzip
    gulp.src('./www/lib/ionic/js/*.min.js')
      .pipe(gzip())
      .pipe(rename({extname: '.gz'}));

      //css gzip
      gulp.src('./www/lib/ionic/css/ionic.css')
        .pipe(gzip())
        .pipe(rename({extname: '.gz'}));
});

执行 gulp gzip 命令, 查看结果,可以节省 70%左右的网络带宽:

其他工具

例如webpack等,这里就省略了,按照 gulp的思路,去找对应 plugin 吧。

Gzip Step2 Web服务器添加Header

Nginx

nginx 去除了支持 gzip 的实时 压缩,也支持静态压缩,添加如下配置即可。

gzip_static on;

开启nginx_static后,对于任何文件都会先查找是否有对应的gz文件。

Apache

通过 deflate_Module和headers_Module 来实现,详情不标。

总结

以 ionic为例,在压缩前, 2.6M左右:

压缩后, 只有不到200K:

整个压缩比例 10倍以上。

后记

其实,nginx_static 还是会有一些I/O性能损耗,即,会对所有的文件都先查询一下是否存在同名gz文件。

如果修改为:
* 站点目录添加 .gzip_statics 配置文件列表;
* 根据站点根目录下的一个配置文件(server 启动时将配置文件加载到内存)的规则,来确定是否查找 gz文件。

附脚本:用gulp 压缩js和css

var gulp = require('gulp');

var     uglify = require('gulp-uglify');
var     rename = require('gulp-rename');
var     mincss = require('gulp-minify-css');
var     concat = require('gulp-concat');
var     gzip = require('gulp-gzip');

var dist_path = 'Public/static/dist/';

gulp.task('gzjs', function() {

    gulp.src([
          'Public/static/vendor/modernizr/modernizr.js',
     //........待压缩的列表,注意顺序
        ])
        .pipe(concat('common.js'))
        .pipe(gulp.dest(dist_path))
        .pipe(rename('common.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(dist_path))
        .pipe(rename('common.min.js'))
        .pipe(gzip())
        .pipe(gulp.dest(dist_path));

});

 gulp.task('gzcss', function() {
     gulp.src([
         'Public/static/css/font-awesome.css',
         //........待压缩的 css 列表,注意顺序
        ])
         .pipe(concat('common.css'))
         .pipe(gulp.dest(dist_path))
         .pipe(rename('common.min.css'))
         .pipe(mincss())
         .pipe(gulp.dest(dist_path))
         .pipe(rename('common.min.css'))
         .pipe(gzip())
         .pipe(gulp.dest(dist_path));

 });

gulp.task('default', ['gzjs', 'gzcss']);