vue-cli3打包优化实战记录与思考

3,066 阅读5分钟

实战前

原先代码直接npm run build之后,生成的dist文件丢到环境就直接跑了,没有做什么优化(vue.config.js文件中没有进行相关的优化配置),并且在这之前对webpack或者相关打包优化并没有研究过。所以在优化过程中有很多低级的问题。。。在此记录一下。

public目录

图片等静态资源放到public文件夹, public 文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们。

chunk文件的减少

dist/js目录中有很多chunk文件,其中chunk-venders文件最大(一般情况下都是这样,因为包含第三方(node_modules)中依赖的东西打包在这个文件中)。其它的chunk-xx.js基本都是路由懒加载所对应的异步组件(一一对应),因为import按需加载的方式可以被webpack自动代码分割。路由懒加载中使用的异步组件越多,chunk文件越多,可以把组件按组分块,即把某个路由下的所有组件都打包在同个异步块中。或者使用webpack的插件来合并chunk:

// 限制打包的个数(减少打包生成的js文件和css文件)
new webpack.optimize.LimitChunkCountPlugin({
  maxChunks: 15, // 来限制 chunk 的最大数量
})
// 设置 chunk 的最小大小
new webpack.optimize.MinChunkSizePlugin({
  minChunkSize: 20000 // Minimum number of characters
})

首屏加载所有chunk文件?

看了下index.html,它中包含了所有的chunk文件,所以这些chunk文件都会加载,但都是以prefetch的方式加载的。

首屏加载性能优化

减小包体积(压缩和去掉无用的代码)、拆包(cdn,路由懒加载)

可视化分析

vue-cli3 可以使用 webpack-bundle-analyzer 插件来辅助分析,参考

减少 chunk-vendors.js 体积的方式

a.使用公共 CDN。最彻底的方案,把 ui 库抽离出来。当然还可以「更彻底」,把 vue、vuex、vue-router、axios 等等依赖都剥离出去。
b.对 element-ui 中用的组件按需引入。虽然用了 element-ui,但是只用了其中一部分常用组件,但是在编译时把全部 ui 库都引入了,所以优化思路是:按需引入

打包优化(体积)

按需引入、路由懒加载(代码分块)、gzip、CDN(进一步减少vender体积、CDN加速加载资源)、全局引入(避免多处import从而多处打进去了,比如monaco很大,项目中多处用到,可以直接全局引入(cdn引入其实更好),避免产生了多个大体积的chunk文件)

打包优化(速度)

DllPlugin 提取公用库、productionSourceMap属性值设置为false、开启多线程、include or exclude指定范围避免无效搜索

gzip的过程与原理

gzip需要服务端客户端共同支持、一般用来压缩静态文件
原理: 1)浏览器请求url,并在request header中设置属性accept-encoding:gzip。表明浏览器支持gzip。
2)服务器收到浏览器发送的请求之后,判断浏览器是否支持gzip,如果支持gzip,则向浏览器传送压缩过的内容,不支持则向浏览器发送未经压缩的内容。 一般情况下,浏览器和服务器都支持gzip,response headers返回包含content-encoding:gzip。
3)浏览器接收到服务器的响应之后判断内容是否被压缩,如果被压缩则解压缩显示页面内容。
gzip 使用deflate算法进行压缩。gzip 对于要压缩的文件,首先使用LZ77算法的一个变种进行压缩,对得到的结果再使用Huffman编码的方法

优化效果

优化前dist目录达到惊人的200M+,优化后只有20M左右(其实还是比较大,还有进一步优化空间)

preload与prefetch

preload 顾名思义就是一种预加载的方式,它通过声明向浏览器声明一个需要提交加载的资源,当资源真正被使用的时候立即执行,就无需等待网络的消耗。
prefetch 跟 preload 不同,它的作用是告诉浏览器未来可能会使用到的某个资源,浏览器就会在闲时去加载对应的资源,若能预测到用户的行为,比如懒加载,点击到其它页面等则相当于提前预加载了需要的资源。
默认情况下,一个 Vue CLI 应用会为所有初始化渲染需要的文件自动生成 preload 提示。
默认情况下,一个 Vue CLI 应用会为所有作为 async chunk 生成的 JavaScript 文件 (通过动态 import() 按需 code splitting 的产物) 自动生成 prefetch 提示。(比如异步组件生成的chunk文件就是以prefetch的方式在index.html中被引入)。
preload 是告诉浏览器页面必定需要的资源,浏览器一定会加载这些资源,而 prefetch 是告诉浏览器页面可能需要的资源,浏览器不一定会加载这些资源。所以建议:对于当前页面很有必要的资源使用 preload,对于可能在将来的页面中使用的资源使用 prefetch

DOMContentLoaded和Load两个时间的区别

DOMContentLoaded —— 浏览器已经完全加载了 HTML,DOM 树已经构建完毕,但是像是img 和样式表等外部资源可能并没有下载完毕。 DOM 加载完毕,所以 JS 可以访问所有 DOM 节点,初始化界面。
load —— 浏览器已经加载了所有的资源(图像,样式表等)。附加资源已经加载完毕,可以在此事件触发时获得图像的大小(如果没有被在 HTML/CSS 中指定)。

参考

优化博客后台(Vue)Javascript文件体积
vue-cli3 使用 webpack-bundle-analyzer 插件
webpack打包速度优化 使用 Preload/Prefetch 优化你的应用
HTML和静态资源_preload&prefetch
vue-cli3 DllPlugin 提取公用库 你真的了解 gzip 吗?
简单聊聊 GZIP 的压缩原理与日常应用
深入理解gzip原理
页面生命周期
再谈load与DOMContentLoaded