浅谈vue项目打包性能优化
主要的目的是减少项目打包体积,提升页面的加载速度,现以vue-cli3为例,vue-cli3项目的webpack配置统一放在vue.config.js内,首先创建一个vue.config.js的文件
创建配置文件,抛出一个配置对象
const vueConfig = {}
module.exports = vueConfig
2.图片压缩
1.设置productionSourceMap=false
const vueConfig = {
productionSourceMap: false
}
图片压缩我是写了两种方案感觉都不错,任选其一。
第一种:使用image-webpack-loader
/* 安装image-webpack-loader */
npm i image-webpack-loader
在配置文件中引入并使用
const vueConfig = {
productionSourceMap: false,
chainWebpack: config => {
/* ============压缩图片 start============ */
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
/* ============压缩图片 end============ */
}
}
第二种:使用tinyimg-webpack-plugin
npm i tinyimg-webpack-pluginx
在配置文件内使用
const TinyimgPlugin = require('tinyimg-webpack-plugin')
const vueConfig = {
productionSourceMap: false,
configureWebpack: config => {
config.plugins.push(
new TinyimgPlugin({
enabled: process.env.NODE_ENV === 'production',
logged: true
})
)
}
}
3.CDN配置
在vue.config.js
上边写入声明:
/* 是否为生产环境 */
const isProduction = process.env.NODE_ENV !== 'development'
/* 本地环境是否需要使用cdn */
const devNeedCdn = false
/* cdn链接 */
const cdn = {
/* cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)*/
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
/* cdn的css链接 */
css: [],
/* cdn的js链接 */
js: [
'https://cdn.staticfile.org/vue/2.6.10/vue.min.js',
'https://cdn.staticfile.org/vuex/3.0.1/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
在vue.config.js
vue.config.js
chainWebpack
中写入:
/* ============注入cdn start============ */
config.plugin('html').tap(args => {
/* 生产环境或本地需要cdn时,才注入cdn */
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
/* ============注入cdn end============ */
在vue.config.js
configureWebpack
中写入:
configureWebpack: config => {
/* 用cdn方式引入,则构建时要忽略相关资源 */
if (isProduction || devNeedCdn) config.externals = cdn.externals
}
当前配置的vue.config.js
/* 是否为生产环境 */
const isProduction = process.env.NODE_ENV !== 'development'
/* 本地环境是否需要使用cdn */
const devNeedCdn = false
/* cdn链接 */
const cdn = {
/* cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称) */
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
/* cdn的css链接 */
css: [],
/* cdn的js链接 */
js: [
'https://cdn.staticfile.org/vue/2.6.10/vue.min.js',
'https://cdn.staticfile.org/vuex/3.0.1/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
module.exports = {
productionSourceMap: false,
chainWebpack: config => {
/* ============压缩图片 start============ */
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
/* ============压缩图片 end============ */
/* ============注入cdn start============ */
config.plugin('html').tap(args => {
/* 生产环境或本地需要cdn时,才注入cdn */
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
/* ============注入cdn end============ */
},
configureWebpack: config => {
/* 用cdn方式引入,则构建时要忽略相关资源 */
if (isProduction || devNeedCdn) config.externals = cdn.externals
}
}
在public
index.html
写入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 使用CDN的CSS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.css) { %>
<link
href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
rel="stylesheet"
/>
<% } %>
<!-- 使用CDN的CSS文件 -->
<title>cli3_base</title>
</head>
<body>
<noscript>
<strong
>We're sorry but cli3_base doesn't work properly without
JavaScript enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- 使用CDN的JS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- 使用CDN的JS文件 -->
<!-- built files will be auto injected -->
</body>
</html>
在src/router.js
修改
Vue.use(Router)
/** 改为 */
if (!window.VueRouter) Vue.use(Router)
重启项目npm run serve
, 然后浏览器查看Network JS

4.代码压缩
安装依赖:cnpm i -D uglifyjs-webpack-plugin
在vue.config.js
上边引入依赖
/* 代码压缩 */
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
在vue.config.js
vueConfig
configureWebpack
里面新增
/* 生产环境相关配置 */
if (isProduction) {
/* 代码压缩 */
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
/* 生产环境自动删除console */
compress: {
warnings: false, /* 若打包错误,则注释这行 */
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
}
5.开启GZIP
安装依赖:cnpm install --save-dev compression-webpack-plugin
在vue.config.js
顶部引入依赖
/* gzip压缩 */
const CompressionWebpackPlugin = require('compression-webpack-plugin')
在vue.config.js
vueConfig
configureWebpack
里面新增,直接放在代码压缩
下边即可
/* 生产环境相关配置 */
if (isProduction) {
/* 代码压缩 */
/* .................. */
/* gzip压缩 */
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, /* 只有大小大于该值的资源会被处理 10240 */
minRatio: 0.8, /* 只有压缩率小于这个值的资源才会被处理 */
deleteOriginalAssets: false /* 删除原文件 */
})
)
}
需要配合nginx(Apache)使用
server {
listen 9900 default_server;
server_name _;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /data/micro-front;
index /index.html;
try_files $uri $uri/ /index.html;
gzip on; # 开启GZIP
gzip_static on; # gzip_static是nginx对于静态文件的处理模块,该模块可以读取预先压缩的gz文件,这样可以减少每次请求进行gzip压缩的CPU资源消耗。
gzip_min_length 1k; # 启用gzip压缩的最小文件;小于设置值的文件将不会被压缩
gzip_http_version 1.1;
gzip_comp_level 9; # gzip 压缩级别 1-10
# 进行压缩的文件类型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
if ($request_filename ~* .*\.(?:html|html)$)
{
add_header Cache_Control "no-cache, must-revalidate";
add_header "Prama" "no-cache";
add_header "Expires" "0";
}
if ($request_filename ~* .*\.(?:js|css)$)
{
add_header Cache_Control "no-cache";
expires 7d;
}
if ($request_filename ~* .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$)
{
expires 7d;
}
if ($request_method = "OPTIONS") {
return 204;
}
}
}
6.公共代码抽离
在vue.config.js
module.exports
configureWebpack
里面新增,直接放在gzip压缩
下边即可
/* 公共代码抽离 */
config.optimization = {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,
maxInitialRequests: 5,
minSize: 0,
priority: 100
},
common: {
chunks: 'all',
test: /[\\/]src[\\/]js[\\/]/,
name: 'common',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 60
},
styles: {
name: 'styles',
test: /\.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true
},
runtimeChunk: {
name: 'manifest'
}
}
}
}
完整的配置文件
/* 代码压缩 */
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
/* gzip压缩 */
const CompressionWebpackPlugin = require('compression-webpack-plugin')
/* 是否为生产环境 */
const isProduction = process.env.NODE_ENV !== 'development'
/* 本地环境是否需要使用cdn */
const devNeedCdn = true
/* cdn链接 */
const cdn = {
/* cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称) */
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
/* cdn的css链接 */
css: [],
/* cdn的js链接 */
js: [
'https://cdn.staticfile.org/vue/2.6.10/vue.min.js',
'https://cdn.staticfile.org/vuex/3.0.1/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
const vueConfig = {
productionSourceMap: false,
chainWebpack: config => {
/* ============压缩图片 start============ */
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
/* ============压缩图片 end============ */
/* ============注入cdn start============ */
config.plugin('html').tap(args => {
/* 生产环境或本地需要cdn时,才注入cdn */
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
/* ============注入cdn end============ */
},
configureWebpack: config => {
/* 用cdn方式引入,则构建时要忽略相关资源 */
if (isProduction || devNeedCdn) config.externals = cdn.externals
/* 生产环境相关配置 */
if (isProduction) {
/* 代码压缩 */
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
/*生产环境自动删除console */
compress: {
warnings: false, /* 若打包错误,则注释这行 */
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
/* gzip压缩 */
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, /* 只有大小大于该值的资源会被处理 10240 */
minRatio: 0.8, /* 只有压缩率小于这个值的资源才会被处理 */
deleteOriginalAssets: false /* 删除原文件 */
})
)
/* 公共代码抽离 */
config.optimization = {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,
maxInitialRequests: 5,
minSize: 0,
priority: 100
},
common: {
chunks: 'all',
test: /[\\/]src[\\/]js[\\/]/,
name: 'common',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 60
},
styles: {
name: 'styles',
test: /\.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true
},
runtimeChunk: {
name: 'manifest'
}
}
}
}
}
}
}
module.exports = vueConfig