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 {
// 构造函数
constructor(config) {
// entry out
this.config = config;
// 1、保存入口文件的路径
this.entryId;
// 2、博阿村所有的模块依赖
this.modules = {};
// 入口路径
this.entry = config.entry;
// 工作路径
this.root = process.cwd();
}
// 获取文件源码
getSource(modulePath){
let content = fs.readFileSync(modulePath,'utf8');
return content;
}
// 解析源码
parse(source,parentPath){
// AST解析语法树
let ast = babylon.parse(source);
let dependencies = [];
traverse(ast,{
CallExpression(p){
let node = p.node; // 对应的节点
if(node.callee.name === 'require'){
node.callee.name = '__webpack_require__';
let moduleName = node.arguments[0].value; // 取到的就是模块的引用名字
moduleName = moduleName + (path.extname(moduleName)?'':'.js');
moduleName = './'+path.join(parentPath,moduleName);
dependencies.push(moduleName);
node.arguments = [t.stringLiteral(moduleName)];
}
}
});
let sourceCode = generator(ast).code;
return { sourceCode, dependencies }
}
// 建立模块
buildModule(modulePath,isEntry){
// 拿到模块的内容
let source = this.getSource(modulePath);
// 模块id modulePath modulePath-this.root = src/index.js
let moduleName = './'+path.relative(this.root,modulePath);
if(isEntry){
// 保存入口的名字
this.entryId = moduleName;
}
// 解析需要把source源码进行改造,返回一个依赖列表
let {sourceCode,dependencies} = this.parse(source,path.dirname(moduleName));
this.modules[moduleName] = sourceCode;
dependencies.forEach(
// 父模块的加载,递归加载
(dep)=>{
this.buildModule(path.join(this.root,dep),false)
}
);
}
emitFile(){
// 发射文件
// 用数据渲染
// 输出路径
let main = path.join(this.config.output.path,this.config.output.filename);
// 模板的路径
let tempateStr = this.getSource(path.join(__dirname,'main.ejs'));
let code = ejs.render(tempateStr,{
entryId:this.entryId,
modules: this.modules
}); // this.assets = {};
// // 路径对应的代码
// this.assets[main] = code;
// fs.writeFileSync(main,this.assets[main]); fs.writeFileSync(main,code);
}
run() {
// 执行并创建模块依赖关系
this.buildModule(path.resolve(this.root, this.entry),true);
// 发射一个打包后的文件
this.emitFile();
}
} module.exports = Compiler;

  

最新文章

  1. JQuery ajax调用一直回调error函数
  2. window SVN设置忽略文件列表
  3. JS的解析机制
  4. 初步比较zeromq vs. wcf
  5. Paying for upgrades, by Bob Arnson
  6. Node.js笔记3
  7. ZendStudio9之SVN项目代码提示丢失解决
  8. android自定义viewgroup初步之一----抽屉菜单
  9. 图的BFS----迷宫问题
  10. [ffmpeg] 解码API
  11. opencontrail—VXLAN模式下数据包的传输过程
  12. 【转】宽带路由器应用(三)—ARP欺骗防护功能的使用
  13. 在Linux下用C语言实现短信收发
  14. jqgrid取所有行的值,jqgrid取行对应列(name)的值,jqgrid取多行值对应列转json的方法
  15. Linux部署项目
  16. 微信支付 统一下单 字段 body 为中文时 报【签名错误】解决方案(C# SDK)
  17. 一个简单有效的kubernetes部署案例
  18. 《转》Python学习(13)-Python的字符编码
  19. EF---延迟加载技术
  20. day 94 RestFramework序列化组件与视图view

热门文章

  1. Linux 命令之 ln
  2. appium 使用name 定位报错 Locator Strategy 'name' is not supported for this session
  3. wsgiref 与 Django框架初识
  4. stm32 HardFault_Handler调试及问题查找方法——飞思卡尔
  5. 使用jQuery快速高效制作网页交互特效-----JavaScript操作DOM对象
  6. 快速幂C++实现
  7. Mysql5.7.27.msi的下载与安装
  8. 使用Spring PropertyPlaceholderConfigurer 配置中文出现乱码的解决方法
  9. Oracle 通过sqlnet.ora文件控制对Oracle数据库的访问
  10. 067_查看 KVM 虚拟机中的网卡信息(不需要进入启动或进入虚拟机)