jsconst fs = require('fs');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const babel = require('@babel/core');
const path = require('path');
const entry = './src/index.js';
const output = './dist/bundle.js';
// 分析依赖
function parseModule(file) {
const entry = getMoudleInfo(file);
const temp = [entry]; // 使用数组,是因为可能有其他模块
const depsGraph = {};
getDeps(temp, entry);
// 生成依赖图
temp.forEach(moduleInfo => {
depsGraph[moduleInfo.file] = {
deps: moduleInfo.deps,
code: moduleInfo.code
}
})
return depsGraph;
}
function getDeps(temp, { deps }) {
Object.keys(deps).forEach(key => {
const child = getMoudleInfo(deps[key]);
temp.push(child);
getDeps(temp, child);
})
}
// 获取模块信息
function getMoudleInfo(file) {
// 读取文件
const body = fs.readFileSync(file, 'utf-8');
// 转化为ast
const ast = parser.parse(body, { sourceType: 'module' });
const deps = {};
traverse(ast, {
// 获取import导入的模块
ImportDeclaration({ node }) {
const dirname = path.dirname(file);
// 获取标准路径
const absPath = './' + path.join(dirname, node.source.value);
deps[node.source.value] = absPath;
},
});
const { code } = babel.(ast, null {
presets: ["@babel/preset-env"]
});
const moduleInfo = { file, deps, code};
return moduleInfo;
}
// 实现bundle
function bundle(file) {
const depsGraph = JSON.stringify(parseModule(file));
// todo
return `;
(function(graph) {
function require(file) {
function absRequire(realPath) {
return require(graph[file]).deps[realPath];
}
var exports = {};
(function(require, exports, code) {
eval(code);
})(absRequire, exports, graph[file].code)
return exports;
}
return require('${file}');
})(${depsGraph});`
}
const content = bundle(entry);
fs.writeFileSync(output, content, 'utf-8');
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93