首先得知道为什么这个文件比较大,chunk-vendors.xxx.js是一个保存着各种相关依赖的关系的文件,比如导入的elmentUI、echarts、vue、vue-router等各种依赖
1.使用cdn加速
// 修改vue.config.js 分离不常用代码库
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === "production") {
config.externals = { // 不会被打包的库
'vue': 'Vue',
'vue-router': 'VueRouter',
'moment': 'moment'
}
}
}
}
// 然后在public文件夹的index.html 使用cdn加载
<!-- CDN -->
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.runtime.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
2.开启gzip压缩
一、安装compression-webpack-plugin插件。前端将文件打包成.gz文件,然后通过nginx的配置,让浏览器直接解析.gz文件,可以大大提升文件加载的速度。
1.npm使用下面命令安装
npm install --save-dev compression-webpack-plugin
修改vue.config.js配置
const webpack = require('webpack')
const CompressionWebpackPlugin = require('compression-webpack-plugin')//这个插件可以看官网还是很好用的
const productionGzipExtensions = ['js', 'css']//对什么文件进行压缩
const Timestamp = new Date().getTime();//防止http的缓存每次打包用时间戳进行区分
module.exports = {
//这里是自己的配置
configureWebpack: {
output: { // 输出重构 打包编译后的 文件名称
filename: `js/[name]${Timestamp}.js`,
chunkFilename: `js/[name]${Timestamp}.js`
},
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),//该插件能够使得指定目录被忽略,从而使得打包变快,文件变小
// 下面是下载的插件的配置
new CompressionWebpackPlugin({
algorithm: 'gzip',//压缩算法
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),//处理所有匹配此 {RegExp} 的资源
threshold: 10240,//只处理比这个值大的资源。按字节计算
minRatio: 0.8//只有压缩率比这个值小的资源才会被处理
}),
//另一种方法是解决打包后chunk.js文件过多问题。
// LimitChunkCountPlugin可以通过合并块来对块进行后期处理
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 5, //控制打包生成js的个数 必须大于或等于 1,此处设置成最多生成5个chunk.js文件
minChunkSize: 100
})
]
},
}
3.移除prefetch插件和preload
vue 脚手架默认开启了 preload 与 prefetch,当我们项目很大时,这个就成了首屏加载的最大元凶了
preload 与 prefetch 都是一种资源预加载机制;
preload 是预先加载资源,但并不执行,只有需要时才执行它;
prefetch 是意图预获取一些资源,以备下一个导航/页面使用;
preload 的优先级高于 prefetch。
vue项目目前用的是路由懒加载的模式,在每一次刷新都会重新加载很多js文件,由于路由都没有自定义webpackChunkName,所以就是默认的11(数字).js这种。
打包后默认是chunk-xxx.js
一种方法是移除prefetch,此插件是用来告诉浏览器在页面加载完成后,利用空闲时间提前获取用户未来可能会访问的内容。具体内容官网
vue.config.js配置
//关闭关闭 preload 与 prefetch
chainWebpack: config => {
// 移除 preload(预载) 插件
config.plugins.delete('preload')
// 移除 prefetch(预取) 插件
config.plugins.delete('prefetch')
}
4.webpack分包
在 Webapck4.x 版本之前,使用 CommonsChunkPlugin去做分离,webpack 4 最大的改动就是废除了 CommonsChunkPlugin 引入了 optimization.splitChunks。如果你的 mode 是 production,那么 webpack4 就会自动开启 Code Splitting。
chainWebpack:config => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
// cacheGroups 下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 被至少用三次以上打包分离
priority: 5, // 优先级
reuseExistingChunk: true // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial', // 只打包初始时依赖的第三方
test: /[\\/]node_modules[\\/]/,
priority: 10
},
vantUI: {
name: 'chunk-vantUI', // 单独将 vantUI 拆包
priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
test: /[\\/]node_modules[\\/]_?vant(.*)/
},
elementUI: {
name: 'chunk-elementUI',
priority: 20,
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
}
})
config.optimization.runtimeChunk('single')
}
5.减少打包文件的体积
productionSourceMap
在通过 vue-cli 脚手架生成的项目中,其值默认为 true 。它的作用是用来显示或定义一些"问题"代码。但是对于生产环境,我们可以进行关闭。这样能够对于打包后文件的体积有很大的减少
module.exports = {
productionSourceMap: false,
...
}
6.tree shaking
// vue.config.js
module.exports = {
configureWebpack: {
optimization: {
usedExports: true, // 启用Tree-Shaking
sideEffects: true, // 表示整个项目全部都有副作用,不会进行Tree-Shaking
sideEffects: false // 全部进行tree shaking
// 如果想设置某些文件不进行Tree-Shaking
sideEffects: [
'./src/some-side-effect-file.js'
]
}
}
}
上面通过·optimzation.usedExports启用了Tree Shaking功能。
sideEffects默认是false,表示可以进行Tree Shaking,会剔除无用代码。
如果整个项目中存在有副作用的文件,需要设置sideEffects为true来关闭。
同时可以通过sideEffects字段来指定某些文件不要进行Tree Shaking。
这样通过配置,可以启用Tree Shaking来删除项目中未使用的代码,减少打包后的容量。
sideEffects
这时候仍存在一个问题,如果通过模块化引入另一个js文件,即使没有被使用,useExports 也不会进行 tree shaking
// index.js
import './format.js';
// format.js
export function timeFormat() {
return '2022-01-01';
}
比如上面这段代码,通过 import 语句引入 format.js,但 format.js 导出的函数没有被使用。
此时仍然对于 import 语句进行了编译,我们希望在引入的文件中也进行 tree shaking,删除无用的代码,这个时候在 package.json 中配置 sideEffects 属性来处理。
// package.json 其他配置省略
{
"sideEffects": false
}
sideEffects 用于告知 webapck 编译器哪些模块有副作用
定义为 false,表示所有的模块都不存在副作用,不需要用到的时候直接删除 定义为数组,告知有副作用的模块,该模块中有副作用的代码会被保留,没有副作用且没有使用到的代码会被删除。
这样引入的 js 文件没有被使用,进行了 tree shaking,可是 css 资源通过 import 引入也被删除了,也不会编译生成对应的 css 文件,解决方式可以选择在 sideEffects 属性中定义数组,或者处理 css 文件的 loader 中配置(推荐)。
// package.json
{
"sideEffects": [
"**.css"
],
}
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
// 其它配置省略
sideEffects: true,
},
],
},
};
7.自动刷新只重新构建修改的文件
// vue.config.js
module.exports = {
configureWebpack: {
// 其他配置
},
devServer: {
watch:true,
hot:true,
watchOptions: {
poll: 1000, //每秒询问1000次
aggregateTimeout: 500, //防抖,500毫秒内重复的重新构建请求只会构建一次
ignored: /node_modules/ //忽略对node_modules的监听
}
}
}
通过配置 watchOptions,可以优化开发时的模块热替换体验,避免不必要的重启编译。
需要注意 devServer.watch 也需要设置为 true,watchOptions 才会生效
8.优化Loader配置,仅针对需要处理的文件
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('js')
.test(/\.js$/)
.include
.add(path.resolve(__dirname, 'src'))
.end()
.use('babel')
.loader('babel-loader')
.options({
cacheDirectory: true
})
config.module
.rule('images')
.test(/\.(png|jpe?g|gif)(\?.*)?$/)
.use('url-loader')
.loader('url-loader')
.options({
limit: 10000
})
}
}
通过chainWebpack获取规则配置,然后使用include仅针对src目录应用babel-loader。
同时使用cacheDirectory开启babel缓存。
另外针对图片使用url-loader,并设置了大小限制,只有小于10kb的图片会转base64编码。
这样只对需要的资源应用Loader进行转换,可以有效优化构建性能。
可以根据项目实际情况,决定哪些文件需要进行Loader转换,只针对该部分文件应用规则。