:::info
💡 dynamic load module
:::
如何动态去加载remote.js
- 创建远端的remoteJs文件,加载远端的资源入口文件
- 获取远端资源变量
loadRemote
动态创建远端remoteJs文件,并且加载
源自官方示例const loadRemote = (remote,shareScope,remoteFallbackUrl = undefined) => {return new Promise((resolve, reject) => {if (!window[remote]) {const existingRemote = document.querySelector(`[data-webpack="${remote}"]`);const onload = async () => {if (!window[remote].__initialized) {// webpack 5中,__webpack_share_scopes__ 必然存在if (typeof __webpack_share_scopes__ === "undefined") {await window[remote].init(shareScope.default);} else {// __webpack_share_scopes__ 会被 编译成 __webpack_require__.S 变量// __webpack_require__.S 存储着 shard 中的资源依赖// window[remote].init 下面会说到await window[remote].init(__webpack_share_scopes__[shareScope]);}window[remote].__initialized = true;}resolve();};if (existingRemote) {existingRemote.onload = onload;existingRemote.onerror = reject;} else if (remoteFallbackUrl) {var d = document,script = d.createElement("script");script.type = "text/javascript";script.setAttribute("data-webpack", `${remote}`);script.async = true;script.onerror = reject;script.onload = onload;script.src = remoteFallbackUrl;d.getElementsByTagName("head")[0].appendChild(script);} else {reject(`Cannot Find Remote ${remote} to inject`);}} else {resolve();}});}
loadComponent
加载完remote资源,就加载需要的组件资源
源自官方示例
const loadComponent = (remote, sharedScope, module, url) => {return async () => {await loadRemote(remote, sharedScope, url);const container = window[remote];// 调用remote中的资源// 方法详情在下面会说const factory = await container.get(module);const Module = factory();return Module;};
小结
动态加载远端资源,需要先加载远端的入口文件remoteJs,加载完成后,可以根据远端资源暴露出来的变量名称,去加载颗粒资源
init/get
webpack内部对remoteJs(远端资源入口文件)做的动态资源的方法
init
var init = (shareScope, initScope) => {// shareScope 是当前执行init时的js上下文的__webpack_require__.S变量// 如果当前的js模块中,缺少__webpack_require__.Sif (!__webpack_require__.S) return;var name = "default"// 获取当前的shard模块var oldScope = __webpack_require__.S[name];// 如果发现不相同,就报错。保证两个shared模块的统一if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");// 注册进当前的__webpack_require__.S__webpack_require__.S[name] = shareScope;// 将host上的的shard资源挂载到当前remotejs中的__webpack_require__.S[name]上// __webpack_require__.I会去判断当前remoteJs中所依赖的是否在host中存在// 如果存在,就返回host中的依赖,否则就会加载自身的依赖return __webpack_require__.I(name, initScope);};
get
// moduleMap 代表当前remote中暴露出的颗粒资源// 类似如下的对象// var moduleMap = {// "./Eexample": () => Promise.all([....])// }// module就是需要的颗粒资源var get = (module, getScope) => {//__webpack_require__.R = getScope;getScope = (// 如果当前存在所需要的模块资源__webpack_require__.o(moduleMap, module)// 就返回promise的资源? moduleMap[module](): Promise.resolve().then(() => {throw new Error('Module "' + module + '" does not exist in container.');}));__webpack_require__.R = undefined;return getScope;};
