虽然在日常开发中,我们使用vue
和react
框架,它们的脚本架vue-cli
和react-react-app
会帮我们配置最基本的webpack
,但我们了解webpack
的一些配置,会让我们在需要特定个性化配置时不至于手忙脚乱,能够做进一步优化操作等。
在vue-cli
中,要查看webpack
的默认配置,可以在项目中使用vue inspect
命令查看;
在react-react-app
中,使用npm run eject
将内建的webpack
文件都暴露出来
这篇将进一步介绍webpack5
一些高级配置:
- 多入口文件配置:
entry + output + html-webpack-plugin
- css文件抽离和压缩:
- 抽离:
mini-css-extract-plugin
- 压缩:
terser-webpack-plugin + optimize-css-assets-webpack-plugin
- 抽离:
- 抽离公共代码和第三方代码:
splitChunks
- 懒加载:
import('xxx.js').then(res => {...})
- 识别
.jsx
:@babel/preset-react
- 识别
.vue
:vue-loader
多入口文件配置
- 修改入口文件,改为对象形式
// webpack.common.js
// entry: path.join(srcPath, 'index'),
entry: {
index: path.join(srcPath, 'index.js'),
other: path.join(srcPath, 'other.js')
},
- 修改要输出的模板配置,一般有多少个入口,就会设多少个出口模板,注意要写上不同的
filename
,chunks
是个数组,用来说明引入哪些chunk
,如果不写,会默认引入所有入口文件
// webpack.common.js
plugins: [
require('autoprefixer'),
new CleanWebpackPlugin(), // 清除之前的打包文件
new htmlWebpackPlugin({
// template: 'index.html',
template: path.join(rootPath, 'index.html'),
// 在这里还可以自定义参数,在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>获取自定义属性
title: 'webpack multi demo1',
filename: 'index.html',
// 指明要引用哪些chunk,如不指定,会默认引用所有入口文件
chunks: ['index'] // 只引用index.js
}),
new htmlWebpackPlugin({
template: path.join(rootPath, 'other.html'),
filename: 'other.html',
title: 'webpack multi demo2',
chunks: ['other'] // 指明引用other.js入口文件
})
]
- 修改出口文件
设置动态的[name]
,用于匹配入口文件设置的文件名
// webpack.prod.js
output: {
// filename: 'bundle.[chunkhash].js',
filename: '[name].[chunckhash:8].js', // 从写死改为以入口文件命名
path: path.join(__dirname, '..', 'dist') // 输出目录
}
抽离并压缩css
- 抽离
上一篇已经说明如何使用mini-css-extract-plugin
来抽离css
文件,抽离的好处是,当只改变js
文件时,css
文件因为hash
没变,所以可以使用缓存,而不需要重新加载,访问速度会快一些
// webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name]-[contenthash].css'
})
]
打包出来的css
文件如下:
body {
background-color: yellow;
opacity: 0.7;
/* transform: rotate(45deg); */
/* background: url('../imgs/img002.jpg'); */
}
.test {
font-size: 18px;
font-weight: bold;
}
- 压缩
单抽离是不够的,我们在生产环境中还需要对其进行压缩,并尽可能让打包的资源体积小,这也是加快速度的一种手段- 安装:
npm i terser-webpack-plugin optimize-css-assets-webpack-plugin -D
- 配置
- 安装:
// webpack.prod.js
const TerserWebpackPlugin = require('terser-webpack-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const prodConfig = {
// ...
optimization: {
minimizer: [new TerserWebpackPlugin({}), new OptimizeCssAssetsWebpackPlugin()]
}
}
打包后,可以看到css
文件被压缩了,且注释被去掉了
body{background-color:#ff0;opacity:.7}.test{font-size:18px;font-weight:700}
抽离公共代码和第三方代码
a
文件引入了c
文件,b
也引入了c
文件,那么在打包这a和b
这两文件时,都要分别引入c
文件,这操作不仅冗余,而且还浪费性能,当c
文件很大时,这个问题就越加明显。
我们希望c
文件只引入一次,就可以在多个文件中使用,这就是我们说的公共代码。
第三方代码指代的,它一般是指我们安装引入的第三方库,引入了后基本就不会变了,所以要与我们的业务代码分离开来,这样,我们修改业务代码时,第三方代码的文件不会改变,从而可以命中缓存,加快加载速度。
抽离公共代码和第三方代码的配置,也比较简单,就是在optimization
中添加splitChucks
的配置,可以看到,在webpack5
除了入口文件外,已经实现基本的按需引入,不需要我们在入口文件中再手动设置指定的chunks
// webpack.prod.js
optimization: {
minimizer: [new TerserWebpackPlugin({}), new OptimizeCssAssetsWebpackPlugin()],
splitChunks: {
chunks: 'all', // 表示要分割的chunk类型:initial只处理同步的; async只处理异步的;all都处理
// 缓存分组
cacheGroups: {
// 第三方模块
verdors: {
name: 'verdor', // chunk名称
test: /node_modules/, // 设置命中目录规则
priority: 1, // 优先级,数值越大,优先级越高
minSize: 0, // 小于这个大小的文件,不分割
minChunks: 1 // 最少复用几次,这里意思是只要用过一次就分割出来
},
// 公共模块
common: {
name: 'common',
minChunks: 2,
priority: 0,
minSize: 0,
minChunks: 2 // 只要引用过2次,就分割成公共代码
}
}
}
}
设置两个入口文件
// index.js
import _ from 'lodash'
import { sum } from './common/math'
console.log(sum(1,2))
console.log(_.each)
// other.js
import { sum } from './common/math'
console.log(sum(3,4))
plugins: [
new htmlWebpackPlugin({
template: path.join(rootPath, 'index.html'),
title: 'webpack multi demo1',
filename: 'index.html',
chunks: ['index'] // 引入index.js
}),
new htmlWebpackPlugin({
template: path.join(rootPath, 'other.html'),
filename: 'other.html',
title: 'webpack multi demo2',
chunks: ['other'] // 指明引用other.js入口文件
})
]
打包后,输出模板中:
index.html
引入了verdor,common,index
<!-- index.html -->
<script defer="defer" src="verdor.ab38c0e4.js"></script>
<script defer="defer" src="common.1be3f0b4.js"></script>
<script defer="defer" src="index.632b90fb.js"></script>
other.html
中引入了common.js
和other.js
<!-- other.html -->
<script defer="defer" src="common.1be3f0b4.js"></script>
<script defer="defer" src="other.cea083a6.js"></script>
懒加载
懒加载是webpack
默认支持的,不需要我们额外配置,使用方式:import('xxxx')
// common/dynamicData.js
export default {
msg: 'dynamic data'
}
// index.js
setTimeout(() => {
// 直接使用import导入即可,这样加载的模块,相当于一个独立的chunk存在
import('./common/dynamicData.js').then(res => {
console.log(res.default.msg);
})
}, 1000)
解析.jsx
- 安装:
npm i @babel/preset-react -D
- 在根目录下创建
.babelrc
{
"presets": ["@babel/preset-react"]
}
解析.vue
- 安装:
npm i vue-loader -D
- 配置:
// webpack.common.js
module: {
rules: [
{
test: /\.vue$/,
use: ['vue-loader'],
include: srcPath
}
]
},