为了账号安全,请及时绑定邮箱和手机立即绑定

webpack 与循环引用

标签:
前端工具

循环引用的基本表现是:a 文件引入了 b 文件的模块,b 文件引入了 a 文件的模块。也有多个文件的循环引用,比如 a 引入 b 模块,b 引入 c 模块,c 引入 a 模块。

理论上循环引用会导致栈溢出,但并非所有循环引用都会导致栈溢出,比如下例,执行 webpack 打包出的文件,会依次打印:undefined、b、a
图片描述

什么情况下才会导致栈溢出呢?在导出模块中相互调用对方,才会导致栈溢出。比如下面的例子:
图片描述

看看打包出的代码(去除了部分无关代码):

/******/ (function(modules) {
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
          "use strict";
          var __WEBPACK_IMPORTED_MODULE_0__b__ = __webpack_require__(2);

          __webpack_exports__["a"] = (val => {
             Object(__WEBPACK_IMPORTED_MODULE_0__b__["a" /* default */])('a')
             console.log(val)
          });
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
           "use strict";
           Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
           var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);
           // 入口文件
           Object(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */])(1)
/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
           "use strict";
           var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);

           __webpack_exports__["a"] = (val => {
                Object(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* default */])('b')
                console.log(val)
           });
/***/ })
]);

执行顺序:

  • 执行模块 1,执行 __webpack_require__(0)
  • 执行模块 0,执行 __webpack_require__(2)
  • 执行模块 2,模块 2 完成安装(b.js),导出一个函数
  • 继续执行模块 0,模块 0 完成安装(a.js),导出一个函数
  • 继续执行模块 1,执行 (_WEBPACK_IMPORTED_MODULE_0__a__["a"])(1)__WEBPACK_IMPORTED_MODULE_0__a_ 拿到的是对 __webpack_require__(0) 的引用,即:
{
  a: val => {
    Object(__WEBPACK_IMPORTED_MODULE_0__b__["a" ])('a')
    console.log(val)
  }
}

调用 WEBPACK_IMPORTED_MODULE_0__a__["a"] 又会执行 __WEBPACK_IMPORTED_MODULE_0__b__["a"]_WEBPACK_IMPORTED_MODULE_0__b_ 是对 __webpack_require__(2) 的引用,即:

{
  a: val => {
    Object(__WEBPACK_IMPORTED_MODULE_0__a__["a"])('b')
    console.log(val)
  }
}

相当于:

f1 = () => f2();
f2 = () => f1();
f1();

既然 webpack 不会因为循环引用导致打包出错,也就意味着项目中可能隐藏着未知的循环引用,怎么才能知道是否存在循环引用呢?有一个插件可以解决这个问题:circular-dependency-plugin

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
7
获赞与收藏
16

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 1
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消