从基础配置到高级优化,全面掌握性能优化核心技巧
// vue.config.js
module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'async',
minSize: 20000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
}
}
dist/
├── js/
│ ├── app.5d8f2e.js # 主入口
│ ├── chunk-vendors.68a45d.js # 第三方库
│ ├── common.1a2b3c.js # 公共模块
│ └── asyncComponent.7e6f5a.js # 异步组件
目标:将Vue、Vuex等稳定依赖单独打包
// vue.config.js
configureWebpack: {
optimization: {
splitChunks: {
cacheGroups: {
vue: {
test: /[\\/]node_modules[\\/](vue|vue-router|vuex)[\\/]/,
name: 'vue-vendors',
chunks: 'all',
priority: 20
},
elementUI: {
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
name: 'element-ui',
chunks: 'all',
enforce: true
}
}
}
}
}
实现原理:利用动态import语法
// router.js
const UserDetails = () => import(/* webpackChunkName: "user" */ './views/UserDetails.vue')
// 生成文件: user.xxxx.js
cacheGroups: {
common: {
name: 'common',
minChunks: 2, // 至少被两个入口引用
chunks: 'initial',
priority: 10,
reuseExistingChunk: true
}
}
// vue.config.js
module.exports = {
chainWebpack: config => {
config.optimization.runtimeChunk('single')
}
}
// 生成 runtime.xxxx.js
// 独立CSS文件
config.plugin('extract-css')
.tap(args => [{
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css'
}])
// CSS按需加载
import(/* webpackChunkName: "styles" */ './style.css')
splitChunks: {
chunks: 'all',
maxSize: 250000, // 250KB
minRemainingSize: 20000,
enforceSizeThreshold: 50000
}
<link rel="preload" href="/js/vue-vendors.xxxx.js" as="script">
<link rel="prefetch" href="/js/user.xxxx.js">
// 文件名哈希策略
config.output.filename('js/[name].[contenthash:8].js')
config.output.chunkFilename('js/[name].[contenthash:8].js')
// 模块ID固化
config.plugin('hashed-module-ids').use(require('webpack').HashedModuleIdsPlugin)
# 安装分析插件
npm install webpack-bundle-analyzer --save-dev
// vue.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
configureWebpack: {
plugins: [new BundleAnalyzerPlugin()]
}
}
指标 | 优化目标 | 测量工具 |
---|---|---|
首屏资源体积 | < 200KB | Chrome DevTools |
主包依赖数量 | < 30个 | webpack-bundle-analyzer |
缓存命中率 | > 90% | Lighthouse |
动态加载延迟 | < 500ms | Performance面板 |
对策:
maxInitialRequests: 5
检测方法:
npx vue-cli-service build --report
优化方案:
minChunks
阈值优化手段:
webpackPrefetch: true
// vue.config.js
module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 250000,
minChunks: 1,
maxAsyncRequests: 6,
maxInitialRequests: 4,
automaticNameDelimiter: '~',
cacheGroups: {
vue: {
test: /[\\/]node_modules[\\/](vue|vue-router|vuex)[\\/]/,
name: 'vue',
priority: 20
},
element: {
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
name: 'element',
priority: 15
},
commons: {
name: 'commons',
minChunks: 2,
priority: 10,
reuseExistingChunk: true
}
}
},
runtimeChunk: {
name: 'runtime'
}
}
},
chainWebpack: config => {
config.plugin('preload').use(require('@vue/preload-webpack-plugin'))
}
}
通过合理的分包策略,典型Vue项目可达成:
实施步骤建议: