问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Webpack原理解析?

发布网友 发布时间:2024-09-26 16:39

我来回答

1个回答

热心网友 时间:2024-11-07 19:20

Webpack是什么?

webpack是静态资源模块化打包工具,通过分析模块间依赖关系,打包出一个或者多个bundle文件

问题思考

什么是模块化,js中模块化包含哪些东西?

webpack是如何分析模块间的依赖关系,最终打包出来?

打包中bundle和chunk的区别是什么?

打包过程中的loader和plugin分别有什么作用?

前置知识

ES6,CommonJS,AMD,CMD等一一些模块化设计规范,有什么异同点

AST语法树

设计步骤

找到入口文件

解析入口文件,提取依赖

递归的创建一个文件间的依赖图,描述所有文件间的依赖关系

把所有的文件打包成一个文件

场景假设(手动实现一个webpack)

场景1

入口文件index.js

依赖文件name.js,person.js

目录结构如下

场景关系依赖分析

index.js(入口)->person.js(依赖)->name.js(依赖)

按照设计步骤,手动实现myWebpack,文件名为myWebpack.js和src同目录

步骤1:找到入口文件

constfs=require("fs");//封装读取文件内容方法functionreadContent(filename){constfileContent=fs.readFileSync(filename,"utf-8");returnfileContent;}//1.找到入口文件constcontent=readContent("./src/index.js");

步骤2:这里需要有一些ast语法树的知识,通俗一点讲就是源码的另一种表现形式,通过对象的形式去描述内容,能够清晰的表现文件内容,依赖关系在线ast转换生成器

观察发现其实就是各种属性表示各种js代码(此过程有词法分析,语法分析啥的)

//2.解析入口文件内容,生成AST语法树(这里通过插件@babel/parser先转义成ast语法树)constastTree=require("@babel/parser").parse(content,{//parseinstrictmodeandallowmoledeclarationssourceType:"mole",plugins:[//enablejsxandflowsyntax"jsx","flow",],});console.log("astTree",astTree);

3.步骤3:深度遍历AST语法树,获取entry.js依赖

//3.babel-traverse作用是像遍历对象一样对AST进行遍历转译,得到新的AST(通过astTree中的astTree->programNode->bodyNode->ImportDeclarationNode->source->value)constdependencies=[];constdeepTraverseAstTree=require("babel-traverse").default(astTree,{//需要遍历语法树中的属性ImportDeclaration:({node})=>{dependencies.push(node.source.value);console.log("node",node);},});

4.步骤4:封装获取所有文件依赖方法,解析入口文件提取依赖

letid=0;functioncreateAsset(filename){constcontent=readContent(filename);constastTree=babylon.parse(content,{sourceType:"mole",});constdependencies=[];babelTraverse(astTree,{//需要遍历语法树中的属性ImportDeclaration:({node})=>{dependencies.push(node.source.value);},});return{id:id++,filename,dependencies,};}constmainAsset=createAsset("./src/index.js");console.log("mainAsset",mainAsset);

步骤5:递归的创建一个文件间的依赖图,需要一个map表示路径和资源的依赖关系

//递归的创建一个文件间的依赖图,需要一个map表示路径和资源的依赖关系functioncreateGraph(entry){constmainAsset=createAsset(entry);//遍历所有的资源文件constallAssets=[mainAsset];for(constassetofallAssets){constdirname=path.dirname(asset.filename);asset.map={};asset.dependencies.forEach(relativePath=>{//转换成绝对路径constabsolutePath=path.join(dirname,relativePath);constchildAsset=createAsset(absolutePath);asset.map[relativePath]=childAsset.id;allAssets.push(childAsset);});}returnallAssets;}constgraph=createGraph("./src/index.js");console.log("graph",graph);

6.步骤6:创建整体的结果代码块,需要接收参数且立即执行,所以定义一个自执行函数包裹,遍历graph拿到所有的mole,以上createAsset方法只获取到了id,filename,dependencies这三个属性只能表示模块间的依赖关系,并未拿到真正的code,所以需要安装插件,通过babel将ast转换成code

//编译所有代码,获取模块内容,并返回codeconst{code}=babel.transformFromAst(astTree,null,{presets:["@babel/preset-env"],});

7.步骤7:经babel编译打包后数据可以分析得出模块需要

function(require,mole,exports){${mole.code}}

步骤8:封装require函数

functionrequire(id){const[fn,map]=moles[id];functionlocalRequire(relativePath){returnrequire(map[relativePath]);}constmole={exports:{}}fn(localRequire,mole,mole.exports)returnmole.exports;}

步骤9:编译源代码,把编译后的代码加入result中

functionbundle(graph){letmoles="";//遍历依赖关系图,拿到将每个模块代码,依赖关系进行组装graph.forEach(mole=>{moles+=`${mole.id}:[function(require,mole,exports){${mole.code}},${JSON.stringify(mole.map)},],`;});//实现require方法,自执行函数,从入口开始引入执行,然后fn(localRequire,mole,mole.exports)加载执行每个模块diamanteconstresult=`(function(moles){functionrequire(id){const[fn,map]=moles[id];functionlocalRequire(relativePath){returnrequire(map[relativePath]);}constmole={exports:{}}fn(localRequire,mole,mole.exports)returnmole.exports;}require(0)})({${moles}})`;returnresult;}总结

什么是模块化,js中模块化包含哪些东西?模块化,就像积木一样,相互独立,有自己的作用范围,通过向外界定义一些接口和方法和外界交互,这样就遵循了开闭原则,单一职责原则可解耦,提高开发效率,提高复用率前端模块化,现在主要是ES6,和CommonJs规范webpack如何分析模块间的依赖关系?

通过插件babel/parser将代码转成ast语法树

通过插件babel/traverse遍历ast语法树拿到每个模块所有依赖

递归并遍历依赖模块,建立文件间的依赖图打包中bundle和chunk的区别是什么?

chunk是webpack打包过程中moles的集合,是打包过程中的概念

bundle是我们最终打包好的一个或者多个文件

大多数情况下,chunk和bundle是一一对应的,但是也有例外,如果加了source-map,一个entry,一个chunk也会产生两个bundle

打包过程中的loader和plugin分别有什么作用?

loader是文件处理器,将各种非js文件,处理成webpack可识别的js和json文件本质上是将所有类型的文件,转换成引用程序的依赖图,可以直接引用的模块

拓展插件,是运行在webpack打包的各个阶段,都会广播自己的事件,然后插件去监听对应的事件,然后去处理一些事情项目地址

原文:https://juejin.cn/post/7099846010456768525
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
微博申请超话认证有哪些要求 申请超话认证要求介绍 土狗一般多大开始懂人性 如何训练 小土狗怎么训练才听话 新手训狗的好方法 跑跑卡丁车故事模式哪一关还海盗船长(人物)奖励的,骨灰玩家说下._百 ... 跑跑卡丁车手游被遗忘的炮塔的宝藏在哪_跑跑卡丁车手游被遗忘的炮塔的... 跑跑卡丁车手游在被遗忘的炮塔附近搜寻宝藏怎么做?遗忘炮塔宝藏攻略... 跑跑卡丁车手游被遗忘炮塔宝藏在哪 炮塔附近搜寻宝箱位置详解-新手攻略... 跑跑卡丁车被遗忘的炮塔附近宝藏在哪里_跑跑卡丁车被遗忘的炮塔附近宝藏... 跑跑卡丁车手游在遗忘的炮塔附近搜寻宝藏在哪 遗忘炮塔宝藏位置详解 迅捷路由器使用问题 如何使用webpack打包文件. 布依族五色花米饭的味道如何? 馁腹的词语馁腹的词语是什么 云米洗衣机门打不开怎么办 云米洗衣机不脱水是什么原因 怎么知道安卓手机的WiFi密码? 京东可以货到分期付款吗 广东培训信息网平台介绍 大培训网网站简介 怎么把手机上不想接到的号码拉黑名单里呢? 从“一朵落花”“一片落叶”“一块石头”中引发的( )和( )。 贷款不能用于什么用途 oppo手机怎么记录步数 违规使用贷款是什么意思 消费贷用途违规后果 怎么在手机桌面显示步数 ...日上午11点整。取2字名,父母同姓詹。(五行,解释)谢谢。 中国医药城普济医院(江苏泰州普济医院)去那当护士好不好 江苏泰州市普济医院(也叫中国医药城医院),我想去那儿做会计(不是坐外面... 在泰州医药城找工作要学什么专业? 非会员怎么看免费视频? 逆向webpack打包后的js(webpack打包umd) 空调室内外机高度差距多少最佳 空调内机高于外机这样装是对的吗有没有什么明确规定 空调内机外机高度是多少合理? 黑龙江江省五七工丧葬费是多少有补偿 柴油车没劲发闷提速慢 柴油车发闷提速无力爬坡无力 河北省邯郸 一年有几个季度分别是哪几个季度 一年有44个季度,1月、2月、3月1月、2月、3月是第一季度,4月、5月... 500字 《草船借剑》缩写 ...ifix自带的vba编程实现与com的直接通信,通信协议自定义,如何... 单片机 和电脑通信 (RS232) 需要特地的去编写驱动吗? 我使用VB_百度知 ... 科普:为什么冬天皮肤更差了? 冬天经常吹空调对身体有害处吗?有的话怎麽做才好呢? 用U深度进pe C盘读不出来 格式化显示无法完成 D盘也是一样 装机未响... 电脑重置失败 然后无法从硬盘启动 u盘也不行 u盘装系统新旧版电脑都进不去怎么回事 u深度PE装系统为什么老是失败? 导航系统传感器