2017-08-30 13:00:00

Vue/React的加载优化(高级篇)

Webpack
react
vue
angular
阿里云
OSS

前言

当下,Vue、React和Angular火爆异常。三者的共同点之一,就是都可以借助Webpack构建项目bundle文件。

本文重点讲述如何减少bundle体积,以及提升页面加载速度。从Webpack开始,同时讲述如何借助常见云平台和node端提升加载效率。

首先引入一个小问题:
请打开本页面的开发窗口(如果是Chrome用户点击F12),在Network标签下发现分别从两个地方下载了vue.js。 这两个文件名称相同,内容相同。一个从CDN加载,一个从OSS加载。可为什么文件尺寸区别这么大?

(图中浏览器Chrome:Mac Version 60.0.3112.101)

正文说明

关于Webpack优化,相关文章说明很多,也很详细。 但是由于版本更替, Webpack v1.x 到 v3.5(2017.08.30)版本差异也造成了一些文章实时性不高。 此外,代码的可达性也十分重要,部署出人人可见的代码,必定是一个从前到后的过程, 只说一端总是不透彻。

所以我就写个“本土化”的总结:过去反复讲述的东西,简单说明;而真正的干货,则详细展开。

Webpack中的一般优化

  1. 提取bundle中图片,用以减少体积。

    Webpack将图片直接转换为base64格式,使得图片间接存入bundle文件,导致体积过大。

    方法: 图片取消转化而改为引用。缺点是需要额外的时间载入图片。

  2. OccurrenceOrder

    new webpack.optimize.OccurrenceOrderPlugin()

    打包过程中,最小化id值。在Webpack v2.0以及以后的版本默认添加。

  3. DefinePlugin

    改变环境变量。

    当NODE_ENV=production后,提升代码打包效果。UglifyJS会将dev模式下的代码清洗掉(如react)。

  4. Dedupe

    防止代码重复添加。

    在Webpack v2.0以及以后的版本不再需要。

  5. Uglify

    new webpack.optimize.UglifyJsPlugin([options])

    老生常谈,注意除了UglifyJsPlugin本身的配置之外,uglifyOptions内部也有很多需要注意。比如 “screw_ie8”等。

  6. Externals

    将一些常用的库和模块,比如react/angular/vue/rxjs/immutable等从bundle文件分离出来。增添全局变量(比如window.React),引入CDN公用库文件,如BootCDN等。

  7. CommonsChunk

    • 单页应用: 生成类似app.js和vendor.js两个文件,由服务器本身提供加载,提升缓存效率;
    • 多页应用: 不同路由的任意组合的分割重组。

  8. Scope Hoisting

    new webpack.optimize.ModuleConcatenationPlugin()

    在Webpack v3新引进的。使用简单,效果不错。

  9. Lazy load

    如果只用到某个库的一部分内容,就不需要讲整个源码都包含入bundle中。

    相关工具如蚂蚁金服ant.design的babel-plugin-import, 或者lodash-webpack-plugin,以及lodash.xxx替代lodash的局部模块。

  10. devtool

    有文章建议cheap-module-source-map,但是production环境下Dev意义不大,直接devtool=false

  11. gzip/compression

    compression-webpack-plugin,expressjs/compression

    文件压缩,非常重要,下文详细讲。

高级优化

回到本文的开始的问题,答案就是HTTP压缩

原理

现代浏览器在进行http请求的时候,普遍支持gzip压缩。这种优化不限制于webpack生成的bundle文件,css、html和图片都可以采用类似策略。在发出请求的时候,会在http头部显示Accept-Encoding:gzip, deflate 也就是告诉服务器可以接受这两种压缩格式。

于是服务器就可以把vue.js文件压缩,并设置Content-Encoding:gzip。浏览器看到这个头部设置,自动解压缩。这种压缩可以减少至少60%的体积。所以两个vue.js文件的显示大小不一样,因为CDN对返回的脚本进行了压缩传输。

实际操作

  • express.js

    express.js项目中,如果使用app.use(express.static('xxx', [options])),服务器会主动查看gzip请求,如果有gzip header, 则将静态文件压缩并返回。当然也可以手动设置option参数。 但是这种压缩并非一劳永逸的,每次请求都要消耗服务器内部的部分资源。优化方法可以是提前压缩再放入路径。

    如果res.sendFile('vue.js'),默认是不压缩的。

  • 阿里云OSS,AWS的S3,或者CDN

    如果把静态文件部署在OSS/S3上,默认不压缩。但是可以进行返回包http头的手动设置


通过以上各种方式的叠加组合,基本可以将原来庞大的文件减少为1/10甚至1/20,加载时间大幅减少。如ColorPK:)

以上步骤其实相对机械化,逐步完成就能达到效果。当然,在项目代码内部,优化变量作用域,提高模块化和复用率等,其实更有意义和价值。 这部分抽空我再写一篇文章。