文章目录
Introduction
Webpack’s async import (dynamic import) enables code splitting and lazy loading. This article analyzes the transformed code to understand how webpack implements async module loading at runtime.
Bundled Runtime Code
Module System Core
// Module storage: maps module ID to module definition
var modules = {};
// Module cache: stores installed/loaded modules
var cache = {};
// Module loading function
function require(moduleId) {
// Return cached module if already loaded
if (cache[moduleId]) {
return cache[moduleId];
}
// Create and cache new module
var module = (cache[moduleId] = { exports: {} });
// Execute module definition, populate exports
modules[moduleId](module, module.exports, require);
return module.exports;
}
// Attach module storage and cache to require function
require.m = modules; // Module definitions
require.c = cache; // Installed modules
Module Definition Helpers
// Mark module as ES module
require.r = exports => {
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
Object.defineProperty(exports, "__esModule", { value: true });
};
// Define getters for exports
require.d = (exports, definition) => {
for (var key in definition) {
Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key],
});
}
};
Chunk Loading Utilities
// Base URL for loading chunks
require.p = "";
// Generate chunk filename from chunk ID
require.u = chunkId => chunkId + ".main.js";
// Create and inject script tag to load chunk
require.l = url => {
let script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
};
Async Chunk Loading
// Track installed/downloading chunks
// Value 0 = installed, array [resolve, reject] = pending
var installedChunks = { main: 0 };
// JSONP callback for chunk loading
require.f.j = (chunkId, promises) => {
var installedChunkData;
// Create promise and store resolve/reject handlers
var promise = new Promise((resolve, reject) => {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
// Store promise in promises array for Promise.all()
promises.push((installedChunkData[2] = promise));
// Load chunk script
var url = require.p + require.u(chunkId);
require.l(url);
};
// Load chunk and return promise
require.e = chunkId => {
let promises = [];
require.f.j(chunkId, promises);
return Promise.all(promises);
};
Global Chunk Loading Callback
// Callback to handle loaded chunk data
var webpackJsonCallback = (chunkIds, moreModules) => {
var resolves = [];
// Resolve all pending promises for loaded chunks
for (var i = 0; i < chunkIds.length; i++) {
var chunkId = chunkIds[i];
resolves.push(installedChunks[chunkId][0]); // Get resolve function
installedChunks[chunkId] = 0; // Mark as installed
}
// Merge new modules into module storage
Object.assign(modules, moreModules);
};
// Setup global array for JSONP chunk loading
var chunkLoadingGlobal = (window["webpackChunk_app_bundle"] = []);
chunkLoadingGlobal.push = webpackJsonCallback; // Override push to trigger callback
Entry Point Usage
// Async load a chunk after 10 seconds
window.setTimeout(() => {
require.e("src_video_js").then(require.bind(null, './src/video.js')).then(() => {
// Chunk loaded, module now available via require()
});
}, 10000);
Lazy Chunk Module Definition
// Chunk module definition (loaded via JSONP)
window["webpackChunk_app_bundle"].push([
["src_video_js"],
{
"./src/video.js": (module, exports, require) => {
require.r(exports);
require.d(exports, {
default: () => DEFAULT_EXPORT,
});
var DEFAULT_EXPORT = "video";
},
},
]);
Loading Flow Summary
- Trigger:
require.e(chunkId)is called - Promise Creation: Create promise with resolve/reject handlers, store in
installedChunks - Script Injection: Create
<script>tag with chunk URL and append to DOM - Chunk Execution: Browser loads and executes chunk script
- JSONP Callback: Chunk calls
window["webpackChunk_app_bundle"].push(), triggeringwebpackJsonCallback - Module Registration: New modules merged into
modulesstorage - Promise Resolution: Pending promises resolved, loading complete
Key Concepts
| Concept | Description |
|---|---|
modules | All module definitions keyed by module ID |
cache | Already loaded modules to avoid re-execution |
installedChunks | Chunk loading state tracking |
require.p | Public path for chunk URLs |
require.l | Script injection for dynamic loading |
| JSONP Pattern | Chunk data pushed via global array callback |