一、引入依赖
const fs = require('fs')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default;
const path = require('path')
const babel = require('@babel/core')
二、形成AST抽象语法树,分析模块的代码和依赖路径
function moduleAnalyser(filename) {
const content = fs.readFileSync(filename, 'utf-8');
const ast = parser.parse(content, {
// parse in strict mode and allow module declarations
sourceType: "module",
});
const dependencies = {};
traverse(ast, {
ImportDeclaration({ node }) {
// dependencies.push(node.source.value)
const dirname = path.dirname(filename)
const newFile = './' + path.join(dirname, node.source.value)
dependencies[node.source.value] = newFile
}
})
// console.log(ast.program)
// console.log(dependencies)
const { code } = babel.transformFromAst(ast, null, {
presets: ["@babel/preset-env"]
});
return {
filename,
dependencies,
code
}
}
三、形成模块间的依赖图谱
const makeDependenciesGraph = (entry) => {
const entryModule = moduleAnalyser(entry)
const graphArry = [entryModule]
for (let i = 0; i < graphArry.length; i++) {
const item = graphArry[i];
// console.log(item,123)
const { dependencies } = item;
if (dependencies) {
for (let j in dependencies) {
graphArry.push(
moduleAnalyser(dependencies[j])
)
}
}
}
const graph = {}
graphArry.forEach(item => {
graph[item.filename] = {
dependencies: item.dependencies,
code: item.code
}
})
return graph
}
四、代码生成
const generateCode = (entry) => {
const graph = JSON.stringify(makeDependenciesGraph(entry));
return `
(function(graph){
function require(module){
function localRequire(relativePath){
return require(graph[module].dependencies[relativePath])
}
var exports={};
(function(require,exports,code){
eval(code)
})(localRequire,exports,graph[module].code);
return exports;
};
require('${entry}');
})(${graph})
`;
}
const code = generateCode('./src/main.js') //这个就是你项目的入口文件
console.log(code)
最后生成的code代码就可以在浏览器上执行