如何实现一个webpack模块解析器
网络编程 2021-07-04 16:46www.168986.cn编程入门
这篇文章主要介绍了如何实现一个webpack模块解析器,长沙网络推广觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随长沙网络推广过来看看吧
最近在学习 webpack源码,由于源码比较复杂,就先梳理了一下整体流程,就参考官网的例子,手写一个最基本的 webpack 模块解析器。
代码很少,github地址:
整体流程分析
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);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持狼蚁SEO。
上一篇:webpack打包非模块化js的方法
下一篇:vue项目中使用Svg的方法
编程语言
- 机械手焊接机器人编程 机械手焊接设备编程
- vb数据库编程实例,vb做数据库
- tiobe世界编程语言排行榜,全球编程语言排行
- 成都java编程培训 成都it编程培训中心
- 编程基础培训,编程基础知识培训
- flash游戏编程基础教程,flash游戏开发教程
- 不会英语能学编程吗 不会英语可以学程序员吗
- 爱心代码编程C语言 爱心代码编程c语言公式
- c语言编程学习入门 c语言编程快速入门
- 西门子plc编程培训 西门子plc编程培训班
- 哪里可以学编程 台州哪里可以学编程
- 少儿编程哪个好 少儿编程哪个品牌好
- 编程是什么意思,图形编程是什么意思
- c语言编程软件下载,c语言编程软件在哪下载
- java编程软件下载,java编程下载手机版
- ug编程培训学校,ug编程培训教程