编写 webpack loader
webpack loader 是什么
loader
就是一个函数,用于编译源代码内部不同类型的模块,同时输出编译后的代码,用来拓展 webpack 的解析能力。
为什么需要 loader
本身 webpack 只能处理.js
,·.json
文件,对于其他类型的模块代码,webpack 需要借助loader
来处理源码,可以把loader
直接理解为编译器,因为它主要负责将 webpack 输入的模块代码转换成另一种形式的代码输出。
loader 运行模式
loader
接收以下三个参数:
content
:源代码map
:可以被 https://github.com/mozilla/source-map 使用的 SourceMap 数据meta
:meta 数据,可以是任何内容
loader
可以直接返回处理后的代码,表示该loader
是以同步模式运行的
module.exports = function(content, map, meta) {
let result = '';
// 一些处理
return result;
};
当loader
内部具有异步处理时,需要对结果使用callback
函数进行包装,callback
依次接收四个参数:
error
:第一个参数是错误信息Error
或者null
result
:第二个参数则是处理过后的代码source map
:第三个参数是 source mapmeta
:第四个参数,会被 webpack 忽略,可以是任何类型的参数
module.exports = function(content, map, meta) {
// 获取 callback 函数
var callback = this.async();
someAsyncOperation(content, function(err, result) {
if (err) {
return callback(err);
}
callback(null, result, map, meta);
});
};
loader 的链式调用
module.rules.use
这个数组传递的多个loader
按照数组索引的顺序从后往前执行,第一个执行的loader
会获取模块源代码作为参数,然后其执行结果会传递给下一个执行的loader
,最后一个loader
执行期望返回JS
代码和sourcemap
;比较常见的就是less
的处理流程
module: {
rules: [
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
]
}
辅助工具
loader-utils
常用于获取在webpack
配置项中传递给loader
的参数配置,返回的参数配置项是一个只读的对象
// 在loader内部使用
const loaderUtils = require('loader-utils');
const options = loaderUtils.getOptions(this);
// 通过queryString指定的配置项,例如loader?some¶ms
const params = loaderUtils.parseQuery(this.resourceQuery);
schema-utils
schema-utils
可以对loader
获取的配置参数进行校验,从schema-utils
中获取的validate
方法接收三个参数:
schema
:用于定义options
配置项的类型和校验不通过时的描述,也就是校验规则options
:即外部传递进来的配置项configuration
:最后一个参数用于补充对于schema
的描述信息
import { getOptions } from 'loader-utils';
import { validate } from 'schema-utils';
// 校验规则
const schema = {
type: 'object',
properties: {
name: {
type: 'string',
},
query: {
type: 'number',
},
},
additionalProperties: false,
};
function loader(src, map) {
const options = getOptions(this);
validate(schema, options, {
name: 'Loader Name',
baseDataPath: 'options',
});
// Code...
return `function() {xxx}`;
}
export default loader;
编写 loader 的注意事项
- 功能单一原则:一个
loader
应该只处理一种类型的源代码 - 禁止写绝对路径