博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
webpack中bundler源码编写
阅读量:5214 次
发布时间:2019-06-14

本文共 5476 字,大约阅读时间需要 18 分钟。

新建一个项目,再新建一个src文件夹,里面有三个文件,word.js,message.js,index.js

word.js

export const word = 'hello';

message.js

import { word } from './word.js';const message = `say ${word}`;export default message;

index.js

import message from './message.js';console.log(message);

这三个模块通过调用,最后打印出say hello。那我们说,如果直接想src目录下的代码运行下浏览器下,是不可以的;浏览器根本就不认识这种语法。所以我们需要通过webpack类似的打包工具帮助我们进行项目的打包。在根目录下创建一个bundler.js,这就是我们要做的打包工具

 

首先打包工具肯定是用node.js来做开发的,所以需要安装node。用了webpack,肯定是装了node的。
bundler.js
const fs = require('fs'); // 帮助我们获取一些文件的信息// 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  console.log(content);}moduleAnalyser('./src/index.js');

 

运行node bundler.js,输出出来的就是index.js里面的内容。这里在控制台显示的内容,黑色的文本,不是很好看。我们可以安装一个工具 

sudo npm install cli-highlight -g
然后运行 node bundler.js | highlight
这个时候,打印出来的代码就会高亮。

 

拿到文件内容以后。需要分析这个文件里面有哪些依赖,怎么拿到依赖呢?字符串截取可以,但如果很多个模块引入的时候,字符串截取就会显得非常麻烦。我们安装babel的第三方模块帮助我们去分析依赖,安装
npm install @babel/parser --save
安装好之后我们就可以使用了

 

bundler.js
const fs = require('fs'); // 帮助我们获取一些文件的信息const parser = require('@babel/parser'); // 帮助我们分析代码,引入的文件// 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  console.log(parser.parse(content, {    sourceType: 'module' // 说明是es module的引入方式  }));}moduleAnalyser('./src/index.js');

 

这个时候打印出来一个对象。这个对象就是我们听说的一个概念,叫做抽象语法树。也就是ast

 

 

这个对象可以很好的表述我当前的这段代码。这个对象里有一个program这样的一个字段,表示当前运行的程序,里面有个body字段,我们可以打印这个字段看一下。
bundler.js
const fs = require('fs'); // 帮助我们获取一些文件的信息const parser = require('@babel/parser'); // 帮助我们分析代码,引入的文件// 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  const ast = parser.parse(content, {    sourceType: 'module' // 说明是es module的引入方式  })  console.log(ast.program.body);}moduleAnalyser('./src/index.js');

 

 

这个时候打印出来body的两个节点,首先第一个节点ImportDeclaration,确实是import一些东西。也就是引入的声明。第二个节点是ExpressionStatement,是一个表达式的声明,console.log确实是一个表达式的语句。所以通过babel.parser可以分析出抽象语法树。通过抽象语法树,我们就可以找到一些声明的语句,而声明的语句,放置的就是入口文件对应的一些依赖关系。我们可以遍历body,找到ImportDeclaration这样的一些内容,如果自己写一些遍历的话,还是有点麻烦,babel还提供给我们一个模块,可以帮助我们快速的找到import的节点。所以我们需要安装这样的一个模块

npm install @babel/traverse --save

bundler.js

const fs = require('fs'); // 帮助我们获取一些文件的信息const parser = require('@babel/parser'); // 帮助我们分析代码,引入的文件const traverse = require('@babel/traverse').default;// 因为是export出来的内容,必须加一个default属性才可以 // 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  // 利用parser.parse获取到ast  const ast = parser.parse(content, {    sourceType: 'module' // 说明是es module的引入方式  });  // 利用traverse对代码进行一个分析  const dependencies = [];  traverse(ast, {    // 只要抽象语法树有ImportDeclaration就会进入这个方法,node是节点    ImportDeclaration({ node }){      dependencies.push(node.source.value);    }  });  console.log(dependencies);} moduleAnalyser('./src/index.js');

再次运行 node bundler.js | highlight。发现已经打印出了依赖的模块。[ './message.js' ]。

 

这个时候对入口文件对依赖分析就分析出来了。但是这个路径是相对路径,相对于传进来对index.js。在真正做代码打包的时候,我们这些依赖文件他不能是相对路径。他必须是一个绝对路径。或者如果一定要相对路径,也要相对于bundler这个项目,打包才不会有问题。解决这个问题,引入node的另外一个核心模块,叫做path

 

const fs = require('fs'); // 帮助我们获取一些文件的信息const path = require('path'); // 打包的时候需要绝对路径,借助path这个模块const parser = require('@babel/parser'); // 帮助我们分析代码,引入的文件const traverse = require('@babel/traverse').default;// 因为是export出来的内容,必须加一个default属性才可以 // 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  // 利用parser.parse获取到ast  const ast = parser.parse(content, {    sourceType: 'module' // 说明是es module的引入方式  });  // 利用traverse对代码进行一个分析  const dependencies = [];  traverse(ast, {    // 只要抽象语法树有ImportDeclaration就会进入这个方法,node是节点    ImportDeclaration({ node }){      // 拿到filename对应的文件夹路径      const dirname = path.dirname(filename);      // 对这个文件夹的路径进行一个转化,将引入的模块转化成绝对路径      const newFile = path.join(dirname, node.source.value);      console.log(newFile);      dependencies.push(node.source.value);    }  });} moduleAnalyser('./src/index.js');

 

 这个时候打印出来的就是引入的模块的绝对路径。入口文件和相对应的依赖,都可以分析出来了。但是我们的代码,浏览器还是不支持的,需要借助babel去解析我们es6的代码。

安装 
npm install @babel/core --save
这是babel的核心模块
 
bundler.js
const fs = require('fs'); // 帮助我们获取一些文件的信息const path = require('path'); // 打包的时候需要绝对路径,借助path这个模块const parser = require('@babel/parser'); // 帮助我们分析代码,引入的文件const traverse = require('@babel/traverse').default;// 因为是export出来的内容,必须加一个default属性才可以const babel = require('@babel/core'); // babel的核心模块,转化代码,转化成浏览器认识的代码 // 分析模块const moduleAnalyser = (filename) => {  // 读取文件内容  const content = fs.readFileSync(filename, 'utf-8');  // 利用parser.parse获取到ast  const ast = parser.parse(content, {    sourceType: 'module' // 说明是es module的引入方式  });  // 利用traverse对代码进行一个分析  const dependencies = {};  traverse(ast, {    // 只要抽象语法树有ImportDeclaration就会进入这个方法,node是节点    ImportDeclaration({ node }){      // 拿到filename对应的文件夹路径      const dirname = path.dirname(filename);      // 对这个文件夹的路径进行一个转化,将引入的模块转化成相对于bundler的相对路径      const newFile = './' + path.join(dirname, node.source.value);      // 为了方便,把相对路径,绝对路径都存上,key是相对路径,value是绝对路径      dependencies[node.source.value] = newFile;    }  });  // 这个方法可以将抽象语法树转化成浏览器可以运行代码。  const { code } = babel.transformFromAst(ast, null, {    presets: ['@babel/preset-env'] // 把es6语法翻译成es5语法  });  // 返回入口文件和相对应的依赖,都可以分析出来了。  return {    filename,    dependencies,    code  }} const moduleInfo = moduleAnalyser('./src/index.js');console.log(moduleInfo);

这个时候就分析好了文件该有的内容,入口文件,对应的依赖,翻译好的代码。那么接下来就是分析其他的文件

 

转载于:https://www.cnblogs.com/wzndkj/p/10927341.html

你可能感兴趣的文章
Scrum实施日记 - QA很累
查看>>
AC日记——[中山市选2009]谁能赢呢? bzoj 2463
查看>>
python并发编程之协程
查看>>
维吉尼亚密码
查看>>
ubuntu 下使用virtaulbox 以及一些问题
查看>>
laravel 增删改查 数据库设置 路由设置
查看>>
NWERC2016F - Free Weights
查看>>
7.17
查看>>
static使用方法小结
查看>>
Android 布局学习之——Layout(布局)具体解释二(常见布局和布局參数)
查看>>
Quick Tip: How to Add Syntax Highlighting to Any Project
查看>>
BoundsChecker使用
查看>>
深度学习框架Keras
查看>>
十大经典误会
查看>>
(C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单
查看>>
电子书下载:Test Drive ASP.NET MVC
查看>>
DirectInput里的键盘鼠标的应用
查看>>
ASP.NET MVC 拓展ActionResult实现Html To Pdf 导出
查看>>
JavaScript实现依赖注入
查看>>
喝酒游戏,概率分布和卷积
查看>>