Webpack5 从零配置一个基础的 Vue 项目
前言
配置日期2021/6/28,使用的 Node.js 版本14.15.4,最低版本建议升至10.16.0+ 。本文记录使用 Webpack5 手动从零配置一个基础 Vue3 项目的学习过程。
若希望使用 vue-cli 创建 Vue3 项目:
- 安装或者升级 vue-cli:npm install -g @vue/cli
- 保证 vue-cli 版本在4.5.0以上:vue --version
- 创建项目选择 vue3.0:vue create 项目名
- windows 用户命令行无法移动光标可以使用这个命令创建项目:winpty vue.cmd create 项目名
文中各配置项,皆为基础使用方法,更多配置请参考官方文档。文中如有不当之处,还望不吝指正,理性交流。
第一部分:初始化项目
目标:完成一个能够打包运行的最基础配置,为后续逐步完善做准备。 示例的基础目录结构如下
创建项目目录、初始化 package.json、安装Webpack 并添加配置文件 webpack.config.js
# 创建文件夹,并且进入
mkdir demo && cd $_
# 初始化package.json
npm init // 或者全部使用默认选项 npm init -y
# 安装 webpack 和 webpack CLI到开发依赖
npm i webpack -D
npm i webpack-cli -D //webpack命令执行之后,会寻找webpack-cli这个包并执行,详见入口文件的逻辑:node_modules/webpack/bin/webpack.js
根目录创建 webpack.config.js 文件并配置 entry 和 output
//webpack.config.js
const path = require('path');
module.exports = {
entry: './src/main.js', // 配置入口文件,单入口使用字符串,多入口使用对象
output: { // 打包后项目文件在硬盘中的存储位置
filename: '[name].js', // [name]占位符的写法可支持多入口
path: path.resolve(__dirname, 'dist'),
},
mode: 'production', // 告知 webpack 使用相应模式的内置优化,默认为 production
}
Vue 和相关依赖
npm i vue -S //-S 等于 --save -D 等于 --save-dev i 等于 install
npm i vue-loader -D //解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理
npm i @vue/compiler-sfc -D //将解析完的vue单页面组件(sfc)编译为js
//webpack.config.js
const { VueLoaderPlugin } = require('vue-loader');
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
];
}
plugins: [
new VueLoaderPlugin(),
]
在main.js 中使用 Vue
import { createApp } from 'vue'
import App from './App.vue' // 测试文件 App.vue 和 用于挂载的index.html 自行创建
createApp(App).mount('#app')
CSS 相关依赖
npm i css-loader -D // 用于处理 .css 文件
npm i style-loader -D //将样式通过 <style>标签的形式 挂载到页面的 head 部分
//webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader' // loader执行从右到左,这里先执行css-loader
]
},
];
}
html-webpack-plugin
npm i html-webpack-plugin -D //在打包结束后,自动生成一个html文件,并把打包生成的js文件引入到这个html文件当中
//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'),
filename: 'index.html'
}),
]
clean-webpack-plugin
npm i clean-webpack-plugin -D //在打包之前清空output配置的文件夹
// //webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin()
]
webpack-dev-server
npm i webpack-dev-server -D //以file形式在浏览器打开打包后的文件,无法发送ajax请求。所以需要devServer在本地开启一个服务器,以http的形式发送请求。
// //webpack.config.js
module.exports = {
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
open:true,
port:8888, // 第三部分会使用 portfinder 自动获取可用端口号
hot:true,
hotOnly:true,
},
}
webpack-cli4版本,将webpack-dev-server的命令集成到了webpack-cli当中,需使用如下命令:
//package.json
"scripts": {
"dev": "webpack serve --config webpack.config.js"
},
此时,在命令行输入 npm run dev,项目已经可以正常打包启动
第二部分:引入常用库
目标:在项目中引入vuex、vue-router、Element Plus、Axios、ESLint
在src文件夹下新建 router,store,views,components,assets文件夹,目录结构如下
vuex和vue-router
npm i vuex --save
npm i vue-router --save
配置router/index.js,可选 hash 模式(createWebHashHistory)和 history 模式(createWebHistory),history 模式需要后端支持。
import { createRouter, createWebHashHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/home.vue')
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/about.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
配置store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
在main.js中引入vue-router和vuex
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'
let app = createApp(App)
app.use(store)
app.use(router)
app.mount('#app')
配置和引入完成后,vuex和vue-router就可以正常使用了,示例中的测试页面(home.vue,about.vue)自行创建。
Element Plus
npm i element-plus --save
采用官网的按需引入方法,减小打包体积,需要下载插件babel-plugin-import
npm i babel-plugin-import -D //将import依赖整个组件库的方法,转换成require依赖具体模块,实现组件的按需加载
使用该插件需要babel配置文件:babel.config.js
plugins: [
[
"import",
{
libraryName: 'element-plus',
customStyleName: (name) => {
return `element-plus/lib/theme-chalk/${name}.css`;
},
},
],
],
// 解释:
// 当Babel解析遇到:
import { xxx } from 'element-plus'
// 会转换成:
var xxx = require('element-plus/lib/xxx')
// 将本来引入整个名为element-plus的库,转换成引入具体模块'element-plus/lib/xxx'。这样webpack会认为依赖的是具体的xxx而不是整个element-plus。同时引入对应的样式文件。
main.js
// 在main.js中引入并使用element-plus
import {
ElButton,
ElSelect
} from 'element-plus';
const Elcomponents = [
ElButton,
ElSelect
]
Elcomponents.forEach(component => {
app.use(component )
})
Axios
npm i axios -S
可以对axios进一步封装
// http.js
import axios from 'axios'
axios.defaults.baseURL = baseURL
// 请求拦截
axios.interceptors.request.use(config => {
// do something
return config
},error => {
return Promise.reject(error)
})
// 返回拦截
axios.interceptors.response.use(response => {
// do something
return response
},error => {
return Promise.reject(error)
})
export function get(url, params) {
return axios.get(url, {
params
}).then((res) => {
// do something
return res.data
}).catch((e) => {
console.log(e)
})
}
在vue组件中直接使用,或提取成函数后在组件中使用
// 定义获取数据的函数
import { get } from './http'
export function getXxx() {
return get('/api/getXxx').then((result) => {
// do something
return result
})
}
//使用
import { getXxx } from '...'
const list = await getXxx()
ESLint
npm i eslint -D
npm i eslint-plugin-vue -D
生成eslint文件
./node_modules/.bin/eslint --init
在生成的配置文件中,添加插件
"extends": [
"plugin:vue/vue3-essential", // 校验 Vue3 逻辑代码
"plugin:vue/vue3-strongly-recommended", // 校验 Vue3 模板
"eslint:recommended" // 引入eslint核心功能
],
常见插件: eslint-plugin-node:node的eslint配置 eslint-plugin-promise:promise语法配置 eslint-plugin-import:针对import语法优化 eslint-plugin-standard:基础配置(已废弃)
第三部分:拆分webpack.config.js
目标:从第三部分开始,为了方便开发调试和上线,需要将webpack.config.js拆分为以下三个文件。
- webpack.dev.js:开发环境配置
- webpack.prod.js:生产环境配置
- webpack.common.js:开发和生产环境配置的共享配置
开发环境和生产环境的区别
- 生产环境可能需要分离CSS成单独文件,以便多个页面共享同一个CSS文件
- 生产环境需要压缩 HTML/CSS/JS 代码
- 开发环境需要 SourceMap 文件方便调试
- 开发环境需要HMR、devServer等功能
- ...... 总的来说:开发环境帮助我们快速开发测试联调,生产环境保证上线环境的打包流程是最优化体验。
安装 webpack-merge
npm i webpack-merge -D // 用于连接数组,合并对象,如下所示:
merge(
{a : [1],b:5,c:20},
{a : [2],b:10, d: 421}
)
//合并后结果
{a : [1,2] ,b :10 , c : 20, d : 421}
引入webpack-merge,按照说明的描述拆分文件,配置很简单,可参考项目文件。
mode
mode 选项用于告知 webpack 使用相应模式的内置优化。可选 development, production 或 none
。通常开发环境使用 development,生产环境使用 production。
module.exports = {
mode: 'development',
};
环境变量
使用 cross-env,跨操作系统设置 node 环境变量。
npm i cross-env -D
"scripts": {
"dev": "cross-env NODE_ENV=development webpack serve --config webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.prod.js"
},
sourcemap
sourcemap 产生的文件映射了压缩后的代码所对应的转换前的源代码位置,解决了代码压缩后难以调试的问题。 具体可参照文档,根据需要配置参数值,不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
// webpack.dev.js
devtool: 'eval-cheap-module-source-map',
// webpack.prod.js
devtool: 'cheap-module-source-map',
第四部分:webpack基础共享配置
目标:完善 webpack.common.js
使用 Babel
npm i babel-loader -D // 相当于连接webpack和babel的桥梁,并不会转换js代码
在 webpack.base.js 的 rules 中新增一条规则。排除 node_modules 文件夹,因为 NPM 引入的工具库已经经过编译,不需要再重复编译,影响打包速度。
// webpack.base.js
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}
CSS样式相关配置
在第一部分,我们已经安装配置过了css-loader 和 style-loader,使得Webpack可以识别css语法,并将css代码以style标签的形式插入到HTML文件当中,现在我们来进一步完善这一部分的配置。
1. css-loader 的 importLoaders
官方解释:用于配置 css-loader 作用于 @import 的资源之前有多少个 loader。 举个例子: 首先假设我们有两个文件:style.css和body.css。style.css中通过@import 'body.css';引入body.css:
/* style.css */
@import 'body.css';
.style-div {
display: flex;
}
/* body.css */
.body-import {
/* body import */
display: flex;
}
测试用的 webpack 配置项如下
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1 // 另一份配置不使用importLoaders
}
},
'postcss-loader'
]
}
]
之后我们来对比一下,开启了importLoaders=1 与未开启 importLoaders 的打包结果
/* 未开启importLoaders */
.body-import {
/* body import */
display: flex;
}
.style-div {
display: -ms-flexbox;
display: flex;
}
--------------------------------------------------------
/* 开启importLoaders=1 */
.body-import {
/* body import */
display: -ms-flexbox;
display: flex;
}
.style-div {
display: -ms-flexbox;
display: flex;
}
通过对比可以发现
- 未使用 importLoaders 的 body.css 内的display: flex; 没有自动添加前缀,说明 Postcss 没有作用到@import引入的文件中;
- 使用了importLoaders=1 的 body.css 内的 display: flex; 添加了前缀,说明 Postcss 作用到了被 @import引入的文件中。
- 所以基于项目需要,我们需要使用 importLoaders,确保 css-loader 之后的 loader 会正常作用。
2. CSS预处理器
预处理器可以提升开发效率和体验。在我的项目里使用 Sass 作为预处理器。
node-sass 已经不再维护,改用官方推荐的 dart-sass,直接安装 sass-loader 和依赖的 sass 即可。
npm i sass sass-loader -D // sass-loader只是将 Sass语法编译成 CSS,后续还需要使用 css-loader 和 style-loader配合使用
module.exports = {
// ...
module: {
rules: [
{
test: /\.sass$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
'sass-loader'
]
}
]
}
};
3. PostCSS 和 autoprefixer
PostCSS 能将 CSS 解析成 AST,然后通过各种插件做各种转换,最终生成处理后的新 CSS,跟 Babel 在功能和实现上都类似。我们这里安装 PostCSS,并使用 autoprefixer 实现自动添加浏览器前缀的功能。
npm i postcss-loader postcss autoprefixer -D
module: {
rules: [
{
test: /\.sass$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}
]
}
在根目录创建 postcss.config.js 和 .browserslistrc 文件来使用 autoprefixer 。
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
// .browserslistrc
> 1%
not ie <=8
//原始样式
display: flex;
// 自动添加浏览器前缀
display: -webkt-box;
dispaly: -ms-flexbox;
display: flex;
4. sass-resources-loader
将 Sass 的 变量、Mixin、Function
自动引入各个 Sass 文件中,未使用的 Mixin 和 Function 在打包后不会编译成 CSS,所以不用担心体积问题。
npm i sass-resources-loader -D
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
},
},
'sass-loader',
'postcss-loader',
{ loader: 'sass-resources-loader',
options: {
resources: [
'src/style/tools/index.scss', // 引入 mixins 和 functions 的文件
'src/style/settings/var.scss', // 引入全局 SasS 变量的文件
]
}
}
],
},
使用 vue-cli 生成的项目,在 vue.config.js 文件中添加配置。参考文档:vue-cli官方文档 的‘向预处理器Loader传递选项’
module.exports = {
css: {
loaderOptions: {
scss: {
prependData: `@import "@/style/tools/index.scss";@import "@/style/settings/var.scss";`
},
}
}
}
管理静态资源
1. 资源模块类型
Webpack 本身并不识别图片等静态资源,这时候就需要借助 loader 的力量,在 Webpack5 之前有两个常用 loader:file-loader 和 url-loader
file-loader
:能够根据配置项复制使用到的资源(不局限于图片)到构建之后的文件夹,并且能够更改对应的链接;url-loader
:包含 file-loader 的全部功能,并且能够根据配置将符合配置的文件转换成 Base64 方式引入,将小体积的图片 Base64 引入项目可以减少 http 请求,是一个前端常用的优化方式。
Webpack v5 新增了资源模块类型的配置,来使用资源文件,并且无需配置额外的loader。
asset/resource
发送一个单独的文件并导出 URL,之前通过 file-loader 实现asset/inline
导出一个资源的data URL,之前通过 url-loader 实现asset/source
导出一个资源的源代码,之前通过 raw-loader 实现asset
导出一个data URL和发送一个单独的文件之间自动选择,之前通过 url-loader,并配置资源体积限制实现。
{
test: /\.(png|svg|jpg|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
}
2. html-loader
HTML 中使用引入图片等静态资源的时候,需要添加 html-loader 配置,不然不会处理静态资源的路径问题。
npm i html-loader -D // 将 HTML 导出为字符串。可以压缩 HTML 字符串。
{
test: /\.html$/,
use: ['html-loader']
},
3. image-webpack-loader
借助 image-webpack-loader
可以对使用到的图片进行优化。它支持 JPG、PNG、GIF 和 SVG 格式的图片,该 loader 不能嵌入图片,需要配置enforce: 'pre'保证在嵌入图片之前执行
npm i image-webpack-loader -D
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'image-webpack-loader',
enforce: 'pre'
}
4. 字体、富媒体
这类资源不需要打包成base64
{
test: /\.(eot|woff|ttf|woff2|appcache|mp4|pdf)(\?|$)/,
type: 'asset/resource'
}
缩小查找范围
1. oneOf
原本的规则匹配,会将每个规则都匹配一遍,使用 oneOf 表示唯一匹配,命中了一条规则就结束,可以提高 loader 的执行效率。
rules: [
{
oneOf: [
{
test: /\.css$/,
use: [...],
},
{
test: /\.scss$/,
use: [...],
},
{
test: /\.html$/,
use:[...]
},
....
],
},
],
2. alias
配置别名可以加快搜索速度
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
}
3. extensions
指定 extensions 之后,使用require 和 import 的时候就不需要加文件扩展名了,查找的时候会依次匹配,但同一个目录有不同类型的同名文件时,也只会匹配第一个。
module.exports = {
resolve: {
extensions: ['.vue','.js','.json','scss','css'],
},
}
4. modules
指定第三方依赖的存放目录,默认为'node_modules'
module.exports = {
resolve: {
modules: [
path.resolve(__dirname, '../../node_modules'),
'node_modules'
]
}
}
第五部分:webpack开发环境配置
安装 portfinder
npm i portfinder -D // 自动获取可用端口,避免端口被占用
// //webpack.dev.js
const path = require('path');
const { merge } = require('webpack-merge');
const commonWebpackConfig = require('./webpack.common');
const portfinder = require('portfinder');
const devConfig = {
// 开发环境的 webpack 配置项
};
const devWebpackConfig = merge(commonWebpackConfig, devConfig);
module.exports = new Promise((resolve, reject) => {
portfinder.getPort({
port: 1081, // 默认1081端口,若被占用,重复+1,直到找到可用端口或到stopPort才停止
stopPort: 65535, // maximum port
},(err, port) => {
if(err) {
reject(err)
return
}
devWebpackConfig.devServer.port = port
resolve(devWebpackConfig);
});
})
缓存
1. cache
缓存之前打包的内容,配置之后会生成一个.cash文件夹,通过文件缓存,直接缓存到本机磁盘
// //webpack.dev.js
cache: {
type: 'filesystem', //默认缓存到 node_modules/.cache/webpack。还可以使用 cacheDirectory选项自定义配置
},
2. babel-loader
babel-loader 自带缓存配置。开启后会将缓存放在node_modules/.cache/babel-loader
// //webpack.dev.js
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}
3. cache-loader
使用此loader,可以将其他 loader 的结果缓存到磁盘中,默认路径node_modules/.cache/cache-loader
npm i cache-loader -D
{
test: /\.css$/,
use: [
'cache-loader',
'style-loader',
'css-loader'
],
},
第六部分:webpack生产环境配置
单独提取CSS
在生产环境 CSS 文件应该是单独导出的,这时候就需要 mini-css-extract-plugin
npm i mini-css-extract-plugin -D //将 CSS 提取到单独文件
mini-css-extract-plugin 使用的时候需要分别配置 loader 和 plugin,loader 需要放在css-loader 之后代替 style-loader
// webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].[contenthash:8].css'
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: false
}
},
'css-loader'
]
}
]
}
};
Tree Shaking
webpack5 有更好的 Tree Shaking 处理机制,mode 为 production 时默认开启,也可以手动配置开启。
// webpack.prod.js
optimization {
usedExports: true,
minimize: true
// 还有更多配置...
}
// package.json
"sideEffects": [
"*.css" // 也可以设置某些文件不 Tree Shaking
]
Scope Hoisting
作用域提升,把几个函数合并成一个函数,减少执行每个新函数,产生的临时执行上下文,减少开销,mode 为 production 时默认开启。
压缩
JS 压缩
如果你使用的是 webpack 5 或以上版本,不需要安装这个插件。webpack 5 自带最新的 terser-webpack-plugin,并在mode 为 'production' 时自动使用。
npm i terser-webpack-plugin -D
// // webpack.prod.js
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
};
HTML 压缩
1. html-webpack-plugin 的 minify
html-webpack-plugin
的 minify
选项用于设置html文件的压缩,如果 mode 为 'production' 则会自动开启 minify。并使用 html-minifier-terser
进行压缩,默认配置如下,可参考 html-minifier-terser 的文档按需修改:
{
collapseWhitespace: true,
keepClosingSlash: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
2. html-minimizer-webpack-plugin
内部同样使用 html-minifier-terser
来压缩 HTML。webpack5 开始,像压缩类的插件,应该配置在 optimization.minimizer 数组中,方便统一管理。插件使用方式可以参考官方文档。
npm i html-minimizer-webpack-plugin -D
// webpack.prod.js
const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin");
optimization: {
minimize: true,
minimizer: [
// For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`,
new HtmlMinimizerPlugin(),
],
},
CSS 压缩
在 Webpack5 之前,通常使用 optimize-css-assets-webpack-plugin
这个插件来压缩 CSS 代码。但在其 NPM库,有一段话“For webpack v5 or above please use css-minimizer-webpack-plugin instead.”
所以,按照 css-minimizer-webpack-plugin
的文档,配置 Webpack 的optimization.minimize 即可开启css压缩。
npm i css-minimizer-webpack-plugin -D
// webpack.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: { // 告知 webpack 使用 TerserPlugin 或其它在 optimization.minimizer 定义的插件压缩 bundle。
minimizer: [
// `...`, // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
new CssMinimizerPlugin(),
],
},
};
拆分代码
splitChunks
在配置 splitChunks 之前,先来简单了解一下 module、chunk、bundle的概念
module
:通过 import、require 语句引入的各类资源。chunk
:chunk 包含一个或多个 module,根据 webpack 的配置拆分出来,例如 splitChunks 就可以拆分出额外的 chunk。bundle
:对 chunk 打包压缩之后的最终文件,一般和 chunk 是一对一的关系,也可能会有多个chunk 中的公共部分被组合到一个bundle。 Webpack4 开始,用于处理公共模块的 splitChunks 功能是开箱即用的,默认配置如下:
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'async', // "initial" | "all" | "async" ,默认async
minSize: 20000, // 20K,当超过这个体积就会被抽离成公共部分。
minRemainingSize: 0, // 确保拆分后剩余的最小 chunk 体积超过限制来避免大小为零的模块。
minChunks: 1, // 拆分前必须共享模块的最小 chunks 数。
maxAsyncRequests: 30, // 按需加载时的最大并行请求数。例如 import('./page.js'),则引入page.js时,算上page.js本身在内的最大请求数量限制为30个。
maxInitialRequests: 30, // entry入口的最大并行请求数。入口文件本身算一个请求,入口文件内的动态加载模块不计算请求数。
enforceSizeThreshold: 50000, // 强制执行拆分的体积阈值和其他限制(minRemainingSize,maxAsyncRequests,maxInitialRequests)将被忽略。
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/, // 符合规则则提取 chunk
priority: -10 // 优先级,当一个模块属于多个 chunkGroup,权重值高的优先
reuseExistingChunk: true, // 如果该chunk包含的modules都已经另一个被分割的chunk中存在,那么直接引用已存在的chunk,不会再重新产生一个
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
}
}
}
}
};
在实际项目中,通过 webpack-bundle-analyzer
等 bundle 分析工具,可以分析并将体积过大的公共模块拆分出来。例如发现下图的 moment 包过大,就可以添加配置,拆分出来(当然也可以使用体积更小的 day.js 或者使用 moment-locales-webpack-plugin 插件缩小 moment 体积)。
// webpack.prod.js
optimization: {
splitChunks: {
cacheGroups: {
moment: {
test: /[\\/]node_modules[\\/]_moment@2.29.1@moment[\\/]/,
name: 'moment',
chunks: 'all',
},
},
},
},
如果使用了 html-webpack-plugin
,需要添加 chunks 配置来自动引入拆分出的 chunk。
new HtmlWebpackPlugin({
// ...
chunks: ['moment','main'],
}),
最后
好了,以上就是本篇文章的全部内容了,还有许多常用配置和 Webpack5 新特性没有使用到,提供的选项也存在很大的封装优化空间,当然你也可以编写自己的 loader 和 plugin 来解决遇到的实际问题。本文仅作为学习记录,起一个抛砖引玉的作用,希望文中内容能你有所帮助,谢谢。
转载自:https://juejin.cn/post/6978832288586924046