- Webpack packs modules that reference each other
- The sample project
- Problems encountered
- Why is this a problem
- How to solve
Webpack packs modules that reference each other
The sample project
(github)
Problems encountered
Can’t read Property ‘XXX’ of undefined or (0, XXX) is not a function Can’t read Property ‘XXX’ of undefined or (0, XXX) is not a function
SRC /index.js in the sample project refers to SRC /a.js, and SRC /a.js also refers to SRC /index.jsCopy the code
Why is this a problem
This has to do with the code execution logic packaged with WebPack
In the header startup code of Webpack, the module name or ID is used as the key of the installedModules object in the closure to cache the export value of each module, and the module has been loaded by determining whether the key of the corresponding module is cached on installedModules
// 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__)
Copy the code
There is a problem: When a module is in its first execution state, webPack can assume that a partially loaded module has been loaded if it encounters cross-references
Take the code in export function.js and export const _var.js for example:
export function.js
/ * * * / (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._console = _console;// < -📢 note here
var _a = __webpack_require__(2);
var _a2 = _interopRequireDefault(_a);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _console() {
console.log('this is index.js');
}
/ * * * / }),
Copy the code
export const _var.js
/ * * * / (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._console = undefined;// < -📢 note here
var _a = __webpack_require__(2);
var _a2 = _interopRequireDefault(_a);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _console = exports._console = function _console() {
console.log('this is index.js');
};
/ * * * / }),
Copy the code
As you can see from the 📢 line of the above two codes, the code that uses the assignment statement export will be packaged after the import(__webpack_require__) attribute on exports, and the code that uses the declaration function statement export will be packaged after the import(__webpack_require__) attribute. Assignments to attributes on exports will precede import(that is, __webpack_require__).
This subtle difference can lead to different results than you might expect when executing code that references each other. Consider the following code execution:
- Set the key of index.js on the installedModules object, load index.js and execute
- Meet the import a. s
- Set the key of a.js on the installedModules object, load a.js and execute
- Meet the import index. Js
- InstalledModules already has the index.js key, which reads the cache of exports from that object.
- Execute _console function on exports (error if property has not been assigned yet)
The way of export will affect steps 5 and 6 of the above process
How to solve
- Break the closed loop of dependencies between files
- Export function funcName(){}