const fs = require('fs');
const path = require('path');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const babel = require('@babel/core');
//模块分析 用于分析模块中的依赖 和 将模块中的代码转化成es5的代码
const moduleAnalyser = (filename) => {
//读取文件内容
const content = fs.readFileSync(filename, 'utf-8');
//通过babel-parser将文件内容解析成抽象语法树
const ast = parser.parse(content, {
sourceType: 'module'
});
const dependencies = {};
//通过babel-traverser在抽象语法树中解析出依赖文件路径
traverse(ast, {
ImportDeclaration({ node }) {
const dirname = path.dirname(filename);
const newFile = './' + path.join(dirname, node.source.value);
dependencies[node.source.value] = newFile;
}
});
//使用babel-core和babel-preset-env将抽象语法树转化成es代码
const { code } = babel.transformFromAst(ast, null, {
presets: ["@babel/preset-env"]
});
//返回模块分析结果 模块名 模块依赖文件路径 模块代码
return {
filename,
dependencies,
code
}
}
//通过递归调用模块分析器生成依赖图片 依赖图谱中每个元素都是一个模块 拥有模块名 模块依赖路径 模块代码
const makeDependenciesGraph = (entry) => {
const entryModule = moduleAnalyser(entry);
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])
);
}
}
}
const graph = {};
graphArray.forEach(item => {
graph[item.filename] = {
dependencies: item.dependencies,
code: item.code
}
});
return graph;
}
//最后通过依赖图谱 和重写require exports的方式把所有依赖代码合并完成打包
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/index.js');
console.log(code);
使用babel实现简版webpack
最新推荐文章于 2023-01-04 10:22:10 发布