接续前篇多页应用改造,优化改造后的项目打包效果。
效果对比
阶段 | 磁盘占用空间 | 打包时间 | 备注 |
---|---|---|---|
原始 | 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 解决。