Vue项目打包优化
一、知识点和目的
1、打包优化的目的
2、性能优化的主要方向
二、打包优化
1.去除.map文件
2.开启CDN加速
3.代码压缩
4.图片压缩
5.公共代码抽离,写在configureWebpack模块中
6.骨架屏
7.开启Gzip压缩
全部代码
点击跳转博主博客
一、知识点和目的
1、打包优化的目的
1、项目启动速度,和性能
2、必要的清理数据
3、减少打包后的体积
第一点是核心,第二点呢其实主要是清理console
2、性能优化的主要方向
1、去重.map文件
2、开启CDN加速
3、代码压缩
4、图片压缩
5、公共代码抽离,写在configureWebpack模块中
6、首屏骨架屏优化
7、开启Gzip压缩
二、打包优化
1.去除.map文件
在vue.config.js中添加
productionSourceMap: false, //不输出map文件
2.开启CDN加速
快速查找对应cdn
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== ‘development’;
// 本地环境是否需要使用cdn
const devNeedCdn = false
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: ‘Vue’,
vuex: ‘Vuex’,
‘vue-router’: ‘VueRouter’,
‘marked’: ‘marked’,
‘highlight.js’: ‘hljs’,
‘nprogress’: ‘NProgress’,
‘axios’: ‘axios’
},
// cdn的css链接
css: [
],
// cdn的js链接
js: [
'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
'https://cdn.bootcss.com/vuex/3.1.2/vuex.min.js',
'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
'https://cdn.bootcss.com/axios/0.19.2/axios.min.js'
]
}
module.exports = {
chainWebpack: config => {
// 注入cdn start
config.plugin(‘html’).tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
// 注入cdn start
},
configureWebpack: config => {
// 用cdn方式引入,则构建时要忽略相关资源
if (isProduction || devNeedCdn) config.externals = cdn.externals
}
}
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.css) { %>
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.js) { %>
<% } %>
3.代码压缩
安装插件 npm i -D uglifyjs-webpack-plugin
// 代码压缩
//在configureWebpack中加入
const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’)
// 代码压缩
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
//生产环境自动删除console
compress: {
drop_debugger: true,
drop_console: true,
pure_funcs: [‘console.log’]
}
},
sourceMap: false,
parallel: true
})
)
4.图片压缩
安装插件 npm install image-webpack-loader --save-dev
在chainWebpack中新增以下代码
// 压缩图片 start
config.plugins.delete(‘prefetch’)
config.module.rule(‘images’)
.test(/.(png|jpe?g|gif|svg)(?.*)?$/)
.use(‘image-webpack-loader’)
.loader(‘image-webpack-loader’)
.options({ bypassOnDebug: true })
// 压缩图片 end
图片生成在线地址
5.公共代码抽离,写在configureWebpack模块中
// 公共代码抽离
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’
}
}
}
}
6.骨架屏
安装插件 npm install vue-skeleton-webpack-plugin
在src下新建Skeleton文件夹,其中新建index.js以及index.vue,在其中写入以下内容,其中,骨架屏的index.vue页面样式请自行编辑
index.js
import Vue from ‘vue’
import home from ‘./index.vue’
import list from ‘./a.vue’
export default new Vue({
components: {
home,
list
},
template: `
vue.config.js
//骨架屏渲染
const SkeletonWebpackPlugin = require(‘vue-skeleton-webpack-plugin’)
//path引入
const path = require(‘path’)
//configureWebpack模块中写入内容
// 骨架屏渲染
config.plugins.push(new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, ‘./src/Skeleton/index.js’),
},
},
minimize: true,
quiet: true,
// 如果不设置那么所有的路由都会共享这个骨架屏组件
router: {
mode: ‘hash’,
// 给对应的路由设置对应的骨架屏组件,skeletonId的值根据组件设置的id
routes: [
{ path: ‘/list’, skeletonId: ‘home’ },
{ path: ‘/kc’, skeletonId: ‘list’ },
]
}))
7.开启Gzip压缩
yarn add [email protected] --save-dev
注意的是,服务器上nginx也必须开启gzip才能生效
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== ‘development’;
}
nginx中
# 开启gzip
gzip on;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 2;
# 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除
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;
# 设置压缩所需要的缓冲区大小
gzip_buffers 4 16k;
全部代码
// vue.config.js
//骨架屏渲染
const SkeletonWebpackPlugin = require(‘vue-skeleton-webpack-plugin’)
//path引入
const path = require(‘path’)
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== ‘development’;
// 代码压缩
const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’)
// 本地环境是否需要使用cdn
const devNeedCdn = false
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: ‘Vue’,
vuex: ‘Vuex’,
‘vue-router’: ‘VueRouter’,
‘axios’: ‘axios’,
‘element-ui’: ‘ELEMENT’,
‘vant’:‘vant’
},
// cdn的css链接
css: [
‘https://unpkg.com/element-ui/lib/theme-chalk/index.css’,
‘https://cdn.jsdelivr.net/npm/[email protected]/lib/index.css’,
],
// cdn的js链接
js: [
‘https://cdn.bootcss.com/vue/2.6.10/vue.min.js’,
‘https://cdn.bootcss.com/vuex/3.1.2/vuex.min.js’,
‘https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js’,
‘https://cdn.bootcss.com/axios/0.19.2/axios.min.js’,
‘https://unpkg.com/element-ui/lib/index.js’,
‘https://cdn.jsdelivr.net/npm/[email protected]/lib/vant.min.js’
]
}
module.exports = {
lintOnSave: false,
publicPath: ‘./’,
css: {
loaderOptions: {
postcss: {
plugins: [
require(‘postcss-plugin-px2rem’)({
rootValue:35, //换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
// unitPrecision: 5, //允许REM单位增长到的十进制数字。
//propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。
// propBlackList: [], //黑名单
// exclude: /(page_pc)/i, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
exclude: /node_modules/i,
// selectorBlackList: [‘van-’], //要忽略并保留为px的选择器,我们一般不转换vantui中的大小
// ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
// replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
}),
]
}
}
},
productionSourceMap: false, //不输出map文件
chainWebpack: config => {
// 注入cdn start
config.plugin(‘html’).tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
// 注入cdn start
// 压缩图片 start
config.module
.rule(‘images’)
.use(‘image-webpack-loader’)
.loader(‘image-webpack-loader’)
.options({bypassOnDebug: true
})
.end()
// 压缩图片 end
},
configureWebpack: config => {
if (isProduction || devNeedCdn) config.externals = cdn.externals
config.plugins.push(new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, ‘./src/Skeleton/entry-skeleton.js’),
},
},
minimize: true,
quiet: true,
router: {
mode: ‘hash’,
// 给对应的路由设置对应的骨架屏组件,skeletonId的值根据组件设置的id
routes: [
{ path: ‘/list’, skeletonId: ‘skeleton’ }
]
}
}))
// 用cdn方式引入,则构建时要忽略相关资源
// if (isProduction || devNeedCdn) config.externals = cdn.externals
// 公共代码抽离
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’
}
}
}
}
// 代码压缩
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
//生产环境自动删除console
compress: {
drop_debugger: true,
drop_console: true,
pure_funcs: [‘console.log’]
}
},
sourceMap: false,
parallel: true
})
)
},
}