如何实现一个webpack模块解析器


Posted in Javascript onOctober 24, 2018

最近在学习 webpack源码,由于源码比较复杂,就先梳理了一下整体流程,就参考官网的例子,手写一个最基本的 webpack 模块解析器。

代码很少,github地址:手写webpack模块解析器

整体流程分析

1、读取入口文件。

2、将内容转换成 ast 语法树。

3、深度遍历语法树,找到所有的依赖,并加入到一个数组中。

4、将 ast 代码转换回可执行的 js 代码。

5、编写 require 函数,根据入口文件,自动执行完所有的依赖。

6、输出运行结果。

createAsset

// 读取内容并提取它的依赖关系
function createAsset(filename) {
 // 以字符串的形式读取文件
 const content = fs.readFileSync(filename, "utf-8");

 // 转换字符串为ast抽象语法树
 const ast = babylon.parse(content, {
  sourceType: "module"
 });

 const dependencies = [];

 // 遍历抽象语法树
 traverse(ast, {
  // 每当遍历到import语法的时候
  ImportDeclaration: ({ node }) => {
   // 把依赖的模块加入到数组中
   dependencies.push(node.source.value);
  }
 });

 const id = ID++;

 // 转换为浏览器可运行的代码
 const { code } = babel.transformFromAstSync(ast, null, {
  presets: ["@babel/preset-env"]
 });

 return {
  id,
  filename,
  dependencies,
  code
 };
}

createGraph

// 从入口开始,分析所有依赖项,形成依赖图,采用深度优先遍历
function createGraph(entry) {
 const mainAsset = createAsset(entry);

 // 定义一个保存依赖项的数组
 const queue = [mainAsset];

 for (const asset of queue) {
  const dirname = path.dirname(asset.filename);

  // 定义一个保存子依赖项的属性
  asset.mapping = {};

  asset.dependencies.forEach(relativePath => {
   const absolutePath = path.join(dirname, relativePath);

   const child = createAsset(absolutePath);

   // 给子依赖项赋值
   asset.mapping[relativePath] = child.id;

   // 将子依赖也加入队列中,循环处理
   queue.push(child);
  });
 }
 return queue;
}

bundle

// 根据生成的依赖关系图,生成浏览器可执行文件
function bundle(graph) {
 let modules = "";

 // 把每个模块中的代码放在一个function作用域内
 graph.forEach(mod => {
  modules += `${mod.id}:[
   function (require, module, exports){
    ${mod.code}
   },
   ${JSON.stringify(mod.mapping)},
  ],`;
 });

 // require, module, exports 不能直接在浏览器中使用,这里模拟了模块加载,执行,导出操作。
 const result = `
  (function(modules){
   // 创建一个require()函数: 它接受一个 模块ID 并在我们之前构建的模块对象查找它.
   function require(id){
    const [fn, mapping] = modules[id];

    function localRequire(relativePath){
     // 根据mapping的路径,找到对应的模块id
     return require(mapping[relativePath]);
    }

    const module = {exports:{}};

    // 执行转换后的代码,并输出内容。
    fn(localRequire,module,module.exports);

    return module.exports;
   }

   // 执行入口文件
   require(0);

  })({${modules}})
 `;

 return result;
}

执行解析

const graph = createGraph("./entry.js");
const result = bundle(graph);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery插件推荐 jquery.cookie
Nov 09 Javascript
JS逆序遍历实现代码
Dec 02 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
May 09 Javascript
js实现简单的联动菜单效果
Aug 19 Javascript
jQuery如何解决IE输入框不能输入的问题
Oct 08 Javascript
Asp.Net之JS生成分页条的方法
Nov 23 Javascript
Node.js利用debug模块打印出调试日志的方法
Apr 25 Javascript
跟混乱的页面弹窗说再见
Apr 11 Javascript
vue缓存的keepalive页面刷新数据的方法
Apr 23 Javascript
JavaScript, select标签元素左右移动功能实现
May 14 Javascript
js轮播图之旋转木马效果
Oct 13 Javascript
video.js添加自定义组件的方法
Dec 09 Javascript
vue项目中使用Svg的方法
Oct 24 #Javascript
js中获取URL参数的共用方法getRequest()方法实例详解
Oct 24 #Javascript
小程序云开发初探(小结)
Oct 24 #Javascript
vue-cli V3.0版本的使用详解
Oct 24 #Javascript
vue+axios 前端实现登录拦截的两种方式(路由拦截、http拦截)
Oct 24 #Javascript
vue 属性拦截实现双向绑定的实例代码
Oct 24 #Javascript
深入理解JavaScript的值传递和引用传递
Oct 24 #Javascript
You might like
配置Apache2.2+PHP5+CakePHP1.2+MySQL5运行环境
2009/04/25 PHP
PHP 冒泡排序算法的实现代码
2010/08/08 PHP
简单的php写入数据库类代码分享
2011/07/26 PHP
多个PHP中文字符串截取函数
2013/11/12 PHP
ajax+php实现无刷新验证手机号的实例
2017/12/22 PHP
PHP支付宝当面付2.0代码
2018/12/21 PHP
使用onbeforeunload属性后的副作用
2007/03/08 Javascript
Add a Formatted Table to a Word Document
2007/06/15 Javascript
Pro JavaScript Techniques学习笔记
2010/12/28 Javascript
简单实用的反馈表单无刷新提交带验证
2013/11/15 Javascript
js限制checkbox选中个数以限制六个为例
2014/07/15 Javascript
js图片上传前预览功能(兼容所有浏览器)
2016/08/24 Javascript
nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
2016/12/30 NodeJs
jQuery用户头像裁剪插件cropbox.js使用详解
2017/06/07 jQuery
vue环形进度条组件实例应用
2018/10/10 Javascript
如何使用VuePress搭建一个类型element ui文档
2019/02/14 Javascript
Vue的编码技巧与规范使用详解
2019/08/28 Javascript
python数据结构链表之单向链表(实例讲解)
2017/07/25 Python
python OpenCV学习笔记之绘制直方图的方法
2018/02/08 Python
将Django项目部署到CentOs服务器中
2018/10/18 Python
[原创]Python入门教程1. 基本运算【四则运算、变量、math模块等】
2018/10/28 Python
python+adb+monkey实现Rom稳定性测试详解
2020/04/23 Python
html5小技巧之通过document.head获取head元素
2014/06/04 HTML / CSS
Boston Proper官网:美国女装品牌
2017/10/30 全球购物
日本最大的旅游网站:Rakuten Travel(乐天旅游)
2018/08/02 全球购物
Amara德国:家居饰品、设计师品牌和豪华礼品
2019/05/20 全球购物
SNIDEL官网:日本VIVI杂志人气少女第一品牌
2020/03/12 全球购物
优秀毕业生求职推荐信范文
2013/11/21 职场文书
十佳教师事迹材料
2014/01/11 职场文书
求职个人评价范文
2014/04/09 职场文书
学生党员批评与自我批评
2014/10/15 职场文书
个人务虚会发言材料
2014/10/20 职场文书
大学生个人总结范文
2015/02/15 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
《吃水不忘挖井人》教学反思
2016/02/22 职场文书
golang json数组拼接的实例
2021/04/28 Golang