【敲黑板】手把手带你写一个简易版webpack!内附超详细分解
作者:炸鸡排我们走
来源:SegmentFault 思否社区
明确webpack实现的功能
开始开发
entry.js
import message from './message.js'
console.log(message)
message.js
import name from "./name.js"
export default `${name} is a girl`
name.js
export const name = 'Yolanda'
读取文件需要用到node的一个基础api-fs(文件系统),fs.readFileSync可以同步拿到js文件中的代码内容。
mywebpack.js
const fs = require('fs')
function creatAsset (filename){
const content = fs.readFileSync(filename,'utf-8')
console.log(content)
}
creatAsset('./source/entry.js')
node mywebpack.js
import message from './message.js';
console.log(message);
看一下entry.js文件的ast是什么?
3.2 在program的body属性里, 就是我们各种语法的描述
3.3 可以看到第一个就是 ImportDeclaration, 也就是引入的声明.
3.4 ImportDeclaration里有一个source属性, 它的value就是引入的文件地址 './message.js'
首先安装一个Babylon(基于Babel的js解析工具)
npm i babylon
mywebpack.js
const fs = require('fs');
const babylon = require('babylon');
function createAsset(filename) {
const content = fs.readFileSync(filename, 'utf-8');
const ast = babylon.parse(content, {
sourceType: 'module'
});
console.log(ast);
}
createAsset('./source/entry.js');
首先,需要遍历出ImportDeclaration节点,那就需要一个工具:babel-traverse(可以像遍历对象一样遍历ast中的节点)
npm i babel-traverse
然后利用它遍历并获取到对应节点,提供一个函数来操作此节点。
mywebpack.js
const fs = require('fs');
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
function createAsset(filename) {
const content = fs.readFileSync(filename, 'utf-8');
const ast = babylon.parse(content, {
sourceType: 'module'
});
traverse(ast, {
ImportDeclaration: ({
node
}) => {
console.log(node)
}
})
}
createAsset('./source/entry.js');
可能会出现多个依赖,这里需要建一个数组存储。
mywebpack.js
const fs = require('fs');
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
function createAsset(filename) {
const content = fs.readFileSync(filename, 'utf-8');
const ast = babylon.parse(content, {
sourceType: 'module'
});
const dependencies = [];
traverse(ast, {
ImportDeclaration: ({
node
}) => {
dependencies.push(node.source.value);
}
})
console.log(dependencies);
}
createAsset('./source/entry.js');
mywebpack.js
const fs = require('fs');
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
let ID = 0;
function createAsset(filename) {
const content = fs.readFileSync(filename, 'utf-8');
const ast = babylon.parse(content, {
sourceType: 'module'
});
const dependencies = [];
traverse(ast, {
ImportDeclaration: ({
node
}) => {
dependencies.push(node.source.value);
}
})
const id = ID++;
return {
id,
filename,
dependencies
}
}
const mainAsset = createAsset('./source/entry.js');
console.log(mainAsset);
新建一个createGraph函数,在这个函数里引用createAsset。
同时entry这个参数是动态的,所以createGraph接收entry这个参数。
mywebpack.js - createGraph
function createGraph(entry) {
const mainAsset = createAsset(entry);
}
const graph = createGraph('./source/entry.js');
console.log(graph);
mywebpack.js - createGraph
function createGraph(entry) {
const mainAsset = createAsset(entry);
}
const graph = createGraph('./source/entry.js');
console.log(graph);
我们在dependencies中存储的都是相对路径,但是我们需要绝对路径才能拿到模块的Asset,这个时候要想办法拿到每个模块的绝对路径。
1.path.dirname(获取当前文件的路径名)
2.path.join(拼接路径)
mywebpack.js - createGraph
function createGraph(entry) {
const mainAsset = createAsset(entry);
const allAsset = [mainAsset];
for (let asset of allAsset) {
const dirname = path.dirname(asset.filename);
asset.dependencies.forEach(relativePath => {
const absoultePath = path.join(dirname, relativePath);
const childAsset = createAsset(absoultePath);
});
}
}
map可以存储模块间的依赖关系,方便后续的查找。
mywebpack.js - createGraph
function createGraph(entry) {
const mainAsset = createAsset(entry);
const allAsset = [mainAsset];
for (let asset of allAsset) {
const dirname = path.dirname(asset.filename);
asset.mapping = {};
asset.dependencies.forEach(relativePath => {
const absoultePath = path.join(dirname, relativePath);
const childAsset = createAsset(absoultePath);
asset.mapping[relativePath] = childAsset.id;
});
}
}
关注公众号:拾黑(shiheibook)了解更多
赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号
随时掌握互联网精彩
随时掌握互联网精彩
- PairDrop彻底改变你的多设备文件共享体验
- 韩元汇率对人民币2024年6月16日
- 统信软件受邀出席2023云栖大会,共促中国操作系统创新发展
- 小米最强影像旗舰要来?小米13 Ultra手机壳曝光!
- 中美CPI有何不同?全球正在进入中长期通胀
- 被 Google Play “判定”违反政策:开源软件 FairEmail 开发者一怒之下关停所有项目
- 由数据驱动的生物学和医学革命
- 新华三CR19000落地上海移动城域网出口,打造运营商大网市场新标杆
- 产品上新,供应链下沉,预制菜成为新风口
- 估值超前程无忧和智联招聘之和,BOSS直聘凭什么?
- 13场直播带货476亿,董明珠和格力“交卷”了?
- 统信UOS服务器操作系统V20企业版发布
赞助链接