webpack系列1--循环依赖解析与处理方式总结

文章首发公众号,欢迎关注
webpack系列1--循环依赖解析与处理方式总结

什么是循环依赖?

一般开发其实不太关注,也不太遇到循环依赖的情况,但是随着项目复杂度增加,尤其是依赖关系复杂的大项目,很容易出现循环依赖的情况,容易产生意想不到的问题,所以今后在编码过程中,要加强这方面的意识。

所谓循环依赖,简单来说,就是 a.js 依赖 b.js 而 b 的脚本执行,又依赖a.js。

用一个demo解释下什么是循环依赖:

webpack.config.js

module.exports = {
    entry: './main.js',
}

mian.js

import a from './a';
console.log(a);

a.js

import b from './b';
export default b;

b.js

import a from './a';
console.log('a:', a); 
export default 1;

执行编译后代码


image.png

webpack 的入口文件为 main.js,随后他们的引用方式为: main.js –> a.js –> b.js –> a.js –> b.js

问题就出在 a.js 被循环引用了,b.js 中导入的 a.js,其引用值为 undefined,虽然我们希望它得到最后的 1 结果。

为什么会发生循环依赖

上面的整个deme会被webpack编译成如下代码

image.png

这个是一个立即执行函数,当浏览器加载js后会被触发执行,立即函数的参数为一个对象,key为依赖的文件路径,value为该文件编译后的内容

并且将入口文件main.js 作为参数传入,执行webpack_require方法,开始整个项目代码的执行

image.png

在这个函数中,做了如下几个事

1、判断全局 installedModules 是否有对应的 moduleId 值,有的话就导出其引用

2、如果没有,就执行 modules[moduleId] 方法,最后返回该模块 module 的引用

也就是说它会执行对应依赖里面的代码,执行后将该依赖再保存到installedModules对象里,下次就不要再执行了

image.png

1、初次调用的时候,installedModules[moduleId] 为空,接着通过 modules[moduleId].call 执行对应的依赖代码。第一个被执行的就是入口文件main.js的代码

2、main.js 里导入了 a.js,则又会调用 webpack_require 方法

3、这里对 a.js 的调用并没有结束(返回值还没有拿到),由于 a.js 中又导入了 b.js,所以又会同上述步骤再执行 b.js 对应的函数。

4、但执行到b这里时就不同了( modules[b.js].call

5、b.js 文件中导入了 a.js 文件,导致 a.js 作为参数又会进入到 webpack_require 方法。

6、因为先前 webpack_require(a.js) 被执行过了,所以在 modules[b.js].call 环节执行 webpack_require(a.js) 中,installedModules[moduleId] 判断为 true 了:

7、而最开始第一次导入 a.js 时,其返回值还没有拿到,所以此时为 true 后,返回值就为 undefined ,这就是问题的出现原因。

image.png

怎么解决?

总结3种处理循环依赖的方法(也欢迎各位小伙伴补充)

  • 单独export一个方法 ⭐️⭐️⭐️
    • 这种适合一个巨无霸对象,某个属性的方法被别的文件引用,别的文件引用的时候是只能全量引入bigObject,然后这样使用bigObject.a(),这种情况下我们可以将方法a,单独抽离出来并export出去,减少循环依赖并使产出最小。
  • 将功能尽可能小的封装在一起,需要某个功能直接按路径引用⭐️⭐️
    • 这种也是适合一个巨无霸对象,但是某个属性的功能是集成了其他对象的某个方法,别的文件引用的时候也只能全量引入bigObject,这种情况下,我们可以将这种功能单独抽离出一个js,然后用路径的方式去引用import a from bigObject/a.js,这样也能减少循环依赖的情况,可能使产出最小。
  • 最小复制原则 ⭐️
    • 有时候循环依赖的环可能是比较长的,我在重构的时候遇见的最长的依赖环是10个文件组成一个闭环,但是如果环中只是因为大家共同引用了一个纯函数工具方法,那我们就干脆霸道的将这个方法复制一份放到某个目录下就好了,推荐指数一颗星。

未雨绸缪:介绍一个插件

circular-dependency-plugin

能够在编译过程中检测项目代码中是否存在循环依赖,如果存在循环依赖就会再控制台输出警告,建议再开发环境下可以配置一个,能够未雨绸缪,毕竟有时候当循环依赖的闭环太长的时候,肉眼是很难区分出来的。

image.png

欢迎小伙伴们补充

以上3种方法是实践中我用来处理循环依赖的,欢迎有其他方法的小伙伴补充哈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容