Default exports circ dep (ES6)

This example assumes you have followed along with the basics, the default export (es5) example and the named exports example.

Note: This example is only valid for target 'es6'. We already covered the default export (es5) example.

We use the exact same source code as in the default export (es5) example.

entry.js
moduleA.js
moduleC.js
moduleB.js

_10
import foo from './moduleA';
_10
_10
console.log(foo);

However we changed the target in the webpack config:

regular/webpack.config.js

_10
module.exports = {
_10
// ... omitted for brevity
_10
target: ['web', 'es5'],
_10
}

regular

_10
module.exports = {
_10
// ... omitted for brevity
_10
target: ['web', 'es6'],
_10
}

How does the circular dependency look like?

We have an import chain where moduleA.js eventually depends on itself:


_10
entry -> moduleA -> moduleC -> moduleB -> moduleA

And moduleA.js define a default export

How does Webpack handle this circular dependency with named exports?

Follow on for a detailed explanation, but in short:

In detail

Full file

Requiring moduleA.js the first time (1)

Similar to the previous examples, Webpack first looks in the cache and does not find a cache entry.

Next, the preliminary exports are set: module.exports = {}

And then the module function is executed.

What is new is that within the module function, there is a bit of code that defines module.exports.default as a getter

Requiring moduleA.js the first time (2)

Similar to the named exports example, this getter is set directly on the module cache.

If we were to set a breakpoint before line 10, the module cache would be:

[Dropdown] module cache with breakpoint before line 10

_10
var __webpack_module_cache__ = {
_10
"./src/regular named export/moduleA.js": {
_10
exports: {
_10
default: function () { return __WEBPACK_DEFAULT_EXPORT__; },
_10
}
_10
}
_10
}

And we also see that __WEBPACK_DEFAULT_EXPORT__ will not be initialized till line 12;

Let's fast forward a bit >>

Requiring moduleA.js the second time (1)

We have recursively called __webpack_require__ a couple of times:

  1. entry -> __webpack_require__('./src/regular es6/moduleA.js')
  2. moduleA -> __webpack_require__('./src/regular es6/moduleC.js')
  3. moduleC -> __webpack_require__('./src/regular es6/moduleB.js')

And we are now about to execute the moduleB.js code

Requiring moduleA.js the second time (2)

There now is a cache hit when requiring moduleA. The cache returns the export object containing the getter.

However when we try to access the getter on line 21, we get an error:

Uncaught ReferenceError: Cannot access 'WEBPACK_DEFAULT_EXPORT' before initialization
dist/main.js

_81
(() => {
_81
"use strict";
_81
var __webpack_modules__ = ({
_81
"./src/regular es6/moduleA.js":
_81
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
_81
__webpack_require__.r(__webpack_exports__);
_81
__webpack_require__.d(__webpack_exports__, {
_81
"default": () => (__WEBPACK_DEFAULT_EXPORT__)
_81
});
_81
var _moduleC__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/regular es6/moduleC.js");
_81
const foo = _moduleC__WEBPACK_IMPORTED_MODULE_0__["default"] + 'bar';
_81
const __WEBPACK_DEFAULT_EXPORT__ = (foo);
_81
}),
_81
"./src/regular es6/moduleB.js":
_81
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
_81
__webpack_require__.r(__webpack_exports__);
_81
__webpack_require__.d(__webpack_exports__, {
_81
"default": () => (__WEBPACK_DEFAULT_EXPORT__)
_81
});
_81
var _moduleA__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/regular es6/moduleA.js");
_81
const bar = _moduleA__WEBPACK_IMPORTED_MODULE_0__["default"] + 'bar';
_81
const __WEBPACK_DEFAULT_EXPORT__ = (bar);
_81
}),
_81
"./src/regular es6/moduleC.js":
_81
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
_81
__webpack_require__.r(__webpack_exports__);
_81
__webpack_require__.d(__webpack_exports__, {
_81
"default": () => (__WEBPACK_DEFAULT_EXPORT__)
_81
});
_81
var _moduleB__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/regular es6/moduleB.js");
_81
const baz = _moduleB__WEBPACK_IMPORTED_MODULE_0__["default"] + 'baz';
_81
const __WEBPACK_DEFAULT_EXPORT__ = (baz);
_81
})
_81
});
_81
_81
var __webpack_module_cache__ = {};
_81
_81
function __webpack_require__(moduleId) {
_81
var cachedModule = __webpack_module_cache__[moduleId];
_81
if (cachedModule !== undefined) {
_81
return cachedModule.exports;
_81
}
_81
var module = __webpack_module_cache__[moduleId] = {
_81
exports: {}
_81
};
_81
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
_81
return module.exports;
_81
}
_81
_81
(() => {
_81
__webpack_require__.d = (exports, definition) => {
_81
for (var key in definition) {
_81
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
_81
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
_81
}
_81
}
_81
};
_81
})();
_81
_81
(() => {
_81
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
_81
})();
_81
_81
(() => {
_81
__webpack_require__.r = (exports) => {
_81
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
_81
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
_81
}
_81
Object.defineProperty(exports, '__esModule', { value: true });
_81
};
_81
})();
_81
_81
var __webpack_exports__ = {};
_81
_81
(() => {
_81
__webpack_require__.r(__webpack_exports__);
_81
var _moduleA__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/regular es6/moduleA.js");
_81
console.log(_moduleA__WEBPACK_IMPORTED_MODULE_0__["default"]);
_81
})();
_81
})()
_81
;

Oops! None of the calls to __webpack_require__() finish, and the default export circular dependency might have just broken your app!

Take aways

  1. Webpack5 with target 'es6' will set a getter for default exports
  2. With target 'es6', when the module which is depending on itself uses a default export, it will throw an error

Next

Can we resolve the getter issue (Cannot access '{{name}}' before initialization) by using functions. Click here to go to the next page.