- 入口(entry)
声明项目入口文件。支持字符串,对象,函数,数组形式来配置。
module.exports = {
entry: {
// 字符串形态
home: './home.js',
// 数组形态
shared: ['react', 'react-dom', 'redux', 'react-redux'],
// 对象形态
personal: {
import: './personal.js',
filename: 'pages/personal.js',
dependOn: 'shared',
chunkLoading: 'jsonp',
asyncChunks: true
},
// 函数形态
admin: function() {
return './admin.js';
}
},
};
对象形式支持如下配置属性
import:声明入口文件,支持路径字符串或路径数组(多入口)
dependOn:当前入口所依赖的入口。它们必须在该入口被加载前被加载
runtime:设置该入口的 Runtime Chunk,若该属性不为空,Webpack 会将该入口的运行时代码抽离成单独的 Bundle
filename:效果与 output.filename 类同,用于声明该模块编译结果路径
library:声明该入口的 output.library 配置,一般在编译 NPM Library 时使用
publicPath:效果与 output.publicPath 相同,用于声明该入口文件的发布 URL
// 加载foo之前先加载main,可以将重复的模块代码、运行时代码等都放到main中
module.exports = {
// ...
entry: {
main: "./src/index.js",
foo: { import: "./src/foo.js", dependOn: "main" },
},
};
// main与foo入口的运行时代码都抽取出来,放在common-runtime的Bundle中
const path = require("path");
module.exports = {
mode: "development",
devtool: false,
entry: {
main: { import: "./src/index.js", runtime: "common-runtime" },
foo: { import: "./src/foo.js", runtime: "common-runtime" },
},
output: {
clean: true,
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
},
};
- 输出(output)
声明编译结果的存放位置。
output.path:声明编译结果放在什么文件目录下
output.filename:声明编译结果文件名规则,支持 [name]/[hash] 等占位符
output.publicPath:文件发布路径,在 Web 应用中使用率较高
output.clean:是否自动清除 path 目录下的内容,调试时特别好用
output.library:NPM Library 形态下的一些产物特性,例如:Library 名称、模块化(UMD/CMD 等)规范
output.chunkLoading:声明加载异步模块的技术方案,支持 false/jsonp/require 等方式
多数情况下只需要使用 path/filename/publicPath 即可满足需求。
- 编译目标(target)
用于配置编译目标的运行环境。
虽然多数时候 Webpack 都被用于打包 Web 应用,但实际上 Webpack 还支持构建 Node、Electron、NW.js、WebWorker 等应用形态,这一特性主要通过 target 配置控制,支持如下数值:
web:构建为 Web 应用。
node[[X].Y]:编译为 Node 应用,此时将使用 Node 的 require 方法加载其它 Chunk,支持指定 Node 版本,如:node12.13。
- 编译模式(mode)
支持 development/production/none 三种值
production:默认值,生产模式,使用该值时 Webpack 会自动帮我们开启一系列优化措施:Three-Shaking、Terser 压缩代码、SplitChunk 提起公共代码,通常用于生产环境构建。
development:开发模式,使用该值时 Webpack 会保留更语义化的 Module 与 Chunk 名称,更有助于调试,通常用于开发环境构建。
none:关闭所有内置优化规则。
- 加载器(loader)
常用的加载器:
压缩图片:image-webpack-loader
使用 Babel:@babel/core @babel/preset-env babel-loader
使用 TypeScript:ts-loader
处理CSS:css-loader style-loader mini-css-extract-plugin
处理Less:css-loader style-loader less-loader
- 插件(plugin)
常用的插件:
使用 ESLint:eslint-webpack-plugin
- resolve
配置模块路径解析规则
- externals
声明外部资源,Webpack 会直接忽略这部分资源,跳过这些资源的解析、打包操作。
- optimization
控制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混淆、代码压缩等功能。
- 图片处理
- file-loader 等同于 type = "asset/resource"
module.exports = {
module: {
rules: [{
test: /\.(png|jpg)$/,
type: 'asset/resource'
}],
},
};
asset/resource 生成的文件会以 [hash][ext][query] 方式重命名并复制到编译目录下,同时在代码中插入文件 URL 地址。
- url-loader 等同于 type = "asset" 或 type = "asset/inline"
module.exports = {
module: {
rules: [{
test: /\.(png|jpg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 1024 // 限定文件大小 1kb
}
}
}],
},
};
对于小于 parser.dataUrlCondition 的图像直接转化为 base64 编码,大于 parser.dataUrlCondition 的图像则调用 file-loader 进行加载。
- raw-loader 等同于 type = "asset/source"
module.exports = {
module: {
rules: [
{
test: /\.svg$/i,
type: "asset/source"
},
],
},
};
将文件内容复制到编译目录中,适用于 SVG 场景。
- 图像压缩
yarn add -D image-webpack-loader
module.exports = {
module: {
rules: [{
test: /\.(gif|png|jpe?g|svg)$/i,
type: "asset/resource",
use: [{
loader: 'image-webpack-loader',
options: {
// jpeg 压缩配置
mozjpeg: {
quality: 80
},
}
}]
}],
},
};
mozjpeg:用于压缩 JPG(JPEG) 图片
optipng:用于压缩 PNG 图片
pngquant:同样用于压缩 PNG 图片
svgo:用于压缩 SVG 图片
gifsicle:用于压缩 Gif 图
webp:用于将 JPG/PNG 图压缩并转化为 WebP 图片格式
- 使用 Babel
能将高版本如 ES6 代码等价转译为向后兼容,能直接在旧版 JavaScript 引擎运行的低版本代码。
npm i -D @babel/core @babel/preset-env babel-loader
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
],
},
],
},
};
- 使用 TypeScript
npm i -D ts-loader
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader'
},
],
},
resolve: {
extensions: ['.ts', '.js'],
}
};
- 使用 ESLint
yarn add -D eslint-webpack-plugin
const ESLintPlugin = require('eslint-webpack-plugin')
module.exports = {
plugins: [new ESLintPlugin()]
}
- 处理CSS
css-loader:和处理 JS 代码一样解析 CSS 内容与资源依赖
style-loader:将 CSS 内容注入到页面的 style 标签,使得样式生效
mini-css-extract-plugin:将 CSS 代码抽离到单独的 .css 文件,并将文件通过 link 标签方式插入到页面中
yarn add -D style-loader css-loader
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
yarn add -D mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: [
// 根据运行环境判断使用那个 loader
// 生产环境用 mini-css-extract-plugin
// 测试环境用 style-loader
(process.env.NODE_ENV === 'development' ?
'style-loader' :
MiniCssExtractPlugin.loader),
'css-loader'
]
}]
},
plugins: [
new MiniCssExtractPlugin(),
new HTMLWebpackPlugin()
]
}
- 使用 Less
yarn add -D less-loader
module.exports = {
module: {
rules: [{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}]
}
}
- 配置结构
- 单个配置对象
module.exports = {
entry: './src/index.js',
// 其它配置...
};
- 配置对象数组
每个数组项都是一个完整的配置对象,每个对象都会触发一次单独的构建,通常用于需要为同一份代码构建多种产物的场景,例如在构建 Library 时,我们通常需要同时构建出 ESM/CMD/UMD 等模块方案的产物。
可以将公共配置抽取为 baseConfig 对象,之后配合 webpack-merge 创建不同目标数组项。
// yarn add -D webpack-merge
const { merge } = require("webpack-merge");
const baseConfig = {
output: {
path: "./dist"
},
name: "amd",
entry: "./app.js",
mode: "production",
};
module.exports = [
merge(baseConfig, {
output: {
filename: "[name]-amd.js",
libraryTarget: "amd",
},
}),
merge(baseConfig, {
output: {
filename: "./[name]-commonjs.js",
libraryTarget: "commonjs",
},
}),
];
若是"多份代码打包多份产物"的场景,则建议使用 entry 配置多个应用入口。
- 函数
函数根据环境参数动态调整配置对象,Webpack 启动时会执行该函数获取参数,函数返回 Webpack 配置对象,或配置数组,或 Promise 对象。
运行时 Webpack 会传入两个环境参数对象env和argv:
- env:通过 --env 传递的命令行参数,适用于自定义参数
| 命令 | env 参数值 |
|---|---|
| npx webpack --env prod | { prod: true } |
| npx webpack --env platform=app --env production | { platform: "app", production: true } |
| npx webpack --env app.platform="staging" --env app.name="test" | { app: { platform: "staging", name: "test" } |
- argv:命令行 Flags 参数,支持 entry/output-path/mode/merge 等。
// 通过命令行传入 env.app.type 与 argv.mode 值
// npx webpack --env app.type=miniapp --mode=production
module.exports = function (env, argv) {
return {
mode: argv.mode ? "production" : "development",
devtool: argv.mode ? "source-map" : "eval",
output: {
path: path.join(__dirname, `./dist/${env.app.type}`,
filename: '[name].js'
},
plugins: [
new TerserPlugin({
terserOptions: {
compress: argv.mode === "production",
},
}),
],
};
};
用户根据命令行参数动态创建配置对象,实现简单的多环境部署策略。
- 环境部署策略
将同一个应用部署在不同环境(如生产环境、开发环境、测试环境)中。通常会将部分通用配置放在基础文件中,其它不同环境的配置文件引入该模块并使用 webpack-merge 合并配置对象。
// webpack.common.js
const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: { main: "./src/index.js" },
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.js$/,
use: ["babel-loader"],
},
],
},
plugins: [new HTMLWebpackPlugin()],
};
// yarn add -D webpack-merge
// webpack.development.js
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.common");
// 使用 webpack-merge 合并配置对象
module.exports = merge(baseConfig, {
mode: "development",
devtool: "source-map",
devServer: { hot: true },
});
// 执行构建命令
npx webpack --config=webpack.development.js