接续前篇多页应用改造,优化改造后的项目打包效果。
效果对比
阶段 | 磁盘占用空间 | 打包时间 | 备注 |
---|---|---|---|
原始 | 9.9M | - | 5.20版 |
架构改造(SPA->MPA) | 7.1M | - | 5.27版 |
样式整合 | 7.0M | - | 5.30版 |
公共组件&工具类整合 | 6.9M | - | 6.4版 |
图片压缩 | 6.0M | 20.767s | - |
UglifyJs | 5.9M | 23.391s | - |
合并小文件 | 5.3M | 55.469s | - |
代码分割splitChunks | 5.1M | 73.730s | - |
gzip | 6.3M | 89.204s | - |
优化前
优化后
优化过程
压缩图片
chainWebpack: config => { config.module .rule("image-webpack-loader") .test(/\.(gif|png|jpe?g|svg)$/i) .use("file-loader") .loader("image-webpack-loader") .tap(() => ({ disable: process.env.NODE_ENV !== "production" })) .end()};
添加UglifyJs,移除console
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')configureWebpack: config => { if (process.env.NODE_ENV === 'production') { const plugins = [] plugins.push( new UglifyJsPlugin({ uglifyOptions: { compress: { drop_console: true, drop_debugger: true } }, cache: true, // 启用文件缓存 parallel: true // 使用多进程并行运行来提高构建速度 // sourceMap: false // 映射错误信息到模块 }) ) config.plugins = [ ...config.plugins, ...plugins ] } }
动态导入合并小文件webpackChunkName
原来打包出来的文件,快上百个了,还有好些0.29KB的,需要合并下。此处使用webpackChunkName
首先按照业务含义合并,以service为例
import Vue from 'vue'import Router from 'vue-router'Vue.use(Router)const routes = [ { path: '/service', component: () => import(/* webpackChunkName: "service-index" */ '@service/components/page-layout/TwoColLayout.vue'), redirect: { name: 'Detail' }, children: [ { path: 'detail', name: 'Detail', component: () => import(/* webpackChunkName: "service-index" */ '@service/views/detail/index.vue') }, /** * 接口申请(指标) */ { path: 'api-apply', name: 'ApiApply', component: () => import(/* webpackChunkName: "service-api-apply" */ '@service/views/detail/views/apply-api/index.vue') }, { path: 'api-apply-form', name: 'ApiApplyForm', component: () => import(/* webpackChunkName: "service-api-apply" */ '@service/views/detail/views/apply-api/api-apply-form.vue') }, /** * 接口管理 */ { path: 'manage', name: 'Manage', component: () => import(/* webpackChunkName: "service-manage" */ '@service/views/manage/index.vue') }, { // 接口管理 - 新建/修改 path: 'manage/upsert', name: 'ManageUpsert', component: () => import(/* webpackChunkName: "service-manage" */ '@service/views/manage/module/upsert/index.vue') }] }, { path: '*', redirect: '/service' }]const router = new Router({ mode: 'history', routes })export default router
看起来都比较小,太小的独立文件单占连接数不是很合适。那就service-manage保留(业务上此处只有管理员能访问的管理页会调用,一般人看不到,不用和其他逻辑一起加载,还是保持独立),
其他的再统一合并成service-main。这里合并的宗旨是文件不超过250K。
...
此处省略处理各个产品打包合并过程。
代码分割splitChunks
从打包目录看,chunk-vendors-xxx.js
已达1.7M,需要拆分。
参考文章: 一步一步的了解webpack4的splitChunk插件
这里根据实际情况优化,具体大家可通过vue-cli-service build --report
生成 report.html分析包内容
首先拆出公用的element-ui
configureWebpack: config => { if (IS_PROD) { config.optimization = { splitChunks: { cacheGroups: { element: { name: 'vendors-element-ui', test: /[\\/]node_modules[\\/]element-ui[\\/]/, chunks: 'initial', reuseExistingChunk: true, enforce: true, priority: 3 }, } } } } }
然后把所有node_modlues下的引用合并到vendors
...cacheGroups: { vendors: { name: 'vendors', test: /[\\/]node_modules[\\/]/, chunks: 'all', priority: 2 }}...
再将所有模块中被不同的 chunk 引入超过 1 次的抽取为 common
...cacheGroups: { common: { name: 'common', chunks: 'initial', minChunks: 2, maxInitialRequests: 5, priority: 1 }}...
启用gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin') configureWebpack: config => { if (IS_PROD) { const plugins = [] plugins.push( new CompressionWebpackPlugin({ filename: '[path].gz[query]', algorithm: 'gzip', test: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i, threshold: 10240, minRatio: 0.8 }) ) config.plugins = [ ...config.plugins, ...plugins ] } }
css根据入口文件打包
到这里,打包出来的css文件都很小,单独放到一个资源文件去请求挺浪费连接数的,所以尝试合并css。
参考:Extracting CSS based on entry
目前暂未成功,可能与上述webpackChunkName方式冲突,合并后的css正常,但根据webpackChunkName之后的css依旧会打包出来,暂时没找到更好的解决办法。待更新~
警告处理
[mini-css-extract-plugin] Conflicting
参考issue reported on Github
两种解决方法:
- 调整import顺序
- 配置忽略警告
选用方法1解决。