let fs = require'fs');
let path = require'path');
let babylon = require'babylon'); // Babylon 把源码转换为AST
let t = require'@babel/types'); // @babel-types 替换节点
let traverse = require'@babel/traverse').default; // @babel-traverse 遍历节点
let generator = require'@babel/generator').default; // @babel/generator 生成
let ejs = require'ejs'); // js模版
class Compiler {
// 构造函数
constructorconfig) {
// entry out
this.config = config;
// 1、保存入口文件的路径
this.entryId;
// 2、博阿村所有的模块依赖
this.modules = {};
// 入口路径
this.entry = config.entry;
// 工作路径
this.root = process.cwd);
}
// 获取文件源码
getSourcemodulePath){
let content = fs.readFileSyncmodulePath,'utf8');
return content;
}
// 解析源码
parsesource,parentPath){
// AST解析语法树
let ast = babylon.parsesource);
let dependencies = [];
traverseast,{
CallExpressionp){
let node = p.node; // 对应的节点
ifnode.callee.name === 'require'){
node.callee.name = '__webpack_require__';
let moduleName = node.arguments[0].value; // 取到的就是模块的引用名字
moduleName = moduleName + path.extnamemoduleName)?'':'.js');
moduleName = './'+path.joinparentPath,moduleName);
dependencies.pushmoduleName);
node.arguments = [t.stringLiteralmoduleName)];
}
}
});
let sourceCode = generatorast).code;
return { sourceCode, dependencies }
}
// 建立模块
buildModulemodulePath,isEntry){
// 拿到模块的内容
let source = this.getSourcemodulePath);
// 模块id modulePath modulePath-this.root = src/index.js
let moduleName = './'+path.relativethis.root,modulePath);
ifisEntry){
// 保存入口的名字
this.entryId = moduleName;
}
// 解析需要把source源码进行改造,返回一个依赖列表
let {sourceCode,dependencies} = this.parsesource,path.dirnamemoduleName));
this.modules[moduleName] = sourceCode;
dependencies.forEach
// 父模块的加载,递归加载
dep)=>{
this.buildModulepath.jointhis.root,dep),false)
}
);
}
emitFile){
// 发射文件
// 用数据渲染
// 输出路径
let main = path.jointhis.config.output.path,this.config.output.filename);
// 模板的路径
let tempateStr = this.getSourcepath.join__dirname,'main.ejs'));
let code = ejs.rendertempateStr,{
entryId:this.entryId,
modules: this.modules
});
// this.assets = {};
// // 路径对应的代码
// this.assets[main] = code;
// fs.writeFileSyncmain,this.assets[main]);
fs.writeFileSyncmain,code);
}
run) {
// 执行并创建模块依赖关系
this.buildModulepath.resolvethis.root, this.entry),true);
// 发射一个打包后的文件
this.emitFile);
}
}
module.exports = Compiler;