Webpack如何编写一个loader

介绍

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或”加载”模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

这种链式调用和gulp跟相似,每一个loader都只关心自己的事,而不是一个loader完成所有的操作。

编写一个 loader

本地设置

  • 匹配(test)单个 loader,你可以简单通过在 rule 对象设置 path.resolve 指向这个本地文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    test: /\.js$/
    use: [
    {
    loader: path.resolve('path/to/loader.js'),
    options: {/* ... */}
    }
    ]
    }
  • 匹配(test)多个 loaders,你可以使用 resolveLoader.modules 配置,webpack 将会从这些目录中搜索这些 loaders。例如,如果你的项目中有一个 /loaders 本地目录,在loaders下面有很多loader

    1
    2
    3
    4
    5
    6
    resolveLoader: {
    modules: [
    'node_modules',
    path.resolve(__dirname, 'loaders')
    ]
    }

loader 工具库

loader-utils :它提供了许多有用的工具,最常用的一种工具是获取传递给 loader 的选项。
schema-utils :配合 loader-utils,用于保证 loader 选项,进行与 JSON Schema 结构一致的校验。

开发

编写一个简单的json-loader

这个loader把简单的Excel表格导出为json对象。提供一个sheet属性,用于选择导出某一页的表格,默认是整个文档。
src/loader.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { getOptions } from 'loader-utils';
import validateOptions from 'schema-utils';
import xlsx from '.json';

// Loader Mode
export const raw = true;

const schema = {
type: "object",
properties: {
sheet: {
anyOf: [
{ type: "number" },
{ type: "string" }
]
}
},
additionalProperties: true
}

export default function loader(source) {
const options = getOptions(this) || {};
validateOptions(schema, options, 'xlsx Loader');

source = JSON.stringify(xlsx.toJson(source, options.sheet || null))
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')

return `export default ${ source }`;
}

raw: loader加载资源的模式,以二进制的方式加载文件,默认值是false,返回源文件内容的字符串。
schema:用于校验option选项。
xlsx.toJson:用于将源文件转换成json对象。

xlsx源码

github地址

测试用例

安装

我们将使用 Jest 框架。然后还需要安装 babel-jest 、 babel-preset-env 和 memory-fs:

1
npm install --save-dev jest babel-jest babel-preset-env

使用loader来处理test/example.xlsx文件

xlsx文件内容

id name age
1 biaoge 30
1 haohua 18

test/compiler.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import path from 'path';
import webpack from 'webpack';
import memoryfs from 'memory-fs';

export default (fixture, options = {}) => {
const compiler = webpack({
context: __dirname,
entry: `./${fixture}`,
output: {
path: path.resolve(__dirname),
filename: 'bundle.js',
},
module: {
rules: [{
test: /\.xls.?$/,
loader: path.resolve(__dirname, '../src/index'),
options
}]
}
});

compiler.outputFileSystem = new memoryfs();

return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
if (err) reject(err);

resolve(stats);
});
});
}

最后,我们来编写测试,并且添加 npm script 运行它。

1
2
3
4
5
6
7
8
9
10
11
12
13
import compiler from './compiler';

test('getSingle', async () => {
const stats = await compiler('example.xlsx', {sheet: 'sheet1'});
const output = stats.toJson().modules[0].source;
expect(output).toBe(`export default [{"id":"1","name":"Jack","age":"20"},{"id":"2","name":"Tom","age":"18"}]`);
})

test('getAll', async () => {
const stats = await compiler('example.xlsx');
const output = stats.toJson().modules[0].source;
expect(output).toBe(`export default [{"sheet":"sheet1","data":[{"id":"1","name":"Jack","age":"20"},{"id":"2","name":"Tom","age":"18"}]}, {"sheet":"sheet2","data":[{"id":"1","name":"Jack","age":"20"},{"id":"2","name":"Tom","age":"18"}]}]`);
})

thank you

感谢支持,我会不断进步