一、引入依赖
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代码就可以在浏览器上执行