webpack 不同 loader 的执行顺序
webpack 中 loader 常用的有配置(普通和 enforce)和内联两种形式。在编译的过程中混用的情况比较常见,本文理一下执行顺序。
默认的从右往左(从下到上)是编程风格的问题,可以参考这篇文章的说法:why-webpack-loader-read-from-right-to-left。
有三种使用 loader 的方式:
- 配置方式:在 webpack.config.js 文件中指定 loader。
- 内联方式:在每个 import 语句中显式指定 loader。
- CLI 方式:在 shell 命令中指定它们。不在执行顺序考虑范围里
结论
loader 的执行分为两个阶段 Pitching phase 和 Normal phase,有点类似捕获和冒泡,这里先贴一下结论,下面再举例
Pitching phase:post -> inline -> normal -> pre
Normal phase:pre -> normal -> inline -> post
其中只要在配置中没有配置 enforce 属性(pre 或 post)的就是 normal loader,inline 指的就是内联方式写的 loader。
下面以 Normal phase 为例说明执行顺序
默认配置方式的执行顺序
先看一个配置示例,详细的配置说明推荐查看官方文档
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.xjs$/,
use: [
{ loader: "a-loader.js" },
{ loader: "b-loader.js" },
{ loader: "c-loader.js" },
],
},
],
},
};
loader 从右到左(或从下到上)执行,此处的顺序是 c-loader -> b-loader -> a-loader
配置添加 enforce
添加 enforce 属性,pre 优先处理,post 最后处理
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.xjs$/,
use: [
{
loader: "a-loader.js",
enforce: "pre",
},
{ loader: "b-loader.js" },
{
loader: "c-loader.js",
enforce: "post",
},
],
},
],
},
};
执行顺序就是 a-loader -> b-loader -> c-loader
内联 loader
若匹配的文件开头来了一句
// xxx.xjs
import { a } from "./e-loader.js!./d-loader.js!./file1.js";
内联 loader 的执行顺序也符合从右到左的规则 d-loader.js -> e-loader.js
搭配刚才 enforce 的配置就是 a-loader -> b-loader -> d-loader -> e-loader -> c-loader
覆盖配置中的 loader
在编译的过程中(例如解析.vue 文件),loader 的选用往往是动态决定的,也就是 inline loader 是动态生成的,此时可能要选用特定的 loader 去处理已经在配置里配置了 loader 的文件。
而这个文件一般已经用配置里的 loader 解析过了,没有必要重复使用这些 loader(需要自行将结果缓存),要忽略这些 loader 可以使用 ! 前缀进行处理。
还是搭配刚才 enfoece 的配置
- 使用 ! 前缀禁用 normal loaders
// xxx.xjs
import { a } from "!./e-loader.js!./d-loader.js!./file1.js";
// a-loader -> d-loader -> e-loader -> c-loader
- 使用 !! 前缀禁用全部配置的 loaders
// xxx.xjs
import { a } from "!!./e-loader.js!./d-loader.js!./file1.js";
// d-loader -> e-loader
- 使用 -! 禁用全部配置的 preLoaders 和 normal loaders
// xxx.xjs
import { a } from "-!./e-loader.js!./d-loader.js!./file1.js";
// d-loader -> e-loader -> c-loader
其他
当 rules 中有多个匹配的 loaders 时,从下向上执行。像下面这个例子,执行顺序就是 js-loader2.js -> js-loader.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "./js-loader.js",
},
{
test: /\.js$/,
loader: "./js-loader2.js",
},
],
},
};
最后贴一个官方对配置顺序的说明:Rule.enforce