webpack中bundler源码编写
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,这就是我们要做的打包工具
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
npm install @babel/parser --save
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');

这个对象可以很好的表述我当前的这段代码。这个对象里有一个program这样的一个字段,表示当前运行的程序,里面有个body字段,我们可以打印这个字段看一下。
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' ]。
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
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);
这个时候就分析好了文件该有的内容,入口文件,对应的依赖,翻译好的代码。那么接下来就是分析其他的文件
webpack中bundler源码编写的更多相关文章
- webpack中bundler源码编写2
通过第一部分的学习,我们已经可以分析一个js的文件.这节课我们学习Dependencies Graph,也就是依赖图谱.对所有模块进行分析.先分析index.js.index.js里面引入了messg ...
- php中foreach源码分析(编译原理)
php中foreach源码分析(编译原理) 一.总结 编译原理(lex and yacc)的知识 二.php中foreach源码分析 foreach是PHP中很常用的一个用作数组循环的控制语句.因为它 ...
- vue打包时,assets目录 和static目录下文件的处理区别(nodeModule中插件源码修改后,打包后的文件应放在static目录)
为了回答这个问题,我们首先需要了解Webpack如何处理静态资产.在 *.vue 组件中,所有模板和CSS都会被 vue-html-loader 及 css-loader 解析,并查找资源URL.例如 ...
- 【原】Spark中Client源码分析(二)
继续前一篇的内容.前一篇内容为: Spark中Client源码分析(一)http://www.cnblogs.com/yourarebest/p/5313006.html DriverClient中的 ...
- 【原】Spark中Master源码分析(二)
继续上一篇的内容.上一篇的内容为: Spark中Master源码分析(一) http://www.cnblogs.com/yourarebest/p/5312965.html 4.receive方法, ...
- 【原】 Spark中Worker源码分析(二)
继续前一篇的内容.前一篇内容为: Spark中Worker源码分析(一)http://www.cnblogs.com/yourarebest/p/5300202.html 4.receive方法, r ...
- Django缓存机制--rest_framework中节流源码使用的就是django提供的缓存api
一.配置缓存 https://www.jb51.net/article/124434.htm 二.缓存全站.页面.局部 三.自我控制的简单缓存API API 接口为:django.core.c ...
- 深入理解 Node.js 中 EventEmitter源码分析(3.0.0版本)
events模块对外提供了一个 EventEmitter 对象,即:events.EventEmitter. EventEmitter 是NodeJS的核心模块events中的类,用于对NodeJS中 ...
- 从 sourcemap 中获取源码
使用 paazmaya/shuji: Reverse engineering JavaScript and CSS sources from sourcemaps 可以从 sourcemap 中获取源 ...
随机推荐
- Keil MDK仿真调试STM32的时候直接进入SystemInit函数
1. 仿真的时候,进入之后 2. 说是main()未定义,可是明明定义了,什么原因?喔,看错了,是--main.对比了一下和正常工厂的配置,都一样,换个jlink V9测试一下吧.换了个ST LINK ...
- 智能指针.Qt测试
1.Qt598x64vs2017(或 Qt598x86vs2015[配置使用vs2017]).Win10x64 2.测试代码: 2.1.MainWindow.h class MainWindow : ...
- c++ 在Ubuntu系统中使用access函数
include<iostream> #include<stdlib.h> #include<stdio.h> #include<unistd.h> us ...
- feign学习笔记
使用:
- vc编译器对 除法的优化
基本知识,7/2 和 6/2 在计算机中的商都为3.C语言的除法不等同于数学意义中的除法. C语言的除法.采用向零取整的方法. -______________0_______________+ 只有在 ...
- xsy 2018 【NOIP2013】货车运输
[NOIP2013]货车运输 Description A 国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有q辆货车在运输货物,司机们想知道每辆车在不超 ...
- Burp Suite的安装与使用
Burp Suite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对web应用的渗透测试和攻击.在渗透测试中,我们使用Burp Suite将使得测试工作变 ...
- PAT(B) 1084 外观数列(Java)
题目链接:1084 外观数列 (20 point(s)) 题目描述 外观数列是指具有以下特点的整数序列: d, d1, d111, d113, d11231, d112213111, - 它从不等于 ...
- 【自学系列一】HTML5大前端学习路线+视频教程(完整版)
今年,本公司全新发布了囊括Java.HTML5前端.大数据.Python爬虫.全链UI设计.软件测试.Unity 3D.Go语言等多个技术方向的全套视频. 面对这么多的知识点,有的盆友就麻爪了…… 我 ...
- Scratch(三)剪刀石头布
经过上一讲的突击训练,我们从门外汉开始走向编程的深坑,我们今天还要对上一讲的游戏进行加强. 上一个游戏还能演变成什么游戏呢? 我其实知道你们想到的是老hu机什么的,确实,上一个游戏改改可以变成老hu机 ...