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 outthis.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.jslet 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;

  

转载于:https://www.cnblogs.com/piaobodewu/p/11330219.html

[webpack]手写一个mvp版本的webpack相关推荐

  1. android手写简单mvp,[webpack]手写一个mvp版本的webpack

    let fs = require('fs'); let path = require('path'); let babylon = require('babylon'); // Babylon 把源码 ...

  2. 手写一个简易版本的RPC

    前言 在1024程序员节前夕,学习技术是对节日最好的庆祝. 手写一个简易版的RPC,可以把模糊抽象的概念具像化,属于落地层面了. 1. RPC基本原理 RPC原理 2. 四个版本的迭代 注:api表示 ...

  3. 理解webpack原理,手写一个100行的webpack

    什么是webpack 可以引用官网的一幅图解释,我们可以看到webpack,可以分析各个模块的依赖关系,最终打包成我们常见的静态文件,.js . .css . .jpg ..png.今天我们先不弄那么 ...

  4. 未能加载文件或程序集或它的某一个依赖项_手写一个miniwebpack

    前言 之前好友希望能介绍一下 webapck 相关的内容,所以最近花费了两个多月的准备,终于完成了 webapck 系列,它包括一下几部分: webapck 系列一:手写一个 JavaScript 打 ...

  5. 【javascript】手写一个webpack loder

    [javascript]手写一个webpack loder 手写一个loader 为什么需要loader?  webpack 实际上只能处理js文件,那么对于除了js文件的其他类型的文件 比如 css ...

  6. 手写一个简易bundler打包工具带你了解Webpack原理

    用原生js手写一个简易的打包工具bundler

  7. 自己手写一个 VB 的 DateAdd 函数(VB/C 双语言版本)

    可能有些朋友觉得这是多余的事情,既然 VB 有了 DateAdd 函数来进行日期运算,干嘛还要自己手写一个? 其实这一点也不多余,因为有些时候我们的开发环境不一定就在 VB 里,而那些个开发环境不一定 ...

  8. 手写一个promise用法_手写一个 Promise

    1 js 的基本数据类型? 2 JavaScript 有几种类型的值? 3 什么是堆?什么是栈?它们之间有什么区别和联系? 4 内部属性 [Class] 是什么? 5 介绍 js 有哪些内置对象? 6 ...

  9. ES6 手写一个“辨色”小游戏

    1. 前言 依稀记得几年前朋友圈流行的辨色小游戏,找出颜色不同的矩形.前些天突发奇想,打算自己手写一个类似的游戏,话不多说,先上 Demo . --项目源码 本实例基于 ES6 实现,并兼容 ie9及 ...

最新文章

  1. linux查看接口名,在linux下 怎么查看网络接口的名字? 网络接口的名字英文是什么呀?...
  2. CentOS下安装protobuf
  3. vim中开shell
  4. openresty开发系列24--openresty中lua的引入及使用
  5. sprintf,求字符串长度
  6. 记一次 .NET游戏站程序的 CPU 爆高分析
  7. 黑马程序员顺义校区php_黑马程序员:从PHP零基础到月薪11K为何送锦旗给班主任?...
  8. IDEA for Mac 常用快捷键
  9. android 迅雷 好用版本,迅雷不限速版本安卓下载-迅雷不限速版 安卓版v6.6.6-PC6安卓网...
  10. PLC实训 — PLC的27条基本逻辑指令
  11. c++ primer plus 第十四章 C++中的代码重用
  12. 准提咒LA 观想 3D文字
  13. 搭建证书服务并配置Tomcat SSL服务器证书
  14. 在LINLUX下面建立GPRS无线MODEM拨号
  15. #pragma comment 用法
  16. 《红楼梦》的香气韵调
  17. Python获取日期是星期几
  18. 35+了,发奋读书改变命运,还有机会吗?
  19. webgl_gpgpu_birds 样例分析
  20. Cisco忘了enable密码怎么办

热门文章

  1. 【NOIP2005】【Luogu1046】陶陶摘苹果
  2. UVa1587 - Box
  3. java 管道流_Java IO7:管道流、对象流
  4. JAVA入门→下载安装编译执行、变量、数据类型
  5. evt参数是干啥用的_女朋友问我,Java8 Optional 到底干啥用的?
  6. commons-fileupload的ServletFileUpload类
  7. MYSQL MVCC 实现机制
  8. 网络层地址解析协议ARP
  9. Educational Codeforces Round 52: E. Side Transmutations(burnside引理)
  10. 标识符的作用域与可见性