环境

webpack 5.92.1

代码

// index.js
import { multiple } from "./module-2";

console.log(multiple(1, 2));

const loadModule1 = () => {
  import("./module-1").then(({ add }) => {
    console.log(add(1, 2));
  });
};

loadModule1();

// module-1.js
export const add = (a, b) => {
  return a + b;
};

// module-2.js
export const multiple = (a, b) => {
  return a * b;
};

经过 webpack 编译及打包后,有了打包文件 bundle.js 以及拆分出来的 1.js,接下来直接查看打包后的代码如何实现动态导入的
首先来看下 bundle.js 文件里面的内容
image.png
我们这里可以看到有一个 webpackJsonCallback 的函数,上方还有注释,这个函数就是用于加载 chunk 的 jsonp 的回调函数的定义,至于是加载什么 chunk,一步步地往下看。
红框标注的地方非常重要,webpackJsonpCallback 劫持了 chunkLoadingGlobal.push 函数,即劫持了 self['webpackChunkwebpack_test'].push 函数,同时将原有的 chunkLoadingGlobal.push 函数当做参数传递

开始动态加载模块代码
image.png
webpack 加载模块借助模块索引,上面截图中 1 表示加载的第 1 个异步模块。
首先看下webpack_require.e 干了什么
image.png
发现是遍历webpack_require.f 这个对象的 key,然后返回一个 promise,其中 promises 是传递给webpack_require.f.j,然后在这个函数里面会有 promise 推入到 promises 这个数组里。
image.png
上面这一堆代码看起来很多,简化下来就是先检查 chunk 有没有被加载过,如果没加过的话就构造 chunk 的 url,调用webpack_require.l 函数来请求 chunk。
image.png
webpack 打包过程会对需要动态加载的模块单独分块,利用 jsonp 方式来加载单独分块的 js 文件,即 1.js。
image.png
前面说过 webpackJsonpCallback 劫持了self['webpackChunkwebpack_test'].push函数,在动态加载完 1.js 后,执行 1.js 代码就调用self['webpackChunkwebpack_test'].push函数,实际上就是调用了 webpackJsonpCallback 函数。
image.png
来到 webpackJsonpCallback 函数
image.png
大致做了两件事,一是把动态模块放入到模块数组webpack_modules里面,二是 resolve 在webpack_require.f.j 函数里面生成的 promise,让webpack_require.e 返回的 promise 被 resolve,后面的 then 函数才能往下执行。
最后回到开始加载模块的代码处
image.png
因为在 webpackJsonpCallback 里面把动态模块放到了webpack_modules里面,__webpack_require__.bind(__webpack_require__, 2)能够直接获取到动态模块,然后返回该模块的导出,最终获取 add 函数并执行 add(1, 2),至此整个流程已经结束。


Tqing
112 声望16 粉丝