Skip to main content

编写 webpack loader

webpack loader 是什么

loader就是一个函数,用于编译源代码内部不同类型的模块,同时输出编译后的代码,用来拓展 webpack 的解析能力。

为什么需要 loader

本身 webpack 只能处理.js,·.json文件,对于其他类型的模块代码,webpack 需要借助loader来处理源码,可以把loader直接理解为编译器,因为它主要负责将 webpack 输入的模块代码转换成另一种形式的代码输出。

loader 运行模式

loader接收以下三个参数:

loader可以直接返回处理后的代码,表示该loader是以同步模式运行的

module.exports = function(content, map, meta) {
let result = '';

// 一些处理
return result;
};

loader内部具有异步处理时,需要对结果使用callback函数进行包装,callback依次接收四个参数:

  • error:第一个参数是错误信息Error或者null
  • result:第二个参数则是处理过后的代码
  • source map:第三个参数是 source map
  • meta:第四个参数,会被 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&params
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应该只处理一种类型的源代码
  • 禁止写绝对路径