从loader到ast树

我的第一个loader

loader/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
const loaderUtils = require("loader-utils");
module.exports = function (content, map, meta) {

console.log('前置钩子', this.data.value);
const options = loaderUtils.getOptions(this);
console.log('配置文件', options);
// tofo content进行遍历的过程
return content+'console.log(1)';
}
//pitch的前置钩子
module.exports.pitch = function (r, prerequest, data) {
data.value = "京城一灯"
}

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: path.resolve('./loader/index.js'),
options: {
data:"自定义的配置"
}
}
}
]
}
}

loader的原理-ast树分析

用acorn这个库来实现代码的转化的

1
2
3
4
5
6
7
8
const acorn = require('acorn');
const walk = require('acorn-walk');
const result = acorn.parse("const a=20");
walk.simple(result, {
Literal(node) {
console.log(`Found a literal:${node.value}`);
}
});

用esprima+estraverse+escodegen实现

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
32
33
34
35
const esprima = require('esprima');
const estraverse = require('estraverse');
const escodegen = require('escodegen');

const code = `const view = {
a: 3,
init: () => {
console.log(this.a);
},
render: () => {
a = 4;
}
}`;
const ast = esprima.parse(code);
// console.log(ast);
/*Script {
type: 'Program',
body:
[ VariableDeclaration {
type: 'VariableDeclaration',
declarations: [Array],
kind: 'const' } ],
sourceType: 'script' }*/

estraverse.traverse(ast, {
enter: function (node) {
// console.log(node);
if (node.type == 'VariableDeclaration') {
node.kind = 'var';
}
}
});

const reg_code = escodegen.generate(ast);
console.log(JSON.stringify(reg_code, null, 4));

tapable的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const {
Tapable,
SyncHook,
SyncBailHook,
AsyncParallelHook,
AsyncSeriesHook
} = require("tapable");

let queue = new SyncHook(["name"]);
//订阅
queue.tap("1", function (name, name2) {
console.log("1", name, name2);
return 1;
});
queue.tap("2", function (name) {
console.log("1", name);
return 2;
});
queue.tap("3", function (name) {
console.log("1", name);
return 3;
});
//执行用call
queue.call("webpack", "webpack-cli");