基础配置
模块解析
webpack 内部使用 enhance-resolve 解析文件路径, 通过 resolve 字段可以配置解析策略
配置解析策略
resolve.alias
指定模块的别名, 以简写某些常用模块的路径
- 通常使用
@表示src目录 - 使用
$特殊字符结尾表示精确匹配
配置示例
module.exports = {
// ...others
resolve: {
alias: {
"@": path.resolve(__dirname, "src/"),
"@utils$": path.resolve(__dirname, "src/util/index.js"),
},
},
};使用示例
import Comps from "@/comps";
import utils from "@utils";resolve.extensions
解析未指定扩展名的文件时, 自动解析确定的扩展
- 默认配置
[".js", ".json"](新版的文档中删除了该说明, 可能不准确) - 配置该选项时会覆盖默认配置
- 配置靠前的字段优先级更高
- 使用
*字段可以匹配任意文件扩展名, 不建议使用 - 常用的配置:
['js', 'jsx', 'ts', 'tsx', 'json'] - 不推荐添加非逻辑文件扩展名, 如 'css'
resolve.modules
指定解析模块时搜索的目录, 通常在引用自定义模块时需要修改该配置
- 默认配置为
['node_modules'] - 可以配置多个目录
- 配置靠前的目录优先级更高
配置示例
module.exports = {
// ...
resolve: {
modules: [path.resolve(__dirname, 'my_modules'), 'node_modules]
}
}resolve.mainFields
导入模块时, 指定依据 'package.json' 中哪个字段导入模块, 通常不会修改该配置
- 默认配置为
['module', 'main'] - 配置靠前的字段优先级更高
resolve.mainFiles
解析目录时, 解析目录下默认的文件, 通常不会修改该配置
- 默认配置
['index'] - 配置靠前的字段优先级更高
解析流程
- 解析路径
- 绝对路径
- 场景示例:
import '/my-project/src/resolve/path/some-module - 解析方式: 不处理, 直接使用
- 场景示例:
- 相对路径
- 场景示例:
import '../utils/some/file' - 解析方式: 将引用文件所在目录作为上下文目录, 并将被引用文件路径解析为绝对路径
- 场景示例:
- 模块路径
- 场景示例:
import '@path/some-module'import 'some-module'
- 解析方式
- 若使用路径别名, 则依据
resolve.alias配置进行解析 - 依据
resolve.modules配置中指定的目录进行搜索解析
- 若使用路径别名, 则依据
- 场景示例:
- 绝对路径
- 解析文件
- 若解析路径指向文件
- 指定扩展名: 直接加载指定文件
- 省略扩展名: 依据
resolve.extensions选项解析文件扩展名
- 若解析路径指向目录
- 目录下存在 'package.json' 文件
- 按照 'package.json' 文件中
main字段解析文件 - 若不存在
main字段或解析失败, 则按照resolve.mainFields配置中指定字段依此解析
- 按照 'package.json' 文件中
- 目录下缺少
package.json文件- 按照
resolve.mainFiles配置依此查找文件 - 未配置
resolve.mainFiles则默认查找 'index.js' 文件
- 按照
- 目录下存在 'package.json' 文件
- 若解析路径指向文件
入口配置
webpack 使用 entry 字段指定构建的入口
- 配置格式
entry: string | [string]: 配置单个入口, 使用默认的 chunk 名称entry: { [name: string]: string | [string] }: 配置单个或多个入口, 使用键作为 chunk 名称entry: () => string | [string]: 配置动态入口, 返回一个配置项
- 路径解析
- 入口路径为单一字符串, 则依此路径解析
- 入口路径为字符串数组, 则依此进行解析并打包至一个文件中
- 默认配置
- 默认入口:
./src/index.js - 默认名称:
main
- 默认入口:
- 使用场景
- 单个入口通常用于构建单页面应用、库等
- 多个入口通常用于构建多页面应用, 实现单页面应用长效缓存, 大型单页面应用的拆分等
- 注意事项
- 动态加载模块不是入口起点
- 长效缓存值将修改频率极低的文件单独构建以避免修改文件名称, 从而充分利用浏览器缓存机制的处理方式
示例
module.exports = {
entry: {
shim: ["./src/shim", "./src/extension"], // 作为长效缓存, 对 shim 环境单独构建, 这里假设存在自定义的原生扩展
main: "./src/index", // 构建的主入口
},
};出口配置
webpack 使用 output 字段配置输出的内容, 基本配置有
filename: 指定输出的文件名, 支持占位符模板, 默认'[name].js'path: 指定输出的目录, 需为绝对路径, 默认__dirname + '/dist'
| 占位符(模板) | 说明 |
|---|---|
| [name] | 模块名称,对应 entry 配置中的 chunk 名称 |
| [id] | 模块标识符,每个 chunk 拥有一个唯一的 id 标志 |
| [hash] | 模块标识符的 hash 值 |
| [chunkhash] | chunk 内容的 hash 值 |
示例
const path = require("path");
module.exports = {
// ...
output: {
filename: `[name].[hash].js`,
path: path.resolve(__dirname, "dist"),
},
};其他常用配置有 publicPath, library, libraryTarget, libraryExport 等, 这些配置与具体的使用场景相关, 详见 生产环境 部分
资源管理
webpack 中通过对应的 loader 允许使用 import 导入非 js 文件
配置 loader
webpack 通过 module.rules 属性配置 loader 规则, 该字段接收一个数组, 每一项为一条 loader 规则
示例
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
};规则
每条规则分为三部分: 条件, 结果, 嵌套规则
- 条件: 有两种输入值, 其路径已根据
resolve规则解析- resource: 请求文件的绝对路径, 配置字段有
test,include,exclude和resource - issuer: 导入请求文件的模块的绝对路径, 相关字段为
issuer, 通常不需要配置
- resource: 请求文件的绝对路径, 配置字段有
- 结果: 有两种输入值, 在规则条件匹配时使用
- loader: 应用在 resourve 上的 loader 数组, 配置字段有
loader,options,use,enforce - parser: 用于为模块创建解析器的选项对象, 配置字段为
parser
- loader: 应用在 resourve 上的 loader 数组, 配置字段有
- 嵌套规则: 可以使用
rules和oneOf指定嵌套规则
配置规则条件
条件种类
{ test: Condition }: 匹配特定条件, 该值通常是正则或正则数组{ include: Condition }: 匹配特定条件, 该值通常是字符串或字符串数组{ exclude: Condition }: 排除特定条件, 该值通常是字符串或字符串数组{ and: [Condition] }: 数组中所有条件满足时匹配{ or: [Condition] }: 数组中任一条件满足时匹配{ not: [Condition] }: 排除数组中条件
条件类型
- 字符串: 目录绝对路径或文件绝对路径
- 正则: test 输入值
- 函数: 调用输入的函数, 必须返回一个 truthy
- 条件数组: 至少一个匹配条件
- 对象: 匹配所有属性, 每个属性有一个定义行为
示例
const path = require('path)
module.exports = {
// ...
module: {
rules: [
{
test: /\.jsx?$/,
include: [path.resolve(__dirname, 'src')]
}
]
}
}配置规则结果
use: 指定应用的 loader, 执行顺序为从后向前loader:{ use: [{ loader }] }的简写options: 配置 loader 中的选项enforce: 指定 loader 的种类, 取值为'pre'和'post', 该值会影响 loader 调用顺序
配置示例
**安装 loaders **
npm i --save-dev style-loader css-loader sass-loader node-sass
npm i --save-dev file-loader url-loader
npm i --save-dev csv-loader xml-loaderwebpack.config.js
module.exports = {
// ...
module: {
rules: [
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{
test: /\.sass/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|jpg|gif)/,
use: [
{
loader: "url-loader",
options: {
limit: 8192, // 配置转换大小
// fallback: 'file-loader' // 默认使用 file-loader
},
},
],
},
{ test: /\.(woff|woff2|eot|ttf|otf)$/, use: ["file-loader"] },
{ test: /\.(csv|tsv)$/, use: ["csv-loader"] },
{ test: /\.xml$/, use: ["xml-loader"] },
],
},
};一些说明
- 样式处理
style-loader: 用于将 css 文件转换为在执行时会插入<style>标签的脚本css-loader: 用于加载 css 文件sass-loader: 用于加载 sass 文件
- 文件处理
file-loader: 用于加载图片, 字体等多种文件url-loader: 可以对文件大小进行判断是否转换为文件- 若文件小于指定大小,则会转换为 Data Url 的格式,该选项通过
limit配置 - 若文件大于指定大小,可以通过
fallback选项指定用来处理的loader,默认使用file-loader
- 若文件小于指定大小,则会转换为 Data Url 的格式,该选项通过
image-webpack-loader: 用于加载图片, 提供更高级的压缩处理等配置, 可参考 文档
- 数据处理
csv-loader: 用于处理 csv 格式文件, 数据内容会转换为对象xml-loader: 用于处理 xml 格式文件, 数据内容会转换为对象- JSON 格式文件默认支持, 无需 loader
全局依赖
不推荐使用全局内容, 这里仅列出可能需要配置全局内容的情况。
全局常量
使用 DefinePlugin 创建在编译时可配置的全局常量, 该插件通常用于在代码中区分开发模式和生产模式
webpack.config.js
module.exports = {
// ...others
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV ": JSON.stringify("development"),
PRODUCTION: JSON.stringify(false), // const PRODUCTION = false
BROWSER_SUPPORTS_HTML5: true, // const BROWSER_SUPPORTS_HTML5 = 'true'
}),
],
};Shimming
shimming 即垫片器, 用于提前初始化全局环境,一般用于以下情况
- 引用的第三方模块需要使用潜在的全局变量
- 加载 polyfill 以兼容低版本的浏览器
shiming 全局变量
使用 ProvidePlugin 插件提前初始化全局环境
const webpack = require('webpack')
// 引入模块
new webpack.ProvidePlugin({
globalName: 'moduleName'
})
// 引入单个导出值
new webpack.ProvidePlugin({
globalName: ['moduleName', 'propertyName', 'childPropertyName', ...]
})示例: 引入全局 lodash 及其 map 方法
const webpack = require("webpack");
module.exports = {
// ...others
plugins: [
new webpack.ProvidePlugin({
_: "lodash",
map: ["lodash", "map"],
}),
],
};细粒度 Shimming
模块中的 this 指向 module.exports, 若期望其指向 window 对象, 可通过 imports-loader 修改模块内的指向
示例: 指定 needWindow 模块的全局变量为 window
module.exports = {
module: {
rules: [
{
test: /neeWindow\.js$/,
use: "imports-loader?this=>window",
},
],
},
};加载 polyfills
polyfills 可通过 import 直接在主 bundle 中引入, 但通常会提取为独立文件并在浏览器中判断是否需要引入
polyfills.js
// 使用单独的模块引入 polyfills
import "babel-polyfill";
import "whatwg-fetch";webpack.config.js
// 指定单独的入口
module.exports = {
entry: {
polyfills: "./src/polyfills.js",
},
};index.html
<script>
// 在浏览器中添加脚本判断,如果浏览器支持则无需引入 polyfill 文件
const modernBrowser = "fetch" in window && "assign" in Object;
if (!modernBrowser) {
const scriptElement = document.createElement("script");
scriptElement.async = false;
scriptElement.src = "/polyfills.bundle.js";
document.head.appendChild(scriptElement);
}
</script>