关于Vue项目优化方案总结
最近优化了一个 vue cli3.0
项目,由于项目打包后体积有点大。下面将优化方法写下:
需要新建文件 vue.config.js
与 package.json
在同一级目录下。
# 展示图形化信息(BundleAnalyzer)
::: info 作用 展示打包图形化信息,会打开一个html页面,帮助自己分析哪些文件过大,可针对其进行优化,上线时注释掉即可。 ::: 安装 webpack-bundle-analyzer 插件
npm install webpack-bundle-analyzer --save-dev
1
在 vue.config.js
里面引入
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
// 展示图形化信息
module.exports = {
chainWebpack: config => {
config
.plugin('webpack-bundle-analyzer')
.use(BundleAnalyzerPlugin)
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 抽离 css 支持按需加载
安装 mini-css-extract-plugin
插件
npm install mini-css-extract-plugin -D
1
在 vue.config.js
里面:
module.exports = {
chainWebpack: config => {
let miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: 'assets/[name].[hash:8].css',
chunkFilename: 'assets/[name].[hash:8].css'
})
config.plugin('extract-css').use(miniCssExtractPlugin)
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 图片按需加载
安装 image-webpack-loader
插件
npm install image-webpack-loader -D
1
在 vue.config.js
里面:
module.exports = {
chainWebpack: config => {
config.module.rule('images')
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
bypassOnDebug: true
})
.end()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
图片压缩可以进行批量压缩 (opens new window)
# gzip压缩代码
安装 compression-webpack-plugin
插件
npm install compression-webpack-plugin -D
1
在 vue.config.js
里面:
const CompressionWebpackPlugin = require('compression-webpack-plugin');
// 开启gzip压缩
module.exports = {
chainWebpack: config => {
config.plugins.push(
new CompressionWebpackPlugin({
filename: info => {
return `${info.path}.gz${info.query}`
},
algorithm: 'gzip',
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
test: new RegExp('\\.(' + ['js'].join('|') + ')$'
),
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 公共代码抽离
在 vue.config.js
里面:
module.exports = {
// 开启gzip压缩
configureWebpack: config => {
config.plugins.push(
new CompressionWebpackPlugin(
{
filename: info => {
return `${info.path}.gz${info.query}`
},
algorithm: 'gzip',
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
test: new RegExp('\\.(' + ['js'].join('|') + ')$'
),
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
}
)
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# element-ui 按需加载
安装 babel-plugin-component
插件
npm install babel-plugin-component --save-dev
1
在 babel.config.js
里面:
module.exports = {
presets: [
'@vue/app'
],
plugins: [
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk"
}
]
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# echarts 按需加载
安装 babel-plugin-equire
插件
npm install babel-plugin-equire -D
1
在项目中创建 echarts.js
:
// eslint-disable-next-line
const echarts = equire([
// 写上你需要的 echarts api
"tooltip",
"line"
]);
export default echarts;
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
在 babel.config.js
里面:
module.exports = {
presets: [
'@vue/app'
],
plugins: [
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk"
}
],
"equire"
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
具体页面应用:
// 直接引用
import echarts from '@/lib/util/echarts.js'
this.myChart = echarts.init(this.$refs.chart)
1
2
3
4
2
3
4
# lodash 按需加载
安装 lodash-webpack-plugin
插件
npm install lodash-webpack-plugin --save-dev
1
在 babel.config.js
里面:
module.exports = {
presets: [
'@vue/app'
],
plugins: [
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk"
}
],
"lodash",
"equire"
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在 vue.config.js
里面:
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
module.exports = {
chainWebpack: config => {
config
.plugin("loadshReplace")
.use(new LodashModuleReplacementPlugin());
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 删除无用的插件
prefetch
和 preload
删除无用的插件,避免加载多余的资源(如果不删除的话,则会在 index.html
里面加载 无用的 js
文件)
module.exports = {
chainWebpack: config => {
// 移除prefetch插件,避免加载多余的资源
config.plugins.delete('prefetch')
/ 移除 preload 插件,避免加载多余的资源
config.plugins.delete('preload');
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 完整的代码示例
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
module.exports = {
productionSourceMap: false, // 关闭生产环境的 source map
lintOnSave: false,
publicPath: process.env.VUE_APP_PUBLIC_PATH,
devServer: {
host: "localhost",
port: 3002,
proxy: {
'/api': {
target: "https://tapi.quanziapp.com/api/",
ws: true,
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
},
}
},
chainWebpack: config => {
// 移除 prefetch 插件
config.plugins.delete('prefetch');
// 移除 preload 插件,避免加载多余的资源
config.plugins.delete('preload');
config.optimization.minimize(true);
config.optimization.splitChunks({
chunks: 'all'
})
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
if (process.env.NODE_ENV !== 'development') {
let miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: 'assets/[name].[hash:8].css',
chunkFilename: 'assets/[name].[hash:8].css'
})
config.plugin('extract-css').use(miniCssExtractPlugin)
config.plugin("loadshReplace").use(new LodashModuleReplacementPlugin());
config.module.rule('images')
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
bypassOnDebug: true
})
.end()
.use('url-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
}).end()
config.module.rule('svg')
.test(/\.(svg)(\?.*)?$/)
.use('file-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
})
}
},
configureWebpack: config => {
// config.plugins.push(["equire"]);
if (process.env.NODE_ENV !== 'development') {
config.output.filename = 'assets/[name].[hash:8].js'
config.output.chunkFilename = 'assets/[name].[hash:8].js'
}
// 公共代码抽离
config.optimization = {
// 分割代码块
splitChunks: {
cacheGroups: {
//公用模块抽离
common: {
chunks: 'initial',
minSize: 0, //大于0个字节
minChunks: 2, //抽离公共代码时,这个代码块最小被引用的次数
},
//第三方库抽离
vendor: {
priority: 1, //权重
test: /node_modules/,
chunks: 'initial',
minSize: 0, //大于0个字节
minChunks: 2, //在分割之前,这个代码块最小应该被引用的次数
},
},
}
}
// 开启gzip压缩
config.plugins.push(
new CompressionWebpackPlugin(
{
filename: info => {
return `${info.path}.gz${info.query}`
},
algorithm: 'gzip',
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
test: new RegExp('\\.(' + ['js'].join('|') + ')$'
),
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
}
)
)
},
css: {
extract: true,
sourceMap: false,
loaderOptions: {
sass: {
},
},
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
上次更新: 2024/01/30, 00:35:17
- 01
- Node与GLIBC_2.27不兼容解决方案08-19
- 02
- Git清空本地文件跟踪缓存08-13