前面在加载样式文件的时候介绍了很多 loader,每个 loader 都有不同的配置方法。实际上,Webpack 提供了多种方式来设置 loader 参数。本文就来详细说明如何配置一个 loader。
Webpack 默认只支持 CommonJS 规范。其他规范的模块,Webpack 需要借助于 loader 来解析。下面的样例展示了利用 babel 来加载 JavaScript 文件的 loader 配置。
const config = {
module: {
rules: [
{
// 文件匹配条件,支持正则表达式或者函数
test: /\.js$/,
// 文件目录匹配
include: path.join(__dirname, "app"),
exclude: (path) => path.match(/node_modules/);
// 针对匹配到的文件需要执行的动作
use: "babel-loader",
},
],
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Loader 的顺序
在 Webpack 中,loader 是按从右向左,从下向上的顺序依次评估的。可以通过函数调用的方式加以理解。use: ["style-loader", "css-loader"]
等同于 style(css(input))
。参考样例:
const config = {
test: /\.css$/,
use: ['style-loader', 'css-loader'],
};
2
3
4
基于从右向左的原则,配置还可以改成这样:
const config = [
{ test: /\.css$/, use: 'style-loader' },
{ test: /\.css$/, use: 'css-loader' },
];
2
3
4
正常情况下,通过上面的规则,我们可以实现各种处理顺序的 loader 定义。但是,有时候如果可以动态调整 loader 定义的顺序会给开发带来极大的遍历。这时候我们可以通过 enforce
这个字段来实现,enforce
取值为 pre
则 loader 会在其他 loader 之前执行,取值为 post
则 loader 会在其他 loader 之后执行。
代码规范静态检查配置可以很好的说明 enforce
的使用,通常我们需要在加载源代码的时候就检查代码规范,因此需要配置 enforce: "pre"
。enforce:"post"
不太常用,通常会被用在对构建输出做校验的场景下。
const config = {
test: /\.js$/,
enforce: 'pre', // "post" too
use: 'eslint-loader',
};
2
3
4
5
通常来说,我们也可以通过纯代码的形式控制 loader 顺序,但是 enforce
提供了更多的遍历,同时也允许 loader 的配置分散在多个文件中,灵活性更好。
loader 的参数
Webpack 支持通过 query 参数的形式给 loader 设置参数。
const config = { test: /\.js$/, use: 'babel-loader?presets[]=env' };
这种传参方式同样可以被应用在源代码中。缺点是可读性差一些。
通常情况下,我们使用 use
来给 loader 传参:
const config = {
test: /\.js$/,
use: { loader: 'babel-loader', options: { presets: ['env'] } },
};
2
3
4
内联 loader 定义
通常情况下,我们通过 webpack 的配置文件来定义 loader,但是,Webpack 同时支持在源代码中通过内联的形式定义 loader。
import 'url-loader!./foo.png';
import '!!url-loader!./bar.png';
2
一般来说,我们应该避免这么做,因为这样使得我们的源代码跟 webpack 产生了耦合。
我们也可以在 webpack 的 entry 配置中定义 loader。
const config = { entry: { app: 'babel-loader!./app' } };
info
对象来加载资源
通过 use
支持传递一个函数,返回 loader 配置。在这个函数里,我们可以根据环境等条件返回不同的配置。use
函数中必须返回一个值,可以为 falsy, object,或者字符串。
const config = {
rules: [
{
test: /\.js$/,
use: [
(info) => ({
loader: 'babel-loader',
options: { presets: ['env'] },
}),
],
},
],
};
2
3
4
5
6
7
8
9
10
11
12
13
info 对象包含如下内容:
{
resource: '/webpack-demo/src/main.css', // 表示匹配到的资源路径
realResource: '/webpack-demo/src/main.css',
resourceQuery: '', // 表示匹配到的资源的查询参数
issuer: '', // 表示引用这个资源的模块路径
compiler: 'mini-css-extract-plugin /webpack-demo/node_modules/css-loader/dist/cjs.js!/webpack-demo/node_modules/postcss-loader/src/index.js??ref--4-2!/webpack-demo/node_modules/postcss-loader/src/index.js??ref--4-3!/webpack-demo/src/main.css'
}
2
3
4
5
6
7
通过 resourceQuery 加载资源
可以通过 oneOf
字段,我们可以配置让 Webpack 根据不同的资源加载不同的 loader。
const config = {
test: /\.png$/,
oneOf: [
{ resourceQuery: /inline/, use: 'url-loader' },
{ resourceQuery: /external/, use: 'file-loader' },
],
};
2
3
4
5
6
7
除了 resourceQuery,也可以使用 resourcePath.
通过 issuer 加载资源
issuer
可以用来根据引用者来加载不同的 loader。下面的例子,表示当一个 css 是被 JavaScript 文件引用的时候,需要加载 style-loader
。
const config = {
test: /\.css$/,
rules: [{ issuer: /\.js$/, use: 'style-loader' }, { use: 'css-loader' }],
};
2
3
4
issuer
也可以与 not
混用,
const config = {
test: /\.css$/,
rules: [
// 将被其他非 css 模块引入的 css 写入到 dom 中
{ issuer: { not: /\.css$/ }, use: 'style-loader' },
{ use: 'css-loader' }, // 处理 css 导入
],
};
2
3
4
5
6
7
8
调整 loader 匹配条件的各种方法
test
,include
,exclude
是最常用的匹配条件,可以设置为正则表达式、字符串、函数、对象,或者一个数组。resource: /inline/
匹配资源路径,包括查询参数,比如:/path/foo.inline.js
,/path/bar.png?inline
.issuer: /bar.js/
当一个资源的引用方满足条件的时候,这个资源被匹配到。比如:/path/foo.png
如果被/path/bar.js
引用了,则它就会被匹配。resourcePath: /inline/
仅匹配资源路径,比如:/path/foo.inline.png
resourceQuery: /inline/
仅匹配资源的查询参数,比如:/path/foo.png?inline
.
同时还可以与下面的布尔型匹配条件组合使用。
not
不匹配某一个条件。and
同时满足一组条件。or
满足一组条件中的一个。
总结
loader-runner
这个包可以不借助 Webpack 直接运行 loader, 可以帮助我们更好的理解 loader 的工作机制。通过将 inspect-loader
这个工具与 Webpack 配置结合起来,我们可以了解 loader 之间数据是如何传递的。
我们通过 loader 来配置 Webpack 根据不同的模块使用不同的处理机制。
一个 loader 定义包块匹配模块的条件和处理模块的动作。
Webpack 提供了多种定义 loader 的方式,我们可以根据不同的需求使用不同的配置。
关注微信公众号,获取最新推送~
加微信,深入交流~