Skip to content
大纲

基础配置 ​

模块解析 ​

webpack 内部使用 enhance-resolve 解析文件路径, 通过 resolve 字段可以配置解析策略

配置解析策略 ​

resolve.alias ​

指定模块的别名, 以简写某些常用模块的路径

  • 通常使用 @ 表示 src 目录
  • 使用 $ 特殊字符结尾表示精确匹配

配置示例

js
module.exports = {
  // ...others
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src/"),
      "@utils$": path.resolve(__dirname, "src/util/index.js"),
    },
  },
};

使用示例

js
import Comps from "@/comps";
import utils from "@utils";

resolve.extensions ​

解析未指定扩展名的文件时, 自动解析确定的扩展

  • 默认配置 [".js", ".json"] (新版的文档中删除了该说明, 可能不准确)
  • 配置该选项时会覆盖默认配置
  • 配置靠前的字段优先级更高
  • 使用 * 字段可以匹配任意文件扩展名, 不建议使用
  • 常用的配置: ['js', 'jsx', 'ts', 'tsx', 'json']
  • 不推荐添加非逻辑文件扩展名, 如 'css'

resolve.modules ​

指定解析模块时搜索的目录, 通常在引用自定义模块时需要修改该配置

  • 默认配置为 ['node_modules']
  • 可以配置多个目录
  • 配置靠前的目录优先级更高

配置示例

js
module.exports = {
    // ...
    resolve: {
        modules: [path.resolve(__dirname, 'my_modules'), 'node_modules]
    }
}

resolve.mainFields ​

导入模块时, 指定依据 'package.json' 中哪个字段导入模块, 通常不会修改该配置

  • 默认配置为 ['module', 'main']
  • 配置靠前的字段优先级更高

resolve.mainFiles ​

解析目录时, 解析目录下默认的文件, 通常不会修改该配置

  • 默认配置 ['index']
  • 配置靠前的字段优先级更高

解析流程 ​

  1. 解析路径
    • 绝对路径
      • 场景示例: import '/my-project/src/resolve/path/some-module
      • 解析方式: 不处理, 直接使用
    • 相对路径
      • 场景示例: import '../utils/some/file'
      • 解析方式: 将引用文件所在目录作为上下文目录, 并将被引用文件路径解析为绝对路径
    • 模块路径
      • 场景示例:
        • import '@path/some-module'
        • import 'some-module'
      • 解析方式
        • 若使用路径别名, 则依据 resolve.alias 配置进行解析
        • 依据 resolve.modules 配置中指定的目录进行搜索解析
  2. 解析文件
    • 若解析路径指向文件
      • 指定扩展名: 直接加载指定文件
      • 省略扩展名: 依据 resolve.extensions 选项解析文件扩展名
    • 若解析路径指向目录
      • 目录下存在 'package.json' 文件
        1. 按照 'package.json' 文件中 main 字段解析文件
        2. 若不存在 main 字段或解析失败, 则按照 resolve.mainFields 配置中指定字段依此解析
      • 目录下缺少 package.json 文件
        1. 按照 resolve.mainFiles 配置依此查找文件
        2. 未配置 resolve.mainFiles 则默认查找 'index.js' 文件

入口配置 ​

webpack 使用 entry 字段指定构建的入口

  • 配置格式
    • entry: string | [string]: 配置单个入口, 使用默认的 chunk 名称
    • entry: { [name: string]: string | [string] }: 配置单个或多个入口, 使用键作为 chunk 名称
    • entry: () => string | [string]: 配置动态入口, 返回一个配置项
  • 路径解析
    • 入口路径为单一字符串, 则依此路径解析
    • 入口路径为字符串数组, 则依此进行解析并打包至一个文件中
  • 默认配置
    • 默认入口: ./src/index.js
    • 默认名称: main
  • 使用场景
    • 单个入口通常用于构建单页面应用、库等
    • 多个入口通常用于构建多页面应用, 实现单页面应用长效缓存, 大型单页面应用的拆分等
  • 注意事项
    • 动态加载模块不是入口起点
    • 长效缓存值将修改频率极低的文件单独构建以避免修改文件名称, 从而充分利用浏览器缓存机制的处理方式

示例

js
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 值

示例

js
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 规则

示例

js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

规则 ​

每条规则分为三部分: 条件, 结果, 嵌套规则

  • 条件: 有两种输入值, 其路径已根据 resolve 规则解析
    • resource: 请求文件的绝对路径, 配置字段有 test, include, exclude 和 resource
    • issuer: 导入请求文件的模块的绝对路径, 相关字段为 issuer, 通常不需要配置
  • 结果: 有两种输入值, 在规则条件匹配时使用
    • loader: 应用在 resourve 上的 loader 数组, 配置字段有 loader, options, use, enforce
    • parser: 用于为模块创建解析器的选项对象, 配置字段为 parser
  • 嵌套规则: 可以使用 rules 和 oneOf 指定嵌套规则

配置规则条件 ​

条件种类

  • { test: Condition }: 匹配特定条件, 该值通常是正则或正则数组
  • { include: Condition }: 匹配特定条件, 该值通常是字符串或字符串数组
  • { exclude: Condition }: 排除特定条件, 该值通常是字符串或字符串数组
  • { and: [Condition] }: 数组中所有条件满足时匹配
  • { or: [Condition] }: 数组中任一条件满足时匹配
  • { not: [Condition] }: 排除数组中条件

条件类型

  • 字符串: 目录绝对路径或文件绝对路径
  • 正则: test 输入值
  • 函数: 调用输入的函数, 必须返回一个 truthy
  • 条件数组: 至少一个匹配条件
  • 对象: 匹配所有属性, 每个属性有一个定义行为

示例

js
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 **

bash
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-loader

webpack.config.js

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
    • image-webpack-loader: 用于加载图片, 提供更高级的压缩处理等配置, 可参考 文档
  • 数据处理
    • csv-loader: 用于处理 csv 格式文件, 数据内容会转换为对象
    • xml-loader: 用于处理 xml 格式文件, 数据内容会转换为对象
    • JSON 格式文件默认支持, 无需 loader

全局依赖 ​

不推荐使用全局内容, 这里仅列出可能需要配置全局内容的情况。

全局常量 ​

使用 DefinePlugin 创建在编译时可配置的全局常量, 该插件通常用于在代码中区分开发模式和生产模式

webpack.config.js

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 插件提前初始化全局环境

js
const webpack = require('webpack')

// 引入模块
new webpack.ProvidePlugin({
    globalName: 'moduleName'
})

// 引入单个导出值
new webpack.ProvidePlugin({
    globalName: ['moduleName', 'propertyName', 'childPropertyName', ...]
})

示例: 引入全局 lodash 及其 map 方法

js
const webpack = require("webpack");

module.exports = {
  // ...others
  plugins: [
    new webpack.ProvidePlugin({
      _: "lodash",
      map: ["lodash", "map"],
    }),
  ],
};

细粒度 Shimming ​

模块中的 this 指向 module.exports, 若期望其指向 window 对象, 可通过 imports-loader 修改模块内的指向

示例: 指定 needWindow 模块的全局变量为 window

js
module.exports = {
  module: {
    rules: [
      {
        test: /neeWindow\.js$/,
        use: "imports-loader?this=>window",
      },
    ],
  },
};

加载 polyfills ​

polyfills 可通过 import 直接在主 bundle 中引入, 但通常会提取为独立文件并在浏览器中判断是否需要引入

polyfills.js

js
// 使用单独的模块引入 polyfills
import "babel-polyfill";
import "whatwg-fetch";

webpack.config.js

js
// 指定单独的入口
module.exports = {
  entry: {
    polyfills: "./src/polyfills.js",
  },
};

index.html

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>