loader 需要 export 一个 function, 通过 this 可以访问到 Loader API.

如何将编写好的 loader 引入

// 单个 loader 直接指定绝对路径
module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: path.resolve('path/to/loader.js'),
            options: {/* ... */}
          }
        ]
      }
    ]
  }
};
// 多个 loader 指定目录
module.exports = {
  //...
  resolveLoader: {
    modules: [
      'node_modules',
      path.resolve(__dirname, 'loaders')
    ]
  }
};

简单用法

loader 被调用的时候,会被传入一个字符串作为参数,包含源文件的代码。

同步的 loader 可以直接返回一个代表被转换过的值。异步的 loader, 可以调用 this.callback(err, values...) 返回任意数量的参数。

loader 将返回一或两个值,第一个是一个结果 javascript 代码,可以为 string | buffer, 第二个是可选值是一个 sourceMap 对象。

复杂用法

如果有多个 loader 那么最后一个 loader 会接受文件的源代码作为参数,中间的 loader, 可以随意返回,只要返回的值能够被下一个 loader 处理,第一个 loader, 必须返回一个 javascript 代码或者一个可选的source map 对象。

编写指引

simple

loader 应该只执行一个任务。这不仅使维护每个 loader 的工作更容易,而且还允许将它们链接起来,以便在更多的场景中使用。

chaining

利用 loader , 可以链式调用的特点,如果需要处理 5 个任务,那么不要把他们写在一起,单独写 5 个 loader,每个 loader 单独处理一个任务。

stateless

确保加载器在模块转换之间不保留状态。每次运行都应该独立于其他已编译模块以及相同模块的先前编译。

Loader 编写工具库

loader-utils 这个包提供了许多有用的工具,其中用的比较多的是获取传递给 loader 的 option。同时 schema-utils,用于基于加载器选项验证的一致JSON模式。

import { getOptions } from 'loader-utils';
import validateOptions from 'schema-utils';

const schema = {
  type: 'object',
  properties: {
    test: {
      type: 'string'
    }
  }
};

export default function(source) {
  const options = getOptions(this);

  validateOptions(schema, options, 'Example Loader');

  // Apply some transformations to the source...

  return `export default ${ JSON.stringify(source) }`;
}

Loader 使用外部资源

如果你的 loader 使用外部资源,比如需要读取文件系统,我们必须将这条记录添加,此信息用于使可缓存加载程序失效并在监视模式下重新编译。需要使用 addDependency 来完成这一操作。

import path from 'path';

export default function(source) {
  var callback = this.async();
  var headerPath = path.resolve('header.js');

  this.addDependency(headerPath);

  fs.readFile(headerPath, 'utf-8', function(err, header) {
    if(err) return callback(err);
    callback(null, header + '\n' + source);
  });
}

common code

避免在加载器处理的每个模块中生成公共代码。相反,在加载器中创建一个运行时文件并生成对该共享模块的需求。

Absolute Paths

不要在模块代码中插入绝对路径,因为当项目的根被移动时,它们会打破 hashing。在loader-utils中有一个stringifyRequest方法,可用于将绝对路径转换为相对路径。


RickyLong
501 声望27 粉丝

所有事情都有一套底层的方法论,主要找到关键点,然后刻意练习,没有刻意练习,做事情只是低效率的重复