我们打包出来的js文件,只要修改或增加了内容,就会导致入口js文件的hash变化,从而重新打包。为了提高打包速度,每次变化仅仅是重新打包自定义代码部分,webpack4提供了optimization.splitChunks
回顾一下:webpack3时代,项目的代码分离抽取出来,是这样子的:使用new webpack.optimize.CommonsChunkPlugin,分别分离出第三方库,webpack运行时的代码文件,自定义公共代码部分
new webpack.optimize.ModuleConcatenationPlugin(),
// vendor,分离出的第三方库:node_modules的模块,这些是固定的
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// 分离出的运行时的代码,这些经常有修改,经常要webpack重新打包
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// 公共模块代码
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3//模块被多少个chunk公共引用才被抽取出来成为commons chunk
})
自从webpack4以来,分离代码用的是optimization.splitChunks
官网SplitChunksPlugin说明
Since webpack v4, the CommonsChunkPlugin was removed in favor of optimization.splitChunks.
这个splitChunks,默认做好相关配置了
> New chunk can be shared OR modules are from the node_modules folder
> 模块被重复引用或者来自node_modules中的模块
> New chunk would be bigger than 30kb (before min+gz)
> 在压缩前最小为30kb
> Maximum number of parallel requests when loading chunks on demand
> would be lower or equal to 5
> 在并行的按需加载时,请求数量小于等于5
> Maximum number of parallel requests at initial page load would be lower or equal to 3 When trying to fulfill the last two conditions, bigger chunks are preferred.
> 在并行的初始化加载时,请求数量小于等于3
以下是其默认代码配置详情
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',//块的范围,有三个可选值:initial/async动态异步加载/all全部块(推荐),默认为async;
minSize: 30000,//代码分割的最小值,默认30k;
maxSize: 0,
minChunks: 1,//模块被引用次数多少时才会进行代码分割,默认为1;
maxAsyncRequests: 5,//最大的按需(异步)加载次数,默认为5
maxInitialRequests: 3,//最大的初始化加载次数,默认为3;
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
name: true,//拆分出来块的名字(Chunk Names),默认由块名和hash值自动生成;
cacheGroups: {//缓存组
vendors: {//key 为entry中定义的 入口名称
test: /[\\/]node_modules[\\/]/,
priority: -10//优先级
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true//复用之前的打包模块
}
}
}
}
};
前置条件:我们在项目中引入一个异步模块,命名为async-module,
本项目中其他已经安装的第三方库有vue,vue-router,均是静态引入
使用默认async配置的打包结果
async-module1.6bf897eb.js 227 bytes 0 [emitted] [immutable] async-module1
async-module1.6bf897eb.js.map 133 bytes 0 [emitted] [dev] async-module1
main.f754e233.js 130 KiB 1 [emitted] [immutable] main
main.f754e233.js.map 127 bytes 1 [emitted] [dev] main
查看代码分析结果:main.js文件包含node_modules和src,
旁边紫色小块是异步模块async-module1.js
来个小尝试,如果把默认配置中的vendor改为’all’会是怎样的?
async-module1.6bf897eb.js 227 bytes 0 [emitted] [immutable] async-module1
async-module1.6bf897eb.js.map 133 bytes 0 [emitted] [dev] async-module1
main.339cc1fc.js 7.7 KiB 1 [emitted] [immutable] main
main.339cc1fc.js.map 115 bytes 1 [emitted] [dev] main
vendors~main.c8120c6a.js 123 KiB 2 [emitted] [immutable] vendors~main
vendors~main.c8120c6a.js.map 137 bytes 2 [emitted] [dev] vendors~main
可以看到,此时webpack会把第三方库node_modules的抽离放在vendors~main.js中,src的放在main.js中,异步的放在async-module1.js中
在指定chunk为all的基础上再追加一个:runtimeChunk:true,把webpack运行时的函数代码抽离出来
. //.............省略..................
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true//复用之前的打包模块
}
}
},
runtimeChunk:true
}
结果如下
Asset Size Chunks Chunk Names
async-module1.6bf897eb.js 227 bytes 0 [emitted] [immutable] async-module1
async-module1.6bf897eb.js.map 133 bytes 0 [emitted] [dev] async-module1
main.5b2f5ac7.js 5.51 KiB 1 [emitted] [immutable] main
main.5b2f5ac7.js.map 115 bytes 1 [emitted] [dev] main
runtime~main.4d3db02e.js 2.29 KiB 2 [emitted] [immutable] runtime~main
runtime~main.4d3db02e.js.map 131 bytes 2 [emitted] [dev] runtime~main
vendors~main.32b19645.js 123 KiB 3 [emitted] [immutable] vendors~main
vendors~main.32b19645.js.map 137 bytes 3 [emitted] [dev] vendors~main
可以看到运行时的代码依赖函数runtime_main.js也被抽离了出来
到这里代码的抽取就结束了
附个性化的配置,根据需要大家自行配置
optimization: {
// 采用splitChunks提取出entry chunk的chunk Group
splitChunks: {
cacheGroups: {
// 处理入口chunk,同步的
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
name: 'vendors',
},
// 处理异步chunk
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
}
}
},
// 为每个入口提取出webpack runtime模块
runtimeChunk: { name: 'manifest' }
}
当mode为production时,webpack会自动启动压缩
optimization.minimize:true
压缩js
我自己试了下在optimization中配置
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
sourceMap: true, // Must be set to true if using source-maps in production
terserOptions: {
// https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
}
}),
new OptimizeCSSAssetsPlugin()
],
发现打包结果不变
既然压缩js好像没啥变化,那就来压缩css代码和html吧
压缩css
const OptimizeCSSAssetsPlugin=require('optimize-css-assets-webpack-plugin')
//......在plugins中添加
new OptimizeCSSAssetsPlugin ()
压缩html
new HtmlWebpackPlugin({
minify:{
removeRedundantAttributes:true, // 删除多余的属性
collapseWhitespace:true, // 折叠空白区域
removeAttributeQuotes: true, // 移除属性的引号
removeComments: true, // 移除注释
collapseBooleanAttributes: true // 省略只有 boolean 值的属性值 例如:readonly checked
},
favicon:''
}),
index.html 361 bytes [emitted]
main.css 2.84 KiB
---------------之前与之后的对比----------
index.html 318 bytes [emitted]
main.css 1.23 KiB
resolve
配置扩展项、别名方便于我们的开发,而modules库的查看范围,一定范围加快了webpack的查找速度
resolve: {
extensions: ['.js', '.vue', '.json'],//告诉解析器在解析路径资源中能够接受哪些扩展名(例如 .js, .jsx)
modules: [
path.resolve('src'),
path.resolve('node_modules')
],// resolve.modules 是用来配置模块库(即 node_modules)所在的位置,默认向上搜素,直接指定位置减少搜索时间
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.resolve('src'),
}
},
图片
对于小的头像图片,可以考虑转base64码,网上有在线转换工具的
图片懒加载动画条可以提高用户体验
避免大的背景图
exclude,include(优先级较高)
例如我们在配置.vue文件,js的loader,可以指定排除哪个文件夹,提升性能
{
test: /\.vue$/,
loader: 'vue-loader',
include: [path.resolve('src')],
},