-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
130 lines (118 loc) · 3.24 KB
/
index.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
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* main bundler */
const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser"); // parses and returns AST
const traverse = require("@babel/traverse").default; // walks through AST
const babel = require("@babel/core"); // main babel functionality
const detective = require("detective");
let ID = 0;
/*
* Given filePath, read and parses module, returns module information
* Module information includes:
* - module ID
* - module filePath
* - all dependencies used in the module (in array form)
* - code inside the module
*/
function createModuleInfo(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const cjsDeps = detective(content);
let deps = [];
let code;
let isES6;
if (cjsDeps.length === 0) {
const ast = parser.parse(content, {
sourceType: "module"
});
traverse(ast, {
ImportDeclaration: ({ node }) => {
deps.push(node.source.value);
}
});
code = babel.transformFromAstSync(ast, null, {
presets: ["@babel/preset-env"]
}).code;
isES6 = true;
} else {
deps = cjsDeps;
code = content;
isES6 = false;
}
const id = ID++;
return {
id,
filePath,
deps,
code,
isES6
};
}
/*
* Given entry path,
* returns an array containing information from each module
*/
function createDependencyGraph(entry) {
const entryInfo = createModuleInfo(entry);
const graphArr = [];
graphArr.push(entryInfo);
for (const module of graphArr) {
module.map = {};
module.deps.forEach(depPath => {
const baseDir = path.dirname(module.filePath);
const baseModuleDir = path.join(baseDir, depPath);
const absPath = path.resolve(baseModuleDir);
const moduleInfo = createModuleInfo(absPath);
graphArr.push(moduleInfo);
module.map[depPath] = moduleInfo.id;
});
}
return graphArr;
}
/*
* Given an array containing information from each module
* return a bundled code to run the modules
*/
function pack(graph) {
const isES6 = graph[0].isES6;
const moduleArgArr = graph.map(module => {
let exportsStatement;
if (isES6) {
exportsStatement = "exports";
} else {
exportsStatement = "module";
}
return `${module.id}: {
factory: (${exportsStatement}, require) => {
${module.code}
},
map: ${JSON.stringify(module.map)}
}`;
});
let factoryExportsStatement;
if (isES6) {
factoryExportsStatement = "module.exports";
} else {
factoryExportsStatement = "module";
}
const iifeBundler = `(function(modules){
const require = id => {
const {factory, map} = modules[id];
const localRequire = requireDeclarationName => require(map[requireDeclarationName]);
const module = {exports: {}};
factory(${factoryExportsStatement}, localRequire);
return module.exports;
}
require(0);
})({${moduleArgArr.join()}})
`;
return iifeBundler;
}
const bundler = entryFilePath => {
const graph = createDependencyGraph(entryFilePath);
const bundle = pack(graph);
console.log("***** Copy code below and paste into browser *****");
console.log(bundle);
console.log("***** Copy code above and paste into browser *****");
return;
};
module.exports = bundler;