// 高亮代码
npm i cli-highlight -g
// 安装依赖包
npm install @babel/parser --save
npm install @babel/core --save
npm install @babel/traverse --save
npm install @babel/preset-env --save
进入正文
- 模块分析: 通过fs读取文件内容,通过@babel/parser将文件内容转化为AST,使用@babel/traverse遍历AST,对每个路径信息做映射,将依赖关系拼装在依赖对象里,使用@babel/core将AST转化为可运行的code,最后该函数return出去文件名称、依赖和代码。
const fs = require('fs'); // 文件处理模块
const parser = require('@babel/parser'); // 用于AST转化
const tarverse = require('@babel/traverse').default; // 引入babel/traverse的默认导出 对AST进行过滤解析
// 分析入口文件
const moduleAnalyser = (entryFile) => { // entryFile 入口文件路径
// fs模块根据路径读取到了module的内容
const content = fs.readFileSync(entryFile, 'utf-8');
console.log(content);
// 分析内容
const AST = parser.parse(content, {
// ESModule形式导入的模块
sourceType: 'module'
});
// 使用@babel/traverse遍历了AST ,对每个ImportDeclaration节点做映射,把依赖关系拼装在 dependencies对象里
const dependencies = {};
tarverse(AST, {
ImportDeclaration({node}) {
console.log(node, 'node');
const dirname = path.dirname(entryFile);
// 新路径
const newPathName = "./" + path.join(dirname, node.source.value)
dependencies[node.source.value] = newPathName;
}
})
// 使用@babel/core结合@babel/preset-env预设,将AST转换成了浏览器可以执行的代码
const { code } = babel.transformFromAst(AST, null, {
presets: ["@babel/preset-env"]
})
return {
entryFile,
dependencies,
code
}
}
- 生成依赖图谱: 拿到上步的dependencies依赖映射,将入口文件的依赖路径再做一次模块分析,再把依赖模板的依赖路径在做一次模块分析.....
const makeDependenciesGraph = (entryFile) => {
const entryModule = moduleAnalyser(entryFile);
const graphArray = [entryModule];
for(let i = 0; i < graphArray.length; i++) {
const item = graphArray[i];
const { dependencies } = item;
if (dependencies) {
for(let j in dependencies) {
graphArray.push(moduleAnalyser(dependencies[j]));
}
}
}
console.log(graphArray, 'graphArray');
const graph = {};
graphArray.forEach(item => {
graph[item.entryFile] = {
dependencies: item.dependencies,
code: item.code
}
})
return graph;
};
- 生成代码:
const generateCode = (entry) => {
const graph = JSON.stringify(makeDependenciesGraph(entry));
// 浏览器可执行的代码里有require方法,有exports对象,bundler.js打包后的代码需要提供一个require方法和exports对象。
// localRequire 传入依赖相对于module的相对路径,根据graph对象,返回依赖相对于bundler.js的相对路径
const bundle = `(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})`
}