前端 Webpack 工程化的最佳实践( 三 )


? 大图片上传CDN
上传CDN后可以大幅减小包体积 。另外,webpack也不需要再去关注那些图片的文件索引路径了 。项目稍微大一些,本地图片5Mb ~ 10Mb的情况非常普遍,亟待优化 。
? devServer Proxy的代理能力
去调研这个能力,得益于一次请求层的改造 。诉求是希望Token不再显示传递,而是通过塞到Header去实现 。在本地开发的环境,我们通常使用jsonp去解决跨域问题,但其本质其实是在网页中嵌入一段<script />,自然也就不能写入Header信息,这个和我们的初衷并不相符,无法满足诉求 。所以对于这样的跨域问题,我们通过几个简单的参数配置,在请求发起和请求返回的两端,分别做了代理配置,从而“欺骗”了“源Origin”,得以解决本地开发的跨域问题:
devServer: {// ...headers: {'Access-Control-Allow-Origin': '*', // CORS},proxy: { // for ajax cors'/h5/ajaxObj': {target: 'http://xxx.xxx.xxx.com',onProxyReq: (proxyReq) => {proxyReq.setHeader('Origin', 'http://xxx.xxx.com');},onProxyRes: (proxyRes) => { // …},},},}, 优化性能 by Node / Happypack
基础配置和需要的自定义配置已经有了,整个项目的构建时间有可能还是非常不理想的,当前本文提及的测试项目,大概有57s的时间,还是有很多地方没有补足的,可优化的空间非常大 。
第一步可以先关注下Node版本,经过测试,是对整体速度可以至少提升30%的事情,尤其是在Node V8版本到V10的时候,以下是之前在另一个项目做技术改造时记录到的数据:
Node版本
v 8.x
v 10.x
compile
32s - 36s
26s
re-compile
8s - 9s
4s
但是这次,在把项目直接升级到了 v 11.x 后发现,有带node-sass的项目编译构建都崩溃了 。才意识到,node-sass的版本也需要相应的版本更新 。也测试了Babel v 6.x 到 v 7.x 版本的升级效果,本来以为babel的大版本升级会带来显著的编译速度提高,实际上却并不理想(基本可以忽略不计) 。
打算开启多线程能力,去处理模块化打包里面那些本是单线程执行的 loaders 们的工作 。Happypack的提升效率对整个项目的首次编译而言,效果是20%左右,比较明显 。加入Happypack能力的时候,有两点需要注意:

  • 其对file-loader和url-loader的支持不好,可以考虑不加,毕竟我们项目里面图片类(最好上传CDN)的和非常规格式的文件只是小部分;
  • 这次也尝试了把ts-loader加入到多线程中,但是也出现了不少编译问题 。大概率怀疑是我个人的配置问题,但过程中去看issues见到了不少ts-loader和ts生态依赖兼容性的问题 。目前这个项目.ts只是少数文件,作为一种尝试,大部分文件还都是.jsx和.js,所以针对ts也先不加入Happypack能力了 。
 优化性能 by DLL/ Optimization
首先需要借助一些工具来进行分析,如:webpack-bundle-analyzer ,通过这个工具我们可以对整个构建(用于生产,Webpack Analyse针对的build过程,不是compile)过程和结果进行数据、图形上的分析,从而得知问题具体出现在了哪里 。进而得知DLL所需拆分的内容是什么 。以下内容是在第一次分析时得出的:
前端 Webpack 工程化的最佳实践

文章插图
这个图片的 3532 modules和62 chunks可以看到具体的模块以及chunks划分后的情况 。更加直观的我们来看下面这张图,可以看到Parsed的尺寸,入口文件(7.09MB)和主chunk(2.04MB,主要是一些首页就需要加载的node_module)的大小都很夸张,并且node_modules里面的包基本上是一一打包、整整齐齐:
前端 Webpack 工程化的最佳实践

文章插图
有了这些分析结果,对应解法的思路就很清晰了:首先要抽离常用的node_modules(这是DLL的意义),然后要逐个分析,把不被经常用到的node_module们(仅被某些页面使用,不具有公共特点)也抽出去 。
对于React项目中的React、React-Dom、React-router、Redux等,还要一些第三方比较大的库,比如antv或者G2相关的,也要进行DLL抽离了:
前端 Webpack 工程化的最佳实践

文章插图
modules数量由3532降低到1500,编译时间缩短了三倍
在做了上述DLL的抽离后其实效果已经很明显了,进一步的提升空间,可以对optimization进行了配置(用法详见官方文档):
  • terser
  • chunksAll
  • no mimimizer sourceMap
 结尾
本文大概主要介绍了一些工具衍变背景、基础的组织结构和自定义配置,以及如何通过分析工具去来做性能优化,其中很多小的细节没办法一一提到,比如我们看到加载的chunk都是hash值的时候,如何能够辨别是什么组件呢:解法是可以在路由处通过配置moduleName的方式去做:


推荐阅读