vue项目中使用webpack打包优化
项目的优化是为了去除项目冗余,使项目加载渲染更快,此篇文章只会说对我目前项目有用的几个优化的点,后续会再更新
————————————————此次更新 2022/10/17
这个标题百度的话会有多种方案,因为我目前的项目比较小,打包完不到4MB,所以有些优化可能用不上
以我目前的这个vue-cli4的项目来讲,配置都是在 根目录下的 vue.config.js 这个文件中进行的
对我项目有用的
项目打包分析的可视化工具
下载到项目中
# NPM
npm install --save-dev webpack-bundle-analyzer
# Yarn
yarn add -D webpack-bundle-analyzer
在vue.config.js文件中配置
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;// 引入
module.exports = {
// 。。。。省略其他配置
chainWebpack:config=>{// 使用
config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin)
}
}
这样你每次打包、启动项目都会给你打开这样的一个页面,就是你项目中用到的所有依赖,可以针对某一块进行优化。
每一个大块都是一个js文件
1、打包优化moment.js包,无需下载任何插件,有webpack即可
通过上面的可视化分析,我发现我项目中的moment.js比较大,希望针对他进行一个优化
优化前:
可以看到只是moment.js就占用了六百多kb,这对我的项目来说绝对是需要优化的点了
方案:
vue.config.js
const webpack = require('webpack');// 引入webpack
configureWebpack: config =>{
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /^\.\/(zh-cn|vi)$/i), //减小moment语言包
// 这段配置大概意思就是去除了moment.js包中的其他语言,只留下了中文部分,从而缩减了体积
}
优化后
可以明显看到moment的体积大大缩小了
有用!
2、注释与console的消除
我们的线上项目一般是不需要注释和控制台输出的,将其处理掉也可以缩小我们项目的部分冗余
直接引入即可,无需下载
const UglifyJsPlugin = require('uglifyjs-webpack-plugin') //引入插件
configureWebpack: config =>{
config.plugins.push(
new UglifyJsPlugin({ // 使用插件
uglifyOptions: {
// 删除注释
output: {
comments: false
},
// 删除console debugger 删除警告
compress: {
drop_console: true, //console
drop_debugger: false,
pure_funcs: ['console.log'] //移除console,这是个数组,也可以后面继续扩展你想要清除的,比如console.error等
}
}
}),
)
}
这个优化对于项目中注释和console比较多的效果会更好,可以对比下配置前与配置后打包体积的大小
3、图片的压缩
因为我们项目中使用到的图片还是比较多的,所以这也是一个优化的大点,图片少的可以忽略~~~
下载这两个loader,处理对图片的压缩
#NPM
npm i url-loader
npm i file-loader
vue-cli项目在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()
.use('url-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
}).end()
config.module.rule('svg')
.test(/\.(svg)(\?.*)?$/)// 针对svg类型图片压缩
.use('file-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
})
},
}
这个对于我目前这个项目的体积优化还是蛮大的,从4M多到3M吧,这个跟项目中图片较多有关系,另外压缩图片方法还有很多其他的配置,这里只是我项目中用到的一种
这里重点提一下tinypng-webpack-plugin这个插件
它是收费的,你申请一个key每个月有一个免费额度,使用完就不能压缩了
我接手这个项目的时候,使用的就是这个,然后某一天,项目突然运行不起来了,终端一直显示图片正在压缩,折腾了一下午,最终发现是当月的免费额度用完了,重新申请了key就可以了,太无语了
需要先下载,这里不推荐使用,所以感兴趣的可以自己去搜索
const tinyPngWebpackPlugin = require('tinypng-webpack-plugin'); // 引用
new tinyPngWebpackPlugin({
// key: "4cQVfjVm5MWKNpvgmTgpGnXg0DlRP6Kd",
/* 项目启动时如果一直出现 【tinyPNG is compressing imgs】 提示,请重新申请key
/* key的申请地址 https://tinypng.com/developers
*/
key: "5y1gdmrpdx3MRpJxBq5Zx9tTH7bTmVQl"
})
3、使用splitChunks拆分第三方库
技术要求:js文件在浏览器中加载要求size不得大于244kb,遂将大文件进一步拆分
webpack打包时,默认的最大资源大小限制为什么是244KB? - 知乎 (zhihu.com)
splitChunks配置介绍:webpack 中文文档 (docschina.org) 文档中有详细说明各个配置项的作用。
拆分第三方库之前,app.js文件达到了1M,没有达到要求
拆分后app.js中的vue、vue-router、core-js被拆分出去,app文件减小
在浏览器中运行的体积,js文件体积均在244kb以下
以下面为例,vue-cli项目中在vue.config.js中将vue、vue-router、core-js 单独拆分为一个js文件
module.exports = {
configureWebpack: config =>{
config.optimization = {
splitChunks: { // 使用splitChunks将第三方库拆分
chunks: 'all',
cacheGroups: {
'vue': {
name: 'vue',
test: /[\\/]node_modules[\\/]vue[\\/]/,
priority: 10
},
'vue-router': {
name: 'vue-router',
test: /[\\/]node_modules[\\/]vue-router[\\/]/,
priority: -10
},
'core-js': {
name: 'core-js',
test: /[\\/]node_modules[\\/]core-js[\\/]/,
priority: -10
},
}
}
},
}
}
webpack创建的vue项目配置:在build/webpack.prod.conf.js中配置
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
entry: { // 想要拆分的第三方插件
// key可以自己定义,value可以参考package.json中的插件名
//3rd party libraries
'vue-qrcode-reader': 'vue-qrcode-reader',
'vue': 'vue',
'moment': 'moment',
// 'vant': 'vant',
// 'vue-router': 'vue-router',
},
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_console: true, //console
drop_debugger: false,
pure_funcs: ['console.log'] //移除console
},
// 删除注释
output: {
comments: false
},
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
new ExtractTextPlugin({ // css压缩
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: true,
}),
// 这里将上面entry中定义的key放在names的数组中
new webpack.optimize.CommonsChunkPlugin({
names: ['vue-qrcode-reader', 'vue', 'moment' ],
minChunks: Infinity
}),
]
第三方插件分离时可以多打包看一下可视化打包结果,是否为最优
4、使用externals将部分第三方库剔除在打包外
Less 快速入门 | Less.js 中文文档 - Less 中文网 (bootcss.com)
less作为css的预处理器,可以更高效、更直观的写出优雅的css
但浏览器最终还是接收的还是css文件,less只是更方便我们书写。
所以我们是否可以打包的时候将less转为css,打包时将less.js包排除在外,这样既享受到了less带来的方便,还没有增加我们的打包体积。
试一下吧
首先确保你没在页面中的任何地方引入less,比如在main.js文件中这样
# import less from "less"
# Vue.use(less)
我们使用less,只需要安装依赖,然后就可以直接使用,并不需要在main.js文件中再引入
不然打包时将less排除,代码中又用到,会报undefined错误
配置如下
外部扩展(externals) | webpack 中文网 (webpackjs.com)
module.exports = {
chainWebpack:config=>{
config.externals({ // 将这些包 排除在build之外
less: "less"
})
}
}
webpack创建的vue项目配置 ./build/webpack.base.conf.js
externals: { // 排除在打包外
'vant': 'vant', // 将vant-ui排除在打包外
},
这样,就没有less,本地查看或者部署到测试,样式都是没问题的
其他
浏览器console输出
performance.timing.loadEventEnd-performance.timing.navigationStart
查看页面加载时间,可以优化前后做一个对比。详情可以搜索 performance
本次更新到这里的优化部分其实就没有(捂脸哭),第一次去研究项目优化这个东西
大家通过可视化工具也看到了,除了moment,还有html2canvas的包也很大,后续将会针对这些进一步减小项目的打包体积,大家如果有什么可行的方案,欢迎在评论区讨论呀
对我项目没用的
在寻找优化的过程中,不可避免的会将可行的方案都执行一遍,然后通过前后对比来确认哪些有用。
这里说的可能是因为某些原因,只是对我的项目没用的,大家也可以在自己项目中尝试看一下有没有效果
1、使用compression-webpack-plugin压缩文件
使用这个插件的目的是为了将我们打包好的文件进一步压缩,在访问服务端传输数据的时候,将压缩好的文件进行传输,达到一个更快的效果
这里是有关插件的一个介绍和一些踩坑注意
说下在我的项目中的配置
安装插件
#NPM npm i compression-webpack-plugin
vue.config.js中配置
module.exports = {
configureWebpack: config =>{
// 省略其他配置。。。。
config.plugins.push(
new CompressionWebpackPlugin({ // 使用插件
// filename: info => { // 会为每个js文件生成一个gz压缩包
// return `${info.path}${info.base}.gz${info.query}`
// },
filename: '[path].gz[query]', // 只会生成一个gz文件
algorithm: 'gzip', // 压缩类型
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
test: /\.js$|\.css$|\.html$|\.ttf$|\.eot$|\.woff$/, // 需要压缩的文件后缀,可更改为适合自己项目的
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 是否删除原文件,一般不删除,如果压缩文件访问失败还可以访问原文件
}),
)
}
}
这里说一下这个filename
我们不删除原文件的话,打包后的体积注定会更大,因为多了压缩后的gz文件,但也应该大不了多少, 这个filename影响了压缩类型,是每个js文件都压缩成一个gz呢,还是一个文件中全部打包只有一个gz文件
我们都应该会选择打包成一个gz文件,这样增加的体积不会太大,还能完成压缩操作,岂不美哉。但是
目前我上面filename的写法: filename:'[path].gz[query]'会在终端中报 waring的错误
大概意思应该就是命名冲突导致的,不清楚这对这个操作有没有什么影响。如果不想看到 waring 的话推荐使用第一种命名方式 ,当然还有其他的写法,但意思都一样
filename: info => { // 会为每个js文件生成一个gz压缩包
return `${info.path}${info.base}.gz${info.query}`
},
感觉没用的原因
这个配置其实我感觉应该是有用的
我的思路是:我们访问服务端需要传输的数据, 将它们打成压缩包,这样向服务器传输的速度更快,我们页面响应的也就会更快
但是老大告诉我,在实际的操作中并不会用到,所以否决了
EMMMMM。。这个问题需要我下去再研究一下,才能得到准确的结论
vue.config.js文件的整体配置(供参考)
const webpack = require('webpack');
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const UglifyJsPlugin = require('uglifyjs-webpack-plugin') //引入插件
module.exports = {
publicPath: '/', // 路由路径
filenameHashing: true, // 文件名hasg
assetsDir: 'assets', //静态资源打包文件夹
productionSourceMap: false,
devServer: {
open: ,
port: , //设置端口
proxy: {
'/api': {
target: 'a.com',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
},
},
},
configureWebpack: config =>{
config.optimization = {
splitChunks: {
chunks: 'all',
cacheGroups: {
'vue': {
name: 'vue',
test: /[\\/]node_modules[\\/]vue[\\/]/,
priority: 10
},
'vue-router': {
name: 'vue-router',
test: /[\\/]node_modules[\\/]vue-router[\\/]/,
priority: -10
},
'core-js': {
name: 'core-js',
test: /[\\/]node_modules[\\/]core-js[\\/]/,
priority: -10
},
}
}
},
config.plugins.push(
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /^\.\/(zh-cn|vi)$/i), //减小moment语言包
new UglifyJsPlugin({
uglifyOptions: {
// 删除注释
output: {
comments: false
},
// 删除console debugger 删除警告
compress: {
drop_console: true, //console
drop_debugger: false,
pure_funcs: ['console.log'] //移除console
}
}
}),
)
},
css: { // css 每次打包清除缓存配置
extract: {
ignoreOrder: true // 处理 “无法满足块组的所需顺序” 警告
},
sourceMap: false,
loaderOptions: {
sass: { },
},
},
//只加载本页面所需要的js文件 (避免加载多余的js文件)
chainWebpack:config=>{
config.externals({ // 将这些包 排除在build之外
less: "less"
})
// 删除无用的prefetch、preload插件,避免加载多余的资源
config.plugins.delete('prefetch')
config.plugins.delete('preload')
config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin)
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]'
})
},
}
————————结尾
————————————————此次更新 2022/10/17
后续再有项目性能优化相关再来更新,上述中有任何错误或者补充 欢迎大家评论区留言 ~ ~ ~
另外弱弱的问一下,webpack官网是好久没更新了吗,使用插件按照官网上的出现各种意外的问题/(ㄒoㄒ)/~~