此webpack配置,针对未webpack5,可参考网址 webpack.docschina.org/concepts/
基本配置
- entry(入口) 指示 Webpack 从哪个文件开始打包
- output(输出) 指示 Webpack 打包完的文件输出到哪里去,如何命名等
- module(加载器)webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader 才能解析
- plugins(插件)扩展 Webpack 的功能
- mode(模式)development/production
// /** @type {import('webpack').Configuration} */可提示webpack配置
/** @type {import('webpack').Configuration} */
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
//__dirname nodejs的变量,代表当前文件的文件夹目录
path: path.resolve(__dirname, 'dist'),//绝对路径
//文件名
filename: 'main.js'
},
module: {
rules: [
{
test: /\.css$/, // 只检测.css文件
use: [
//use倒序执行,先执行 'css-loader' ,再执行'style-loader'
'style-loader', // 将js中的css通过创建style标签添加到html文件中的生效
'css-loader'//将css资源编译成commonjs的模块到js中
]
}
]
},
plugins: [],
mode: 'development'
}
处理样式资源
处理样式资源主要是对样式进行编译处理,对浏览器做兼容。
- 下载loader处理器
npm i css-loader style-loader -D
css-loader:负责将 Css 文件编译成 Webpack 能识别的模块
style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容。
注意:在生产模式下需要将 css 单独打包,可以避免闪屏现象 - css兼容处理
npm i postcss-loader postcss postcss-preset-env -D 在package.json文件加配置 "browserslist": ["ie >= 8"] // 兼容到指定浏览器版本 "browserslist": ["last 2 version", "> 1%", "not dead"] //推荐使用 - css压缩
npm install css-minimizer-webpack-plugin --save-dev const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); plugins: [new MiniCssExtractPlugin()],// production模式 // CSS单独打包,避免闪屏现象 const MiniCssExtractPlugin = require("mini-css-extract-plugin") { test: /\.less$/, use: [ MiniCssExtractPlugin.loader, // CSS单独打包 "css-loader", //将css资源编译成commonjs的模块到js中 { // css兼容 loader: "postcss-loader", options: { postcssOptions: { plugins: [ "postcss-preset-env", // 能解决大多数样式兼容性问题 ], }, }, }, "less-loader" ], }, 在package.json文件加配置 "browserslist": ["ie >= 8"] // 兼容到指定浏览器版本 "browserslist": ["last 2 version", "> 1%", "not dead"] //推荐使用
处理图片、字体图标资源
过去在 Webpack4 时,我们处理图片资源通过 file-loader 和 url-loader 进行处理。 现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源,详情可以参考官网webpack.docschina.org/guides/asse…
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理 ,优点:减少请求数量,缺点:体积变得更大
}
},
// 资源发送到指定目录 Rule.generator.filename 与 output.assetModuleFilename 相同,并且仅适用于 asset 和 asset/resource 模块类型。
generator: {
//[hash:10] hash值只取前10位
filename: 'static/images/[hash:10][ext][query]'
}
}
处理字体图标资源
{
test: /\.(ttf|woff2?)$/,
// type: "asset/resource" 相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理
// type: "asset" 相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
处理html资源
使用html-webpack-plugin处理html,该插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。
npm i html-webpack-plugin -D
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins: [
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "public/index.html"),
}),
],
开发服务器自动化
webpack-dev-server 为你提供了一个基本的 web server,并且具有 live reloading(实时重新加载) 功能。
npm i webpack-dev-server -D
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
}
优化
- 提升开发体验
- 提升打包构建速度
- 减少代码体积
- 优化代码运行性能
提升开发体验
当 webpack 打包源代码时,可能会很难追踪到 error(错误) 和 warning(警告) 在源代码中的原始位置。例如,如果将三个源文件(a.js, b.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会直接指向到 bundle.js。你可能需要准确地知道错误来自于哪个源文件,所以这种提示这通常不会提供太多帮助。
为了更容易地追踪 error 和 warning,JavaScript 提供了 source maps 功能,可以将编译后的代码映射回原始源代码。如果一个错误来自于 b.js,source map 就会明确的告诉你。
SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。
它会生成一个 xxx.map 文件,里面包含源代码和构建后代码每一行、每一列的映射关系。当构建后代码出错了,会通过 xxx.map 文件,从构建后代码出错位置找到映射后源代码出错位置,从而让浏览器提示源代码文件出错位置,帮助我们更快的找到错误根源。
开发模式:cheap-module-source-map ,
优点:打包编译速度快,只包含行映射;
缺点:没有列映射。
生产模式:source-map ,
优点:包含行/列映射;
缺点:打包编译速度更慢。
module.exports = {
// 其他省略
mode: "development",
devtool: "cheap-module-source-map",
};
module.exports = {
// 其他省略
mode: "production",
devtool: "source-map",
};
提升打包速度
模块热替换
开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。
模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新。
从 webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。
HMR 加载样式
借助于 style-loader,使用模块热替换来加载 CSS 实际上极其简单。此 loader 在幕后使用了 module.hot.accept,在 CSS 依赖模块更新之后,会将其 patch(修补) 到 <style> 标签中。
HMR 处理js
在入口文件需要对需要进行热加载的每一个模块进行配置module.hot.accept,实际开发我们会使用其他 loader 来解决。 比如:vue-loader ,react-hot-loader
// 判断是否支持HMR功能
if (module.hot) {
module.hot.accept("./js/count.js", function (count) {
const result1 = count(2, 1);
console.log(result1);
});
module.hot.accept("./js/sum.js", function (sum) {
const result2 = sum(1, 2, 3, 4);
console.log(result2);
});
}
oneOf
打包时每个文件都会经过所有 loader 处理,虽然因为 test 正则原因实际没有处理上,但是都要过一遍,比较慢。
oneOf 规则数组,当规则匹配时,只使用第一个匹配规则。可以提高打包速度
module: {
rules: [
{
oneOf: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
],
},
Include/Exclude
开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。而这些文件是不需要编译可以直接使用的。所以我们在对 js 文件处理时,要排除 node_modules 下面的文件。
include:包含,只处理 xxx 文件
exclude:排除,除了 xxx 文件以外其他文件都处理
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "src"), // 也可以用包含
loader: "babel-loader",
},
babel缓存
每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了
缓存目录:node_modules/.cache
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩,提高开发速度,压缩会影响打包速度
}
},
threads 多进程打包
当项目越来越庞大时,打包速度越来越慢,我们想要继续提升打包速度,其实就是要提升 js (体积最大)的打包速度,而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具
多进程打包:开启电脑的多个进程同时干一件事,速度更快。
需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销
// nodejs核心模块,直接使用
const os = require("os");
// 获取cpu核数
const threads = os.cpus().length;
// 压缩js
const TerserPlugin = require("terser-webpack-plugin");
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
use:[
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩,提高开发速度,压缩会影响打包速度
}
}
]
},
optimization: {
minimize: true,
minimizer: [
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads // 开启多进程
})
],
},
减少代码体积
babel
Babel 为编译的每个文件都插入了辅助代码,使代码体积过大!
Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。
你可以将这些辅助代码作为一个独立模块,来避免重复引入。
npm i @babel/plugin-transform-runtime -D
{
test: /.js$/,
include: path.resolve(__dirname, "../src"), // 也可以用包含
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
},
},
],
},
优化代码运行性能
代码分割
打包代码时会将所有 js 文件打包到一个文件中,体积太大了。我们如果只要渲染首页,就应该只加载首页的 js 文件,其他文件不应该加载。所以我们需要将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。
- 分割文件:将打包生成的文件进行分割,生成多个 js 文件。
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割
// 以下是默认值
// minSize: 20000, // 分割代码最小的大小
// minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
// minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
// maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
// maxInitialRequests: 30, // 入口js文件最大并行请求数量
// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// cacheGroups: { // 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
// default: { // 其他没有写的配置会使用上面的默认值
// minChunks: 2, // 这里的minChunks权重更大
// priority: -20,
// reuseExistingChunk: true,
// },
// },
// 修改配置
cacheGroups: {
// 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
default: {
// 其他没有写的配置会使用上面的默认值
minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
// 一般直接设置chunks: "all",
optimization:{
splitChunks:{
chunks: "all"
}
}
- 按需加载:需要哪个文件就加载哪个文件。
document.getElementById('btn').onclick = function () {
// 动态导入 --> 实现按需加载
// 即使只被引用了一次,也会代码分割
///* webpackChunkName:"sum" */ 这是webpack动态导入模块命名的方式
//"sum"将来会座位 [name] 的值显示
import(/* webpackChunkName:"sum" */'./js/sum').then(res => {
console.log(res, res.default(2, 2))
}).catch(err => {
console.log(err, 'err')
})
}
npm i eslint-plugin-import babel-eslint -D
// 此处要注意babel-eslint的版本问题,出错就降版本
output:{
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
}
// .eslintrc.js
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
plugins: ["import"], // 解决动态导入import语法报错问题 --> 实际使用eslint-plugin-import的规则解决的
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
};
Preload / Prefetch
- Preload:告诉浏览器立即加载资源。
- Prefetch:告诉浏览器在空闲时才开始加载资源。
它们共同点:
- 都只会加载资源,并不执行。
- 都有缓存。
它们区别:
- Preload加载优先级高,Prefetch加载优先级低。
- Preload只能加载当前页面需要使用的资源,Prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源。
总结:
- 当前页面优先级高的资源用 Preload 加载。
- 下一个页面需要使用的资源用 Prefetch 加载。
浏览器兼容不好,谨慎使用
npm i @vue/preload-webpack-plugin -D
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
plugins: [
new PreloadWebpackPlugin({
rel: "preload", // preload兼容性更好
as: "script",
// rel: 'prefetch' // prefetch兼容性更差,prefetch没有as配置
}),
],
Network Cache(runtimeChunk)
将来开发时我们对静态资源会使用缓存来优化,这样浏览器第二次请求资源就能读取缓存了,速度很快。但是这样的话就会有一个问题, 因为前后输出的文件名是一样的,都叫 main.js,一旦将来发布新版本,因为文件名没有变化导致浏览器会直接读取缓存,不会加载新资源,项目也就没法更新了。所以我们从文件名入手,确保更新前后文件名不一样,这样就可以做缓存了。
- fullhash(webpack4 是 hash) 每次修改任何一个文件,所有文件名的 hash 至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。
- chunkhash 根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们 js 和 css 是同一个引入,会共享一个 hash 值。
- contenthash 根据文件内容生成 hash 值,只有文件内容变化了,hash 值才会变化。所有文件 hash 值是独享且不同的。
- 问题: 当我们修改 math.js 文件再重新打包的时候,因为 contenthash 原因,math.js 文件 hash 值发生了变化(这是正常的)。但是 main.js 文件的 hash 值也发生了变化,这会导致 main.js 的缓存失效。明明我们只修改 math.js, 为什么 main.js 也会变身变化呢?
- 原因:
- 更新前:math.xxx.js, main.js 引用的 math.xxx.js
- 更新后:math.yyy.js, main.js 引用的 math.yyy.js, 文件名发生了变化,间接导致 main.js 也发生了变化
- 解决: 将 hash 值单独保管在一个 runtime 文件中。 我们最终输出三个文件:main、math、runtime。当 math 文件发送变化,变化的是 math 和 runtime 文件,main 不变。 runtime 文件只保存文件的 hash 值和它们与文件关系,整个文件体积就比较小,所以变化重新请求的代价也小。
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
// [contenthash:8]使用contenthash,取8位长度
filename: "static/js/[name].[contenthash:8].js", // 入口文件打包输出资源命名方式
chunkFilename: "static/js/[name].[contenthash:8].chunk.js", // 动态导入输出资源命名方式
assetModuleFilename: "static/media/[name].[hash][ext]", // 图片、字体等资源命名方式(注意用hash)
clean: true,
},
module: {},
plugins: [
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
}),
],
optimization: {
// 提取runtime文件
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`, // runtime文件命名规则
},
},
};
Core-js
过去我们使用 babel 对 js 代码进行了兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
它能将 ES6 的一些语法进行编译转换,比如箭头函数、点点点运算符等。但是如果是 async 函数、promise 对象、数组的一些方法(includes)等,它没办法处理。
所以此时我们 js 代码仍然存在兼容性问题,一旦遇到低版本浏览器会直接报错。
core-js是专门用来做 ES6 以及以上 API 的 polyfill
// babel.config.js
module.exports = {
// 智能预设:能够编译ES6语法
presets: [
[
"@babel/preset-env",
// 按需加载core-js的polyfill
{ useBuiltIns: "usage", corejs: { version: "3", proposals: true } },
],
],
};
// webpack.prod.js
const path = require("path")
const ESLintWebpackPlugin = require("eslint-webpack-plugin")
// index.html自动引入打包子资源
const HtmlWebpackPlugin = require("html-webpack-plugin")
// 把css样式从js文件中提取到单独的css文件中
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// css压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
// 剔除没有使用的冗余代码
const TerserPlugin = require("terser-webpack-plugin")
// 图片压缩
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin")
// preload/prefetch预加载
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin")
// nodejs核心模块,直接使用
const os = require("os")
// cpu核数
const threads = os.cpus().length
// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
preProcessor,
].filter(Boolean)
}
// 渐进式网络应用程序
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"), // 生产模式需要输出
// [contenthash:8]使用contenthash,取8位长度
filename: "static/js/[name].[contenthash:8].js", // 入口文件打包输出资源命名方式
chunkFilename: "static/js/[name].[contenthash:8].chunk.js", // 动态导入输出资源命名方式
assetModuleFilename: "static/media/[name].[hash][ext]", // 图片、字体等资源命名方式(注意用hash)
clean: true,
},
module: {
rules: [
{
oneOf: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleLoaders("stylus-loader"),
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
// generator: {
// // 将图片文件输出到 static/imgs 目录中
// // 将图片文件命名 [hash:8][ext][query]
// // [hash:8]: hash值取8位
// // [ext]: 使用之前的文件扩展名
// // [query]: 添加之前的query参数
// filename: "static/imgs/[hash:8][ext][query]",
// },
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
// generator: {
// filename: "static/media/[hash:8][ext][query]",
// },
},
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "src"), // 也可以用包含
use: [
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
plugins: [ "@babel/plugin-transform-runtime" ], // 减少代码体积
},
},
],
},
],
},
],
},
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"node_modules/.cache/.eslintcache"
),
threads, // 开启多进程
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/[name].[contenthash:8].css",
chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
}),
// css压缩
// new CssMinimizerPlugin(),
new PreloadWebpackPlugin({
rel: "preload", // preload兼容性更好
as: "script",
// rel: 'prefetch' // prefetch兼容性更差
}),
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
],
optimization: {
minimizer: [
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads, // 开启多进程
}),
// 压缩图片
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
[ "gifsicle", { interlaced: true } ],
[ "jpegtran", { progressive: true } ],
[ "optipng", { optimizationLevel: 5 } ],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割
// 其他内容用默认配置即可
},
// 提取runtime文件
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`, // runtime文件命名规则
},
},
mode: "production",
devtool: "source-map",
}