webpack为loader提供了一系列的配置属性,同时也为提取这些配置属性提供了一系列的工具方法,这些东西原先并不是webpack本身就包含的,只是用的地方多了, 他就放进去了。
使用 schema-utils
schema-utils
是验证一个对象中是否包含这个这个属性,并且这个属性是否符合预期值,正好webpack
中的loader
、plugin
都会有大量的配置,那就正好可以使用这个工具包来验证配置是否符合预期,用法如下:
- 安装依赖:
npm i -D schema-utils
- 编写代码:
// 引入 schema-utils ,里面有一个 validate 函数 const { validate } = require('schema-utils'); // 定义预期配置值 const schema = { "type": "object", "properties": { // 有一个 name 属性,属性值为 boolean "name": { "type": "boolean" } }, // name 属性值必须要有 "required": ["name"], // 不能使用其他没有被声明的属性值 "additionalProperties": false } validate(schema, {name: ''}); // name 属性值不是 boolean 报错 validate(schema, {name: true, a: ''}); // 有其他没有被声明的属性值报错
一般在loader
中使用的时候,配置量比较大可以定义为外部.json
文件:
const { validate } = require('schema-utils'); // 定义外部json文件 const schema = require('./schema.json'); function loader(source, sourceMap, data) { // 获取loader配置 const options = this.getOptions(); validate(schema, options); this.callback( null, source, sourceMap, data ); } module.exports = loader
在webpack5
之后,可以简化上面的流程:
const schema = require('./schema.json'); function loader(source, sourceMap, data) { this.getOptions(schema); return source; } module.exports = loader
如果验证不合规,schema-utils
会抛出异常,如下
抛出异常自然就会阻断后续的任务,除非你捕获异常。
schema-utils
的校验能力很强,其实了解这个工具后,不仅可以在webpack
的loader
或plugin
中去验证配置,还可以在其他你任何需要验证的地方使用。
schema-utils
内部使用 ajv 的 JSON-Schema模式实现参数校验,而 JSON-Schema 是一种以 JSON 格式描述数据结构的 公共规范,使用时至少需要提供 type
参数,如:
{ "type": "number" }
ajv
默认支持下面这些基础属性(不想做搬运工,下面的就简写了,感兴趣的自行查看文档):
- number:数值型,支持整数、浮点数,支持如下校验规则:
maximum
、minimum
、exclusiveMaximum
、exclusiveMinimum
、multipleOf
interger
:整数型,与number
类似,也支持上面介绍的maximum
等校验规则;- string:字符串型,支持如下校验规则:
maxLength
、minLength
、pattern
、format
boolean
:bool 值;- array:数组型,支持如下校验属性:
maxItems
、minItems
、uniqueItems
、items
null
:空值,常用于复合type
类型,如type = ['object', 'null']
支持传入对象结构或null
值;- object:对象结构,这是一个比较负责的结构,支持如下校验属性:
maxProperties
/minProperties
、required
、properties
patternProperties
:同样用于定义对象属性的 Schema,但属性名支持正则表达式形式,例如:
{ type: "object", patternProperties: { "^el-.*$": {type: "string"}, "^a-.*$": {type: "string"} } }
additionalProperties
:限定对象是否可以提供除properties
、patternProperties
之外的属性;
上面的这些是基本的配置属性解释,除了上面这些还有其他的通用规则字段: enum
:枚举数组; const
:静态数值,属性值必须完全等于 const
定义;
还有复合指令:
not
:数值必须不符合该条件,例如:{type: "number", not: {minimum: 3}}
时,传入数值必须小于 3;anyof
:数值必须满足anyof
条件之一;oneof
:数值必须满足且只能满足oneof
条件之一;allof
:数值必须满足allof
指定的所有条件;if/then/else
:这个有点绕,所以我翻译一下:
{ "type": "object", "if": {"properties": {"foo": {"minimum": 10}}}, "then": {"required": ["bar"]}, "else": {"required": ["baz"]} }
配置长上面这样,直接用代码翻译:
if (option.foo < 10) { if (option.bar == null) { throw new Error() } } else { if (option.baz == null) { throw new Error() } }
口语瞎 J er 翻译:
if
-> 如果传进来的配置满足:有一个foo
的属性,它的值必须小于 10
then
-> 如果通过了if
老哥的考验,那么传进来的属性中必须有一个 bar 属性
else
-> 如果没有通过if
老哥的考验,那么传进来的属性中必须有一个 baz 属性
大白话翻译:
满足
if
的条件就需要进入then
,然后再满足then
的条件,不满足if
的条件就需要进入else
,然后满足else
的条件。
这些基础数据类型与校验规则让我们可以非常完善的属性规则定义,再也不必写a != null || typeof a === 'string' ...
这样的验证代码了,我们使用 schema-utils
时大部分时间都需要构建这些配置体系,所以简写就是让你多看文档。
使用 loader-utils
loader-utils
见名知意,就是webpack
开发loader
的工具类,据说在webpack5
之前这玩意很重要,别问为什么是据说,因为我在webpack5
之前就没开发过loader
,然后webpack5
看这玩意这么多人用,还用的这么频繁,就给里面的一些功能,做到了loader
注入的上下文中了。
被裁减后的 loader-utils
仅保留了四个接口:
urlToRequest
:用于将模块路径转换为文件路径的工具函数;isUrlRequest
:用于判定字符串是否为模块请求路径;getHashDigest
:用于计算内容 Hash 值;interpolateName
:用于拼接文件名的模板工具;
课程中只讲了
interpolateName
,说上面的三个没多少地方使用,就没讲了。
在配置webpack
的时候,output.filename
属性支持[path]/[name].[ext]
这样的占位符,用interpolateName
这个方法就可以做到这样的效果,使用方法如下:
const {interpolateName} = require('loader-utils'); function loader(source, sourceMap, data) { const url = interpolateName(this, "js/[hash].script.[ext]", { content: source }); this.emitFile(url, source); return source; } loader.pitch = function (remainingRequest, previousRequest, data) { } module.exports = loader
interpolateName
支持如下占位符,:
[ext]
:原始资源文件的扩展名;[name]
:原始文件名;[path]
:原始文件相对context
参数的路径;[folder]
:原始文件所在的文件夹;[query]
:查询参数,即?foo=bar[contenthash]
:文件内容hash
上面这些占位符在官网里面都有详细的解释,之前有提到过,而且这里的占位符没有Template String全。
总结
了解schema-utils
和loader-utils
能更高效的开发loader
,loader-utils
是为loader
服务的,但是schema-utils
并不是只为loader
服务,了解这些工具,可以让你的开发更高效和稳定。