Webpack 从 4.6.0+ 开始支持 prefetch,用法如下:
使用 prefetch
const loadAsync = () =>
import(/* webpackChunkName:"async" */ /* webpackPrefetch: true */ './async');
异步模块里面依赖了异步模块并且使用了 webpackPrefetch 才会在打包出来的 runtime 中增加 prefetch 的逻辑。
要理解这个逻辑先把整个 webpack runtime 梳理一遍。
webpack runtime 处理异步 chunk 的逻辑
这里简单总结为一个图:
webpack runtime 处理异步加载 import()
这种是在 __webpack_require__.e
中。
__webpack_require__.e
内部通过 reduce 把多个挂载在 __webpack_require__.f
对象下的处理函数迭代一次,比如
__webpack_require__.f.j
通过 head 插入 script 方式加载 js,里面的逻辑有点复杂__webpack_require__.f.miniCSS
加载 css__webpack_require__.f.prefetch
处理 prefetch
可以把 webpack 通过 reduce 处理
__webpack_require__.f
当作处理中间件,webpack 的插件可以通过在__webpack_require__.f
挂载新的处理函数实现加载模块过程中定制功能。
webpack 打包的时候会分析出来加了 webpackPrefetch: true
的模块加入到 chunkToChildrenMap
中,然后在 __webpack_require__.f.prefetch
查找 map 找到就会通过 link rel prefetch 的方式插入到 head 让浏览器处理。
重复提示一下:异步模块里面依赖了异步模块并且使用了 webpackPrefetch 才会被加入到 chunkToChildrenMap,比如 index.js 如下
XX.js 如下
async.js
(忽略)
这个时候会在 runtime 产生以下代码:
/* webpack/runtime/chunk prefetch trigger */
(() => {
var chunkToChildrenMap = {
XX: ['async'],
};
__webpack_require__.f.prefetch = (chunkId, promises) =>
Promise.all(promises)
.then(() => {
var chunks = chunkToChildrenMap[chunkId];
Array.isArray(chunks) && chunks.map(__webpack_require__.E);
})
.catch(() => {});
})();
在 webpack 通过 __webpack_require__.e
处理异步的 XX.js 模块
__webpack_require__.f.j
加载 XX.js 本身__webpack_require__.f.prefetch
检查 XX.js 内部的 prefetch 模块,找到 async.js 去 prefetch async.js