使用vue-cli的webpack模板的一次优化

使用过vuejs的开发者一定对vue-cli不陌生,这个命令行工具提供了几个常用的搭建项目的模板,目前官方支持6个模板:

  • webpack
  • webpack-simple
  • browserify
  • browserify-simple
  • pwa
  • simple

而使用得最多也是Github上start数最多的模板则是webpack这个模板,它包含的内容也非常丰富:语法校验、css预处理、测试框架等,相对于其它模板而言更适合搭建大型项目。

更为良心的是连npm脚本都写好了,开发的时候直接输入npm run dev,开发完成则输入npm run build生成对应的可部署文件。

但是当我们真正开始用于大型项目的时候,尤其在引入一些第三方模块之后就会发现一个问题~

这是我的一个项目使用默认配置编译后生成的文件目录截图。

其中有1个vendor.xxxx.js文件显示颜色为黄色,后面给出一个[big]的警告,文件大小达到981kB!

更可怕的是 app.xxx.js 和 vendor.xxx.js 在首次加载的时候浏览器都会请求,js文件下载完成之后才开始渲染页面。直接后果就是首屏加载时间大大增加,用户浏览网页时需要长时间等待,体验相当糟糕。

定位问题

我们来看看这个vendor.xxx.js是怎么形成的。

全局搜索一下”vendor”即可找到 build 目录下的 webpack.prod.conf.js 文件,看到下面几行:

1
2
3
4
5
6
7
8
9
10
11
12
13
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),

这里用到了webpack的一个插件CommonsChunkPlugin来提取entry对应文件(所有编写的业务代码)中的公共代码,其中 minChunks 的配置项对应的函数为提取代码块规则,规定将node_modules中的所有依赖模块都打包到一个叫vendor的文件中。

解决问题

最终目的是减小文件体积,途径有两个:

  • 减少依赖。
  • 分割文件。

对于第一种方式通常会随着项目代码量增大而难度增大,而且除非引入了较多的不需要的垃圾模块,否则效果不会很明显。而引入不适用的模块一般在编译时校验规则无法通过就会报错,这种情况几乎不会出现。

所以考虑第二种方式。我们将首屏需要的第三方模块提取出来优先加载,让页面快速渲染,其它模块延迟加载或懒加载。

要做到这一点我们首先需要回归打包工具webpack,通过查看官方文档可以找到code splitting的描述和我们所需的场景较为匹配——它可以用来分割成更小的模块和控制资源加载的优先级,如果使用正确的话可以极大地提升加载速度。

同时文档上提供了3种实现方式:

  • 通过entry配置项手动分割。
  • 通过CommonsChunkPlugin插件提取公用代码。
  • 动态引入模块。

第一种方式:将首页依赖的模块手动配置成entry并不会奏效,因为CommonsChunkPlugin插件仍然会将部分模块抽取出来,配置形同虚设。
第二种方式:这种方式尝试了很久,一直想把首页的第三方模块单独抽取出来。后来仔细思考因为main.ts文件中始终会引用首页组件,也就是说两个entry配置的文件有包含关系,注定了在抽取公共模块的时候会把这些模块一起抽取出来,所以这种方式行不通。
第三种方式:使用vuejs的异步组件特性,再加上webpack的import函数实现。但是使用ts转成ES5时会出现报错:不支持模块懒加载。需要引用第三方库,比如require.js或者system.js。最后代码如下:

1
2
3
// 需要先安装system.js模块:npm i -S systemjs
const Index = () => System.import(/*webpackChunkName: 'Index'*/ '../components/home/Index.vue')
...

换一种思路

有没有简单粗暴的方法?有!

在服务端开启gzip,可以有效地减小文件体积。具体操作需要根据不同服务器进行配置。

本文使用了nginx作为Web服务器,并开启了最高压缩级别地gzip,上述vendor.xxx.js压缩后体积:

608kB => 154kB

体积减少了74.67%,效果相当可观。

当然实际生产环境不会把压缩级别调到这么高,避免过多消耗CPU资源。

总结

这些年Web前端的发展越来越变得工程化和专业化,从最初的使用空的种子项目来快速搭建框架,到聚集各类框架模板的脚手架平台yeoman,再到框架使用专有的命令行工具(vue-cli, angular-cli等)。

不少模板、种子项目虽然都做到了“开箱即用”,但是这个“可用性”更多的是相对于开发测试而言,对于生产部署往往需要开发者花费心思去改进、优化,纯粹的“拿来主义”不可取~

亚里士朱德 wechat
更多WEB技术分享请订阅微信公众号“WEB学习社”