1. 概述
1.1 基本概念
MF是在webpack5出来后提出来的新概念,解决模块级别复用问题。简单分为两种应用,
- 生产者(Provider),通过Module federation构建插件设置exposes暴露内部模块给其他应用使用;一个remote仓库。
- 消费者(Consumer),同样通过插件设置remotes消费其他生产者的模块。消费者同样可以作为生产者。

1.2 接入方案
1.2.1 介绍
老版本的mf无法在webpack低版本等不支持module federation的构建插件中消费远程模块,而且导出模块和消费模块都是纯构建行为,加载过程被构建工具插件封装,只需要在代码中引入远程模块进行消费即可。
对原本项目的构建模式要求比较高。所以Module Federation2.0提出了Federation Runtime方法。提供高级Api在代码中动态引入消费远程模块,不受构建框架限制。具体的共享依赖复用、远程模块加载等行为全都封装到Runtime中。
目前Module Federation提供两种注册模块和加载模块的方式:
- 一种是在构建插件中声明(一般是在
module-federation.config.ts 文件中声明) - 另一种方式是直接通过
runtime 的 api 进行模块注册和加载。
| 运行时注册模块 | 插件中注册模块 |
|---|
| 可脱离构建插件使用,在 webpack4 等项目中可直接使用纯运行时进行模块注册和加载 | 构建插件需要是 webpack5 或以上 |
| 支持动态注册模块 | 不支持动态注册模块 |
| 不支持 import 语法加载模块 | 支持 import 同步语法加载模块 |
| 支持 loadRemote 加载模块 | 支持 loadRemote 加载模块 |
| 设置 shared 必须提供具体版本和实例信息 | 设置 shared 只需要配置规则即可,无须提供具体版本及实例信息 |
| shared 依赖只能供外部使用,无法使用外部 shared 依赖 | shared 依赖按照特定规则双向共享 |
| 可以通过 runtime 的 plugin 机制影响加载流程 | 目前不支持提供 plugin 影响加载流程 |
| 不支持远程类型提示 | 支持远程类型提示 |
1.2.2 构建时接入
在构建工具对应的配置项中,增加module-federation插件配置
1.2.2.1 消费者配置
1.2.2.1.1 webpack构建配置
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = (env = {}) => ({
mode: 'development',
cache: false,
...
plugins: [
new ModuleFederationPlugin({
name: 'layout',
filename: 'remoteEntry.js',
remotes: {
home: 'home@http://localhost:3002/remoteEntry.js',
},
exposes: {},
shared: {
vue: {
singleton: true,
},
},
}),
],
})
1.2.2.1.2 页面引入
const Content = defineAsyncComponent(() => import('home/Content'));
const Button = defineAsyncComponent(() => import('home/Button'));
1.2.2.2 生产者webpack配置
这里生产者通过配置exposes导出了Content和Button两个组件。
1.2.2.2.1 webpack构建配置
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = (env = {}) => ({
mode: 'development',
cache: false,
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new ModuleFederationPlugin({
name: 'home',
filename: 'remoteEntry.js',
remotes: {
home: 'home@http://localhost:3002/remoteEntry.js',
},
exposes: {
'./Content': './src/components/Content',
'./Button': './src/components/Button',
},
shared: {
vue: {
singleton: true,
},
},
}),
],
});
1.2.3 Runtime接入
对于消费者提供了js api进行模块注册和模块加载,可以脱离构建插件使用,在 webpack4 等项目中可直接使用纯运行时进行模块注册和加载。生产者还是用对应的构建插件进行配置,需要单独打包出remoteEntry.js入口文件
1.2.3.1 核心API
1.2.3.1.1 Init
<!---->
// 可以只使用运行时加载模块,而不依赖于构建插件
// 当不使用构建插件时,共享的依赖项不能自动设置细节
import { init, loadRemote } from '@module-federation/enhanced/runtime';
init({
name: '@demo/app-main',
remotes: [
{
name: "@demo/app1",
// mf-manifest.json 是在 Module federation 新版构建工具中生成的文件类型,对比 remoteEntry 提供了更丰富的功能
// 预加载功能依赖于使用 mf-manifest.json 文件类型
entry: "http://localhost:3005/mf-manifest.json",
alias: "app1"
},
{
name: "@demo/app2",
entry: "http://localhost:3006/remoteEntry.js",
alias: "app2"
},
],
});
// 使用别名加载
loadRemote<{add: (...args: Array<number>)=> number }>("app2/util").then((md)=>{
md.add(1,2,3);
});
1.2.3.1.2 loadRemote
- 用于加载初始化的远程模块,当与构建插件一起使用时,它可以通过原生的
import("remote name/expose")语法直接加载,并且构建插件会自动将其转换为loadRemote("remote name/expose")用法。
<!---->
import { init, loadRemote } from '@module-federation/enhanced/runtime';
init({
name: '@demo/main-app',
remotes: [
{
name: '@demo/app2',
alias: 'app2',
entry: 'http://localhost:3006/remoteEntry.js',
},
],
});
// remoteName + expose
loadRemote('@demo/app2/util').then((m) => m.add(1, 2, 3));
// alias + expose
loadRemote('app2/util').then((m) => m.add(1, 2, 3));
1.2.3.1.3 registerRemotes
<!---->
function registerRemotes(remotes: Remote[], options?: { force?: boolean }) {}
type Remote = (RemoteWithEntry | RemoteWithVersion) & RemoteInfoCommon;
interface RemoteInfoCommon {
alias?: string;
shareScope?: string;
type?: RemoteEntryType;
entryGlobalName?: string;
}
interface RemoteWithEntry {
name: string;
entry: string;
}
interface RemoteWithVersion {
name: string;
version: string;
}
1.2.3.1.4 registerPlugins
<!---->
import { registerPlugins } from '@module-federation/enhanced/runtime'
import runtimePlugin from 'custom-runtime-plugin.ts';
registerPlugins([runtimePlugin()]);
1.3 调试工具
1.3.1 安装Module Federation插件
https://chromewebstore.google.com/detail/module-federation/ae...

1.3.2 插件提供了Devtools面板

1.3.3 查看远程依赖关系

2. 实战示例
介绍一下 简单的host-remote模式开发,及开发体验
官方发布的module-federation-examples,包含了很多不同构建框架之间结合使用的场景,
这里我们主要拿一个最简单的demo查看使用,依赖关系简单,方便对照分析后面的原理解析部分。
module-federation-examples/vue3-demo at master · module-federation/module-federation-examples
2.1 项目目录
项目可以拆分成两个文件夹
- home: 生产者,暴露出来Content和Button组件给外部使用,同时配置了共享库vue,设置singleton: true
- Layout: 消费者,也就是host,消费home项目暴露出来的Content和Button,也配置了vue共享库
<!---->
vue3-demo/
├── home(remote)
│ ├── src
│ │ ├── App.vue -- 入口组件 components: { Content: defineAsyncComponent(() => import('./components/Content')),
│ │ ├── components
│ │ │ ├── Button.js。 -- 业务组件Button
│ │ │ └── Content.vue -- 业务组件Content
│ │ ├── index.js. -- import('./main.js');
│ │ └── main.js -- const app = createApp(App);app.mount('#app');
│ └── webpack.config.js -- expose:{Content, Button}
│
├── layout(host)
│ ├── src
│ │ ├── Layout.vue -- 使用业务组件Content,
│ │ ├── index.js -- import('./main.js');
│ │ └── main.js -- const Content = defineAsyncComponent(() => import('home/Content'));
│ └── webpack.config.js -- remotes:{home: 'home@http://home.com/remoteEntry.js'}
└── package.json
2.2 核心代码块
2.2.1 Remote
2.2.1.1 src/index.js
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
import('./main.js');
2.2.1.2 src/main.js
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
2.2.1.3 webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = (env = {}) => ({
target: 'web',
entry: path.resolve(__dirname, './src/index.js'),
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new ModuleFederationPlugin({
name: 'home',
filename: 'remoteEntry.js',
remotes: {
home: 'home@http://localhost:3002/remoteEntry.js',
},
exposes: {
'./Content': './src/components/Content',
'./Button': './src/components/Button',
},
shared: {
vue: {
singleton: true,
},
},
}),
],
devServer: {
port: 3002,
},
});
2.2.2 Host
<!---->
2.2.2.1 src/index.js
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
import('./main.js');
2.2.2.2 src/main.js
import { createApp, defineAsyncComponent } from 'vue';
import Layout from './Layout.vue';
const Content = defineAsyncComponent(() => import('home/Content'));
const Button = defineAsyncComponent(() => import('home/Button'));
const app = createApp(Layout);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
2.2.2.3 wepback.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = (env = {}) => ({
entry: path.resolve(__dirname, './src/index.js'),
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new ModuleFederationPlugin({
name: 'layout',
filename: 'remoteEntry.js',
remotes: {
home: 'home@http://localhost:3002/remoteEntry.js',
},
exposes: {},
shared: {
vue: {
singleton: true,
},
},
}),
],
devServer: {
port: 3001,
},
});
2.3 示例截图

3. 原理分析
not magic, just async chunk
大白话解释一下,共享组件单独打包成一个异步chunk里面,共享的依赖会在加载组件之前进行前置加载,中间有一些复杂的依赖版本号比较,依赖库加载的逻辑通过shared字段进行配置。
这里的加载模块流程分析准备分三部分,首先介绍最基础的webpack异步模块加载流程,后面分别介绍module federation两个引入方式对应不同的加载流程
3.1 webpack异步模块加载流程
3.1.1 按需加载
按需加载,也叫异步加载、动态导入,即只在有需要的时候才去下载相应的资源文件。
在 webpack 中可以使用 import 和 require.ensure 来引入需要动态导入的代码,还是用前面的vue3-demo示例,现在只关注home目录,并且把webpack配置中的ModuleFederationPlugin插件去掉。
home文件夹目录结构
vue3-demo/
├── home(remote)
│ ├── src
│ │ ├── App.vue -- 入口组件 components: { Content: defineAsyncComponent(() => import('./components/Content')),
│ │ ├── components
│ │ │ ├── Button.js -- 业务组件Button
│ │ │ └── Content.vue -- 业务组件Content
│ │ ├── index.js. -- import('./main.js');
│ │ └── main.js -- const app = createApp(App);app.mount('#app');
│ └── webpack.config.js
App.vue组件里面进行组件注册时,使用import方法引入
components: {
Content: defineAsyncComponent(() => import('./components/Content')),
Button: defineAsyncComponent(() => import('./components/Button')),
},
本地开发环境配置修改后,重新进行构建,可以看到从请求html到后续的js、css文件加载顺序。
3.1.2 初始化请求链路
3.1.3 源码与构建后代码对照
<!---->
3.1.3.1 入口html文件
3.1.3.1.1 源码
<div id="app"></div>
3.1.3.1.2 构建后代码
<head>
<script defer src="main.js"></script>
</head>
<div id="app"></div>
3.1.3.2 入口index.js文件
3.1.3.2.1 源码
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
import('./main.js');
3.1.3.2.2 构建后代码
构建后的startUp 入口函数
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
**********************/
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_pnpm_mini-css-extract-plugin_2_9_2_webpack_5_96_1__swc_core_1_9_2_webpac-fe6f3f"), __webpack_require__.e("src_main_js")]).then(__webpack_require__.bind(__webpack_require__, /*! ./main.js */ "./src/main.js"));
/***/ })
})
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
/******/ __webpack_require__.i.forEach(function(handler) { handler(execOptions); });
/******/ module = execOptions.module;
/******/ execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = __webpack_module_cache__;
/******/
/******/ // expose the module execution interceptor
/******/ __webpack_require__.i = [];
/******/
/************************************************************************/
/******/
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/get javascript chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.u = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return "" + chunkId + ".js";
/******/ };
/******/ })();
/******/
/******/
/******/ /* webpack/runtime/get mini-css chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.miniCssF = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return "" + chunkId + ".css";
/******/ };
/******/ })();
/******/
/******/
/******/
/******/ /* webpack/runtime/load script */
/******/ (() => {
/******/ var inProgress = {};
/******/ var dataWebpackPrefix = "vue3-demo_home:";
/******/ // loadScript function to load a script via script tag
/******/ __webpack_require__.l = (url, done, key, chunkId) => {
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
/******/ var script, needAttach;
/******/ if(key !== undefined) {
/******/ var scripts = document.getElementsByTagName("script");
/******/ for(var i = 0; i < scripts.length; i++) {
/******/ var s = scripts[i];
/******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
/******/ }
/******/ }
/******/ if(!script) {
/******/ needAttach = true;
/******/ script = document.createElement('script');
/******/
/******/ script.charset = 'utf-8';
/******/ script.timeout = 120;
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
/******/
/******/ script.src = url;
/******/ }
/******/ inProgress[url] = [done];
/******/ var onScriptComplete = (prev, event) => {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var doneFns = inProgress[url];
/******/ delete inProgress[url];
/******/ script.parentNode && script.parentNode.removeChild(script);
/******/ doneFns && doneFns.forEach((fn) => (fn(event)));
/******/ if(prev) return prev(event);
/******/ }
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ script.onload = onScriptComplete.bind(null, script.onload);
/******/ needAttach && document.head.appendChild(script);
/******/ };
/******/ })();
/******/
/******/
/******/
/******/ /* webpack/runtime/css loading */
/******/ (() => {
/******/ if (typeof document === "undefined") return;
/******/ var createStylesheet = (chunkId, fullhref, oldTag, resolve, reject) => {
/******/ var linkTag = document.createElement("link");
/******/
/******/ linkTag.rel = "stylesheet";
/******/ linkTag.type = "text/css";
/******/ if (__webpack_require__.nc) {
/******/ linkTag.nonce = __webpack_require__.nc;
/******/ }
/******/ var onLinkComplete = (event) => {
/******/ // avoid mem leaks.
/******/ linkTag.onerror = linkTag.onload = null;
/******/ if (event.type === 'load') {
/******/ resolve();
/******/ } else {
/******/ var errorType = event && event.type;
/******/ var realHref = event && event.target && event.target.href || fullhref;
/******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + errorType + ": " + realHref + ")");
/******/ err.name = "ChunkLoadError";
/******/ err.code = "CSS_CHUNK_LOAD_FAILED";
/******/ err.type = errorType;
/******/ err.request = realHref;
/******/ if (linkTag.parentNode) linkTag.parentNode.removeChild(linkTag)
/******/ reject(err);
/******/ }
/******/ }
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
/******/ document.head.appendChild(linkTag);
/******/ }
/******/ return linkTag;
/******/ };
/******/ var findStylesheet = (href, fullhref) => {
/******/ var existingLinkTags = document.getElementsByTagName("link");
/******/ for(var i = 0; i < existingLinkTags.length; i++) {
/******/ var tag = existingLinkTags[i];
/******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
/******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return tag;
/******/ }
/******/ var existingStyleTags = document.getElementsByTagName("style");
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
/******/ var tag = existingStyleTags[i];
/******/ var dataHref = tag.getAttribute("data-href");
/******/ if(dataHref === href || dataHref === fullhref) return tag;
/******/ }
/******/ };
/******/ var loadStylesheet = (chunkId) => {
/******/ return new Promise((resolve, reject) => {
/******/ var href = __webpack_require__.miniCssF(chunkId);
/******/ var fullhref = __webpack_require__.p + href;
/******/ if(findStylesheet(href, fullhref)) return resolve();
/******/ createStylesheet(chunkId, fullhref, null, resolve, reject);
/******/ });
/******/ }
/******/ // object to store loaded CSS chunks
/******/ var installedCssChunks = {
/******/ "main": 0
/******/ };
/******/
/******/ __webpack_require__.f.miniCss = (chunkId, promises) => {
/******/ var cssChunks = {"src_main_js":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
/******/ promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(() => {
/******/ installedCssChunks[chunkId] = 0;
/******/ }, (e) => {
/******/ delete installedCssChunks[chunkId];
/******/ throw e;
/******/ }));
/******/ }
/******/ };
/******/
/******/ var oldTags = [];
/******/ var newTags = [];
/******/ var applyHandler = (options) => {
/******/ return { dispose: () => {
/******/ for(var i = 0; i < oldTags.length; i++) {
/******/ var oldTag = oldTags[i];
/******/ if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);
/******/ }
/******/ oldTags.length = 0;
/******/ }, apply: () => {
/******/ for(var i = 0; i < newTags.length; i++) newTags[i].rel = "stylesheet";
/******/ newTags.length = 0;
/******/ } };
/******/ }
/******/ __webpack_require__.hmrC.miniCss = (chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) => {
/******/ applyHandlers.push(applyHandler);
/******/ chunkIds.forEach((chunkId) => {
/******/ var href = __webpack_require__.miniCssF(chunkId);
/******/ var fullhref = __webpack_require__.p + href;
/******/ var oldTag = findStylesheet(href, fullhref);
/******/ if(!oldTag) return;
/******/ promises.push(new Promise((resolve, reject) => {
/******/ var tag = createStylesheet(chunkId, fullhref, oldTag, () => {
/******/ tag.as = "style";
/******/ tag.rel = "preload";
/******/ resolve();
/******/ }, reject);
/******/ oldTags.push(oldTag);
/******/ newTags.push(tag);
/******/ }));
/******/ });
/******/ }
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = __webpack_require__.hmrS_jsonp = __webpack_require__.hmrS_jsonp || {
/******/ "main": 0
/******/ };
/******/
/******/ __webpack_require__.f.j = (chunkId, promises) => {
/******/ // JSONP chunk loading for javascript
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ if(true) { // all chunks have JS
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ if(installedChunkData) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ installedChunkData[1](error);
/******/ }
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ }
/******/ }
/******/ }
/******/ };
/******/
/******/ // no prefetching
/******/
/******/
/******/
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // module cache are used so entry inlining is disabled
/******/ // startup
/******/ // Load entry module and return exports
/******/ __webpack_require__("../../node_modules/.pnpm/webpack-dev-server@5.0.4_webpack-cli@5.1.4_webpack@5.96.1/node_modules/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=0.0.0.0&port=3002&pathname=%2Fws&logging=info&overlay=true&reconnect=10&hot=true&live-reload=true");
/******/ __webpack_require__("../../node_modules/.pnpm/webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4/node_modules/webpack/hot/dev-server.js");
/******/ var __webpack_exports__ = __webpack_require__("./src/index.js");
/******/
/******/ })()
;
//# sourceMappingURL=main.js.map
3.1.3.3 main.js文件
<!---->
3.1.3.3.1 源码
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
3.1.3.3.2 构建后代码
"use strict";
(self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || []).push([["src_main_js"], {
/***/
"../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-2.use[0]!../../node_modules/.pnpm/css-loader@7.1.2_@rspack+core@1.1.1_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/css-loader/dist/cjs.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/stylePostLoader.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css": /*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-2.use[0]!../../node_modules/.pnpm/css-loader@7.1.2_@rspack+core@1.1.1_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/css-loader/dist/cjs.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/stylePostLoader.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css ***!
*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/
( (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
if (true) {
(function() {
var localsJsonString = undefined;
// 1758629789554
var cssReload = __webpack_require__(/*! ../../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/hmr/hotModuleReplacement.js */
"../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/hmr/hotModuleReplacement.js")(module.id, {});
// only invalidate when locals change
if (module.hot.data && module.hot.data.value && module.hot.data.value !== localsJsonString) {
module.hot.invalidate();
} else {
module.hot.accept();
}
module.hot.dispose(function(data) {
data.value = localsJsonString;
cssReload();
});
}
)();
}
/***/
}
),
/***/
"./src/App.vue": /*!*********************!*\
!*** ./src/App.vue ***!
*********************/
/***/
( (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (__WEBPACK_DEFAULT_EXPORT__)/* harmony export */
});
/* harmony import */
var _App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./App.vue?vue&type=template&id=7ba5bd90&scoped=true */
"./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true");
/* harmony import */
var _App_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./App.vue?vue&type=script&lang=js */
"./src/App.vue?vue&type=script&lang=js");
/* harmony import */
var _App_vue_vue_type_style_index_0_id_7ba5bd90_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css */
"./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css");
/* harmony import */
var _Users_liqi_fe_module_federation_examples_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js");
;
const __exports__ = /*#__PURE__*/
(0,
_Users_liqi_fe_module_federation_examples_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__["default"])(_App_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__["default"], [['render', _App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render], ['__scopeId', "data-v-7ba5bd90"], ['__file', "src/App.vue"]])
/* hot reload */
if (true) {
__exports__.__hmrId = "7ba5bd90"
const api = __VUE_HMR_RUNTIME__
module.hot.accept()
if (!api.createRecord('7ba5bd90', __exports__)) {
console.log('reload')
api.reload('7ba5bd90', __exports__)
}
module.hot.accept(/*! ./App.vue?vue&type=template&id=7ba5bd90&scoped=true */
"./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true", __WEBPACK_OUTDATED_DEPENDENCIES__ => {
/* harmony import */
_App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./App.vue?vue&type=template&id=7ba5bd90&scoped=true */
"./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true");
( () => {
console.log('re-render')
api.rerender('7ba5bd90', _App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render)
}
)(__WEBPACK_OUTDATED_DEPENDENCIES__);
}
)
}
/* harmony default export */
const __WEBPACK_DEFAULT_EXPORT__ = (__exports__);
/***/
}
),
/***/
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=script&lang=js": /*!*****************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=script&lang=js ***!
*****************************************************************************************************************************************************************************************************************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (__WEBPACK_DEFAULT_EXPORT__)/* harmony export */
});
/* harmony import */
var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */
"../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
// import Content from "./components/Content";
// import Button from "./components/Button";
/* harmony default export */
const __WEBPACK_DEFAULT_EXPORT__ = ({
components: {
Content: (0,
vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)( () => __webpack_require__.e(/*! import() */
"src_components_Content_vue").then(__webpack_require__.bind(__webpack_require__, /*! ./components/Content */
"./src/components/Content.vue"))),
Button: (0,
vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)( () => __webpack_require__.e(/*! import() */
"src_components_Button_js").then(__webpack_require__.bind(__webpack_require__, /*! ./components/Button */
"./src/components/Button.js"))),
},
// components: {
// Content,
// Button,
// },
setup() {
const count = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.ref)(0);
const inc = () => {
count.value++;
}
;
return {
count,
inc,
};
},
});
/***/
}
),
/***/
"./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css": /*!*****************************************************************************!*\
!*** ./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css ***!
*****************************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var _node_modules_pnpm_mini_css_extract_plugin_2_9_2_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_mini_css_extract_plugin_dist_loader_js_clonedRuleSet_2_use_0_node_modules_pnpm_css_loader_7_1_2_rspack_core_1_1_1_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_css_loader_dist_cjs_js_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_App_vue_vue_type_style_index_0_id_7ba5bd90_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-2.use[0]!../../../node_modules/.pnpm/css-loader@7.1.2_@rspack+core@1.1.1_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/css-loader/dist/cjs.js!../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css */
"../../node_modules/.pnpm/mini-css-extract-plugin@2.9.2_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-2.use[0]!../../node_modules/.pnpm/css-loader@7.1.2_@rspack+core@1.1.1_webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/css-loader/dist/cjs.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/stylePostLoader.js!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css");
/***/
}
),
/***/
"./src/App.vue?vue&type=script&lang=js": /*!*********************************************!*\
!*** ./src/App.vue?vue&type=script&lang=js ***!
*********************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (/* reexport safe */
_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_App_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__["default"])/* harmony export */
});
/* harmony import */
var _node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_App_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./App.vue?vue&type=script&lang=js */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=script&lang=js");
/***/
}
),
/***/
"./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true": /*!***************************************************************!*\
!*** ./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true ***!
***************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
render: () => (/* reexport safe */
_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_1_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render)/* harmony export */
});
/* harmony import */
var _node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_1_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./App.vue?vue&type=template&id=7ba5bd90&scoped=true */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true");
/***/
}
),
/***/
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true": /*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true ***!
*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
render: () => (/* binding */
render)/* harmony export */
});
/* harmony import */
var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */
"../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
const _withScopeId = n => ((0,
vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)("data-v-7ba5bd90"),
n = n(),
(0,
vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(),
n)
const _hoisted_1 = /*#__PURE__*/
_withScopeId( () => /*#__PURE__*/
(0,
vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "Main App", -1 /* HOISTED */
))
function render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_Content = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("Content")
const _component_Button = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("Button")
return ((0,
vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(),
(0,
vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", null, [_hoisted_1, (0,
vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_Content), (0,
vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_Button)]))
}
/***/
}
),
/***/
"./src/main.js": /*!*********************!*\
!*** ./src/main.js ***!
*********************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */
"../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
/* harmony import */
var _App_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./App.vue */
"./src/App.vue");
const app = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.createApp)(_App_vue__WEBPACK_IMPORTED_MODULE_1__["default"]);
app.mount('#app');
/***/
}
)
}]);
//# sourceMappingURL=src_main_js.js.map
3.1.3.4 button.js组件文件
<!---->
3.1.3.4.1 源码
import { render, h } from 'vue';
const button = {
name: 'btn-component',
render() {
return h(
'button',
{
id: 'btn-primary',
},
'Hello World',
);
},
};
export default button;
3.1.3.4.2 构建后代码
"use strict";
(self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || []).push([["src_components_Button_js"],{
/***/ "./src/components/Button.js":
/*!**********************************!*\
!*** ./src/components/Button.js ***!
**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
const button = {
name: 'btn-component',
render() {
return (0,vue__WEBPACK_IMPORTED_MODULE_0__.h)(
'button',
{
id: 'btn-primary',
},
'Hello World',
);
},
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (button);
/***/ })
}]);
//# sourceMappingURL=src_components_Button_js.js.map
3.1.3.5 Content.vue组件文件
<!---->
3.1.3.5.1 源码
<template>
<div style="color: red">{{ title }}</div>
</template>
<script>
export default {
data() {
return {
title: 'Remote Component in Action..',
};
},
};
</script>
3.1.3.5.2 构建后代码
"use strict";
(self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || []).push([["src_components_Content_vue"], {
/***/
"./src/components/Content.vue": /*!************************************!*\
!*** ./src/components/Content.vue ***!
************************************/
/***/
( (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (__WEBPACK_DEFAULT_EXPORT__)/* harmony export */
});
/* harmony import */
var _Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Content.vue?vue&type=template&id=7eab81f9 */
"./src/components/Content.vue?vue&type=template&id=7eab81f9");
/* harmony import */
var _Content_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Content.vue?vue&type=script&lang=js */
"./src/components/Content.vue?vue&type=script&lang=js");
/* harmony import */
var _Users_liqi_fe_module_federation_examples_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js");
;const __exports__ = /*#__PURE__*/
(0,
_Users_liqi_fe_module_federation_examples_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_2__["default"])(_Content_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__["default"], [['render', _Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__.render], ['__file', "src/components/Content.vue"]])
/* hot reload */
if (true) {
__exports__.__hmrId = "7eab81f9"
const api = __VUE_HMR_RUNTIME__
module.hot.accept()
if (!api.createRecord('7eab81f9', __exports__)) {
console.log('reload')
api.reload('7eab81f9', __exports__)
}
module.hot.accept(/*! ./Content.vue?vue&type=template&id=7eab81f9 */
"./src/components/Content.vue?vue&type=template&id=7eab81f9", __WEBPACK_OUTDATED_DEPENDENCIES__ => {
/* harmony import */
_Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Content.vue?vue&type=template&id=7eab81f9 */
"./src/components/Content.vue?vue&type=template&id=7eab81f9");
( () => {
console.log('re-render')
api.rerender('7eab81f9', _Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__.render)
}
)(__WEBPACK_OUTDATED_DEPENDENCIES__);
}
)
}
/* harmony default export */
const __WEBPACK_DEFAULT_EXPORT__ = (__exports__);
/***/
}
),
/***/
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=script&lang=js": /*!********************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=script&lang=js ***!
********************************************************************************************************************************************************************************************************************************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (__WEBPACK_DEFAULT_EXPORT__)/* harmony export */
});
/* harmony default export */
const __WEBPACK_DEFAULT_EXPORT__ = ({
data() {
return {
title: 'Remote Component in Action..',
};
},
});
/***/
}
),
/***/
"./src/components/Content.vue?vue&type=script&lang=js": /*!************************************************************!*\
!*** ./src/components/Content.vue?vue&type=script&lang=js ***!
************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (/* reexport safe */
_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_Content_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__["default"])/* harmony export */
});
/* harmony import */
var _node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_Content_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./Content.vue?vue&type=script&lang=js */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=script&lang=js");
/***/
}
),
/***/
"./src/components/Content.vue?vue&type=template&id=7eab81f9": /*!******************************************************************!*\
!*** ./src/components/Content.vue?vue&type=template&id=7eab81f9 ***!
******************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
render: () => (/* reexport safe */
_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_1_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__.render)/* harmony export */
});
/* harmony import */
var _node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_1_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_index_js_ruleSet_1_rules_4_use_0_Content_vue_vue_type_template_id_7eab81f9__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./Content.vue?vue&type=template&id=7eab81f9 */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=template&id=7eab81f9");
/***/
}
),
/***/
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=template&id=7eab81f9": /*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[1]!../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/index.js??ruleSet[1].rules[4].use[0]!./src/components/Content.vue?vue&type=template&id=7eab81f9 ***!
************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
render: () => (/* binding */
render)/* harmony export */
});
/* harmony import */
var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */
"../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
const _hoisted_1 = {
style: {
"color": "red"
}
}
function render(_ctx, _cache, $props, $setup, $data, $options) {
return ((0,
vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(),
(0,
vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, (0,
vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($data.title), 1 /* TEXT */
))
}
/***/
}
)
}]);
//# sourceMappingURL=src_components_Content_vue.js.map
3.1.4 过程解析
3.1.4.1 webpack\_require("./src/index.js")
先从入口index.js文件开始看,里面只有一行代码,异步引入main.js模块,
import('./main.js');
但是构建后的startUp入口文件,里面包含了很多基础依赖库,只有在代码最后出现了index.js引入相关代码,
再把里面的代码简化一下,只保留关键的引入部分。
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
**********************/
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_pnpm_mini-css-extract-plugin_2_9_2_webpack_5_96_1__swc_core_1_9_2_webpac-fe6f3f"), __webpack_require__.e("src_main_js")]).then(__webpack_require__.bind(__webpack_require__, /*! ./main.js */ "./src/main.js"));
/***/ })
})
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
/******/ __webpack_require__.i.forEach(function(handler) { handler(execOptions); });
/******/ module = execOptions.module;
/******/ execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = __webpack_module_cache__;
/******/
/******/ // expose the module execution interceptor
/******/ __webpack_require__.i = [];
/******/
/************************************************************************/
/******/ // module cache are used so entry inlining is disabled
/******/ // startup
/******/ // Load entry module and return exports
/******/ __webpack_require__("../../node_modules/.pnpm/webpack-dev-server@5.0.4_webpack-cli@5.1.4_webpack@5.96.1/node_modules/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=0.0.0.0&port=3002&pathname=%2Fws&logging=info&overlay=true&reconnect=10&hot=true&live-reload=true");
/******/ __webpack_require__("../../node_modules/.pnpm/webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4/node_modules/webpack/hot/dev-server.js");
/******/ var __webpack_exports__ = __webpack_require__("./src/index.js");
/******/
/******/ })()
;
直接看到最后一行代码,通过\_\_webpack\_require\_\_方法引入index.js文件,这里也可以认为是一般的同步加载模块部分
*/ var __webpack_exports__ = __webpack_require__("./src/index.js");
继续看\_\_webpack\_require\_\_函数实现,先从\_\_webpack\_module\_cache\_\_缓存变量中获取moduleId为./src/index.js的模块,没有缓存,则创建一个新的模块数据结构,并放到\_\_webpack\_module\_cache\_\_变量里面,
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // 先从__webpack_module_cache__缓存变量中获取moduleId为./src/index.js的模块
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // 没有缓存,则创建一个新的模块数据结构,并放到__webpack_module_cache__变量里面
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
/******/ __webpack_require__.i.forEach(function(handler) { handler(execOptions); });
/******/ module = execOptions.module;
/******/ execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
缓存数据结构中factory字段存放模块里面的具体代码实现,通过\_\_webpack\_modules\_\_[moduleId]获取代码实现部分,最后执行。
3.1.4.2 webpack\_modules
接着看\_\_webpack\_modules\_\_变量,其实在文件最开头已经定义好了,这里才是真正存放原始的'src/index.js'文件,经过构建后的代码,可以具体看一下
/******/ var __webpack_modules__ = ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
**********************/
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
Promise.all(/*! import() */
[
__webpack_require__.e("vendors-node_modules_pnpm_mini-css-extract-plugin_2_9_2_webpack_5_96_1__swc_core_1_9_2_webpac-fe6f3f"),
__webpack_require__.e("src_main_js")]
).then(
__webpack_require__.bind(__webpack_require__, /*! ./main.js */ "./src/main.js")
);
/***/ })
})
简单看原始的 import('./main.js'); 异步加载main.js模块,转化成了 __webpack_require__.e("src_main_js") 。
这里可以暂时理解成去异步请求main.js文件,等main.js文件请求完成后,进入then里面,执行
__webpack_require__.bind(__webpack_require__, /*! ./main.js */ "./src/main.js")
也就是进行一般的同步加载模块,类似前面加载"./src/index.js",都是用__webpack_require__函数。
3.1.4.3 webpack\_require.e
接着关键看__webpack_require__.e是如何实现,其实从前面的index.js加载过程,大致可以推测一下,它主要任务有两个
- 通过创建一个script标签,并设置到html里面,发起请求main.js文件,并自动执行main.js
- ...
__webpack_modules__变量中找到./src/main.js的具体实现。
如何把main.js执行完成后,把自身代码实现设置到__webpack_modules__变量上面。就是最大的疑问。
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
遍历\_webpack\_require\_\_.f对象上挂载的所有方法,并执行。
__webpack_require__.f = {
miniCss: (chunkId, promises) => {
/******/ var cssChunks = {"90":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
/******/ promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(() => {
/******/ installedCssChunks[chunkId] = 0;
/******/ }, (e) => {
/******/ delete installedCssChunks[chunkId];
/******/ throw e;
/******/ }));
/******/ }
/******/ };
/******/ j: (chunkId, promises) => {
/******/ // JSONP chunk loading for javascript
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ if(true) { // all chunks have JS
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ if(installedChunkData) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ installedChunkData[1](error);
/******/ }
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ }
/******/ }
/******/ }
/******/ };
}
两个方法
- miniCss: 通过createStylesheet方法,动态创建link标签,异步加载样式文件
- j: 应该就是jsonp缩写,具体实现是
__webpack_require__.l,里面主要功能也是通过动态创建script标签,异步加载./src/main.js文件
<!---->
/******/ /* webpack/runtime/load script */
/******/ (() => {
/******/ var inProgress = {};
/******/ var dataWebpackPrefix = "vue3-demo_home:";
/******/ // loadScript function to load a script via script tag
/******/ __webpack_require__.l = (url, done, key, chunkId) => {
...
/******/ needAttach = true;
/******/ script = document.createElement('script');
/******/
/******/ script.charset = 'utf-8';
/******/ script.timeout = 120;
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
/******/
/******/ script.src = url;
/******/
/******/ inProgress[url] = [done];
/******/ var onScriptComplete = (prev, event) => {
....
/******/ }
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ script.onload = onScriptComplete.bind(null, script.onload);
/******/ };
/******/ })();
3.1.4.4 ./src/main.js
接着看./src/main.js 文件加载并执行完成有什么效果。
"use strict";
(self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || []).push([["src_main_js"], {
/***/
"./src/App.vue": /*!*********************!*\
!*** ./src/App.vue ***!
*********************/
/***/
( (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */
"default": () => (__WEBPACK_DEFAULT_EXPORT__)/* harmony export */
});
/* harmony import */
var _App_vue_vue_type_template_id_7ba5bd90_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./App.vue?vue&type=template&id=7ba5bd90&scoped=true */
"./src/App.vue?vue&type=template&id=7ba5bd90&scoped=true");
/* harmony import */
var _App_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./App.vue?vue&type=script&lang=js */
"./src/App.vue?vue&type=script&lang=js");
/* harmony import */
var _App_vue_vue_type_style_index_0_id_7ba5bd90_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css */
"./src/App.vue?vue&type=style&index=0&id=7ba5bd90&scoped=true&lang=css");
/* harmony import */
var _Users_liqi_fe_module_federation_examples_node_modules_pnpm_vue_loader_16_8_3_vue_compiler_sfc_3_4_31_vue_3_3_7_typescript_5_6_3_webpack_5_96_1_swc_core_1_9_2_webpack_cli_5_1_4_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js */
"../../node_modules/.pnpm/vue-loader@16.8.3_@vue+compiler-sfc@3.4.31_vue@3.3.7_typescript@5.6.3__webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4_/node_modules/vue-loader/dist/exportHelper.js");
;
/* harmony default export */
const __WEBPACK_DEFAULT_EXPORT__ = (__exports__);
/***/
}
),
/***/
"./src/main.js": /*!*********************!*\
!*** ./src/main.js ***!
*********************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */
var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */
"../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js");
/* harmony import */
var _App_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./App.vue */
"./src/App.vue");
const app = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.createApp)(_App_vue__WEBPACK_IMPORTED_MODULE_1__["default"]);
app.mount('#app');
/***/
}
)
}]);
push里面的内容跟. __webpack_modules__变量结构很类似,key对应moduleid, value对应具体代码实现。
self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || []).push([["src_main_js"], {
{key}: {value}
}])
self是指向当前 window 对象的引用,在Service Workers和Web Workers非window场景下也适用
3.1.4.5 self["webpackChunkvue3\_demo\_home"].push = webpackJsonpCallback
从[入口的js文件中]寻找 self["webpackChunkvue3\_demo\_home"]的实现。
// install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
上面代码有两个关键点:
- chunkLoadingGlobal.push,也就是self["webpackChunkvue3\_demo\_home"].push方法被改写成了webpackJsonpCallback
- webpackJsonpCallback里面\_\_webpack\_require\_\_.m 也就是指向了 webpack\_modules, 把push方法传入的参数解析到\_\_webpack\_modules\_\_对象上,完成了模块赋值闭环。
3.1.5 整体组件加载执行过程

3.2 Module Federation模块加载流程
module federation加载流程跟异步加载主流程保持不变,额外引入了remote、resumes处理方法,所以需要先看完webpack按需加载到流程
3.2.1 概述
Module Federation 加载跟按需加载最大的区别是它需要处理共享模块和共享依赖,
如何进行依赖前置是很大的问题。
还是用前面的vue3-demo示例,现在设置上ModuleFederationPlugin插件,主要看Layout目录下的文件,从消费者角度看模块加载流程,入口文件还是src/index.js
vue3-demo/
├── layout(host)
│ ├── src
│ │ ├── Layout.vue -- 使用业务组件Content,
│ │ ├── index.js -- import('./main.js');
│ │ └── main.js -- const Content = defineAsyncComponent(() => import('home/Content'));
│ └── webpack.config.js -- remotes:{home: 'home@http://home.com/remoteEntry.js'}
└── package.json
3.2.2 初始化请求链路
从请求链路入口js后面多了remoteEntry,提前加载了共享组件Content、Button
3.2.3 源码与构建后代码对照
3.2.3.1 入口html文件
<!---->
3.2.3.1.1 源码
<div id="app"></div>
3.2.3.1.2 构建后代码
<head><script defer src="main.js"></script></head><div id="app"></div>
3.2.3.2 入口index.js文件
3.2.3.2.1 源码
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
import('./main.js');
3.2.3.2.2 构建后代码
构建后的startUp 入口函数
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
**********************/
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
// https://webpack.js.org/concepts/module-federation/#uncaught-error-shared-module-is-not-available-for-eager-consumption
__webpack_require__.e(/*! import() */ "src_main_js").then(__webpack_require__.bind(__webpack_require__, /*! ./main.js */ "./src/main.js"));
/***/ }),
/***/ "webpack/container/reference/home":
/*!************************************************************!*\
!*** external "home@http://localhost:3002/remoteEntry.js" ***!
************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var __webpack_error__ = new Error();
module.exports = new Promise((resolve, reject) => {
if(typeof home !== "undefined") return resolve();
__webpack_require__.l("http://localhost:3002/remoteEntry.js", (event) => {
if(typeof home !== "undefined") return resolve();
var errorType = event && (event.type === 'load' ? 'missing' : event.type);
var realSrc = event && event.target && event.target.src;
__webpack_error__.message = 'Loading script failed.\n(' + errorType + ': ' + realSrc + ')';
__webpack_error__.name = 'ScriptExternalLoadError';
__webpack_error__.type = errorType;
__webpack_error__.request = realSrc;
reject(__webpack_error__);
}, "home");
}).then(() => (home));
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
/******/ __webpack_require__.i.forEach(function(handler) { handler(execOptions); });
/******/ module = execOptions.module;
/******/ execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = __webpack_module_cache__;
/******/
/******/ // expose the module execution interceptor
/******/ __webpack_require__.i = [];
/******/
/******/
/******/
/******/
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
/******/
/******/
/******/
/******/ /* webpack/runtime/get mini-css chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.miniCssF = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return "" + chunkId + ".css";
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/remotes loading */
/******/ (() => {
/******/ var chunkMapping = {
/******/ "webpack_container_remote_home_Content": [
/******/ "webpack/container/remote/home/Content"
/******/ ],
/******/ "webpack_container_remote_home_Button": [
/******/ "webpack/container/remote/home/Button"
/******/ ]
/******/ };
/******/ var idToExternalAndNameMapping = {
/******/ "webpack/container/remote/home/Content": [
/******/ "default",
/******/ "./Content",
/******/ "webpack/container/reference/home"
/******/ ],
/******/ "webpack/container/remote/home/Button": [
/******/ "default",
/******/ "./Button",
/******/ "webpack/container/reference/home"
/******/ ]
/******/ };
/******/ __webpack_require__.f.remotes = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ var getScope = __webpack_require__.R;
/******/ if(!getScope) getScope = [];
/******/ var data = idToExternalAndNameMapping[id];
/******/ if(getScope.indexOf(data) >= 0) return;
/******/ getScope.push(data);
/******/ if(data.p) return promises.push(data.p);
/******/ var onError = (error) => {
/******/ if(!error) error = new Error("Container missing");
/******/ if(typeof error.message === "string")
/******/ error.message += '\nwhile loading "' + data[1] + '" from ' + data[2];
/******/ __webpack_require__.m[id] = () => {
/******/ throw error;
/******/ }
/******/ data.p = 0;
/******/ };
/******/ var handleFunction = (fn, arg1, arg2, d, next, first) => {
/******/ try {
/******/ var promise = fn(arg1, arg2);
/******/ if(promise && promise.then) {
/******/ var p = promise.then((result) => (next(result, d)), onError);
/******/ if(first) promises.push(data.p = p); else return p;
/******/ } else {
/******/ return next(promise, d, first);
/******/ }
/******/ } catch(error) {
/******/ onError(error);
/******/ }
/******/ }
/******/ var onExternal = (external, _, first) => (external ? handleFunction(__webpack_require__.I, data[0], 0, external, onInitialized, first) : onError());
/******/ var onInitialized = (_, external, first) => (handleFunction(external.get, data[1], getScope, 0, onFactory, first));
/******/ var onFactory = (factory) => {
/******/ data.p = 1;
/******/ __webpack_require__.m[id] = (module) => {
/******/ module.exports = factory();
/******/ }
/******/ };
/******/ handleFunction(__webpack_require__, data[2], 0, 0, onExternal, 1);
/******/ });
/******/ }
/******/ }
/******/ })();
/******/
/******/ /* webpack/runtime/sharing */
/******/ (() => {
/******/ __webpack_require__.S = {};
/******/ var initPromises = {};
/******/ var initTokens = {};
/******/ __webpack_require__.I = (name, initScope) => {
/******/ if(!initScope) initScope = [];
/******/ // handling circular init calls
/******/ var initToken = initTokens[name];
/******/ if(!initToken) initToken = initTokens[name] = {};
/******/ if(initScope.indexOf(initToken) >= 0) return;
/******/ initScope.push(initToken);
/******/ // only runs once
/******/ if(initPromises[name]) return initPromises[name];
/******/ // creates a new share scope if needed
/******/ if(!__webpack_require__.o(__webpack_require__.S, name)) __webpack_require__.S[name] = {};
/******/ // runs all init snippets from all modules reachable
/******/ var scope = __webpack_require__.S[name];
/******/ var warn = (msg) => {
/******/ if (typeof console !== "undefined" && console.warn) console.warn(msg);
/******/ };
/******/ var uniqueName = "vue3-demo_layout";
/******/ var register = (name, version, factory, eager) => {
/******/ var versions = scope[name] = scope[name] || {};
/******/ var activeVersion = versions[version];
/******/ if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };
/******/ };
/******/ var initExternal = (id) => {
/******/ var handleError = (err) => (warn("Initialization of sharing external failed: " + err));
/******/ try {
/******/ var module = __webpack_require__(id);
/******/ if(!module) return;
/******/ var initFn = (module) => (module && module.init && module.init(__webpack_require__.S[name], initScope))
/******/ if(module.then) return promises.push(module.then(initFn, handleError));
/******/ var initResult = initFn(module);
/******/ if(initResult && initResult.then) return promises.push(initResult['catch'](handleError));
/******/ } catch(err) { handleError(err); }
/******/ }
/******/ var promises = [];
/******/ switch(name) {
/******/ case "default": {
/******/ register("vue", "3.3.7", () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! ../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js"))))));
/******/ initExternal("webpack/container/reference/home");
/******/ }
/******/ break;
/******/ }
/******/ if(!promises.length) return initPromises[name] = 1;
/******/ return initPromises[name] = Promise.all(promises).then(() => (initPromises[name] = 1));
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/consumes */
/******/ (() => {
/******/ var parseVersion = (str) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ var p=p=>{return p.split(".").map((p=>{return+p==p?+p:p}))},n=/^([^-+]+)?(?:-([^+]+))?(?:+(.+))?$/.exec(str),r=n[1]?p(n[1]):[];return n[2]&&(r.length++,r.push.apply(r,p(n[2]))),n[3]&&(r.push([]),r.push.apply(r,p(n[3]))),r;
/******/ }
/******/ var versionLt = (a, b) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ a=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++}
/******/ }
/******/ var rangeToString = (range) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ var r=range[0],n="";if(1===range.length)return"*";if(r+.5){n+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,n+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return n}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^((.+))$/,"$1")}
/******/ }
/******/ var satisfy = (range, version) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o();
/******/ }
/******/ var exists = (scope, key) => {
/******/ return scope && __webpack_require__.o(scope, key);
/******/ }
/******/ var get = (entry) => {
/******/ entry.loaded = 1;
/******/ return entry.get()
/******/ };
/******/ var eagerOnly = (versions) => {
/******/ return Object.keys(versions).reduce((filtered, version) => {
/******/ if (versions[version].eager) {
/******/ filtered[version] = versions[version];
/******/ }
/******/ return filtered;
/******/ }, {});
/******/ };
/******/ var findLatestVersion = (scope, key, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ var key = Object.keys(versions).reduce((a, b) => {
/******/ return !a || versionLt(a, b) ? b : a;
/******/ }, 0);
/******/ return key && versions[key];
/******/ };
/******/ var findSatisfyingVersion = (scope, key, requiredVersion, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ var key = Object.keys(versions).reduce((a, b) => {
/******/ if (!satisfy(requiredVersion, b)) return a;
/******/ return !a || versionLt(a, b) ? b : a;
/******/ }, 0);
/******/ return key && versions[key]
/******/ };
/******/ var findSingletonVersionKey = (scope, key, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ return Object.keys(versions).reduce((a, b) => {
/******/ return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;
/******/ }, 0);
/******/ };
/******/ var getInvalidSingletonVersionMessage = (scope, key, version, requiredVersion) => {
/******/ return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"
/******/ };
/******/ var getInvalidVersionMessage = (scope, scopeName, key, requiredVersion, eager) => {
/******/ var versions = scope[key];
/******/ return "No satisfying version (" + rangeToString(requiredVersion) + ")" + (eager ? " for eager consumption" : "") + " of shared module " + key + " found in shared scope " + scopeName + ".\n" +
/******/ "Available versions: " + Object.keys(versions).map((key) => {
/******/ return key + " from " + versions[key].from;
/******/ }).join(", ");
/******/ };
/******/ var fail = (msg) => {
/******/ throw new Error(msg);
/******/ }
/******/ var failAsNotExist = (scopeName, key) => {
/******/ return fail("Shared module " + key + " doesn't exist in shared scope " + scopeName);
/******/ }
/******/ var warn = /*#__PURE__*/ (msg) => {
/******/ if (typeof console !== "undefined" && console.warn) console.warn(msg);
/******/ };
/******/ var init = (fn) => (function(scopeName, key, eager, c, d) {
/******/ var promise = __webpack_require__.I(scopeName);
/******/ if (promise && promise.then && !eager) {
/******/ return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], key, false, c, d));
/******/ }
/******/ return fn(scopeName, __webpack_require__.S[scopeName], key, eager, c, d);
/******/ });
/******/
/******/ var useFallback = (scopeName, key, fallback) => {
/******/ return fallback ? fallback() : failAsNotExist(scopeName, key);
/******/ }
/******/ var load = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ return get(findLatestVersion(scope, key, eager));
/******/ });
/******/ var loadVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
/******/ if (satisfyingVersion) return get(satisfyingVersion);
/******/ warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager))
/******/ return get(findLatestVersion(scope, key, eager));
/******/ });
/******/ var loadStrictVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
/******/ if (satisfyingVersion) return get(satisfyingVersion);
/******/ if (fallback) return fallback();
/******/ fail(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager));
/******/ });
/******/ var loadSingleton = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ return get(scope[key][version]);
/******/ });
/******/ var loadSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ if (!satisfy(requiredVersion, version)) {
/******/ warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
/******/ }
/******/ return get(scope[key][version]);
/******/ });
/******/ var loadStrictSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ if (!satisfy(requiredVersion, version)) {
/******/ fail(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
/******/ }
/******/ return get(scope[key][version]);
/******/ });
/******/ var installedModules = {};
/******/ var moduleToHandlerMapping = {
/******/ "webpack/sharing/consume/default/vue/vue": () => (loadSingletonVersion("default", "vue", false, [1,3,0,11], () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! vue */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js")))))))
/******/ };
/******/ // no consumes in initial chunks
/******/ var chunkMapping = {
/******/ "src_main_js": [
/******/ "webpack/sharing/consume/default/vue/vue"
/******/ ]
/******/ };
/******/ var startedInstallModules = {};
/******/ __webpack_require__.f.consumes = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ if(__webpack_require__.o(installedModules, id)) return promises.push(installedModules[id]);
/******/ if(!startedInstallModules[id]) {
/******/ var onFactory = (factory) => {
/******/ installedModules[id] = 0;
/******/ __webpack_require__.m[id] = (module) => {
/******/ delete __webpack_require__.c[id];
/******/ module.exports = factory();
/******/ }
/******/ };
/******/ startedInstallModules[id] = true;
/******/ var onError = (error) => {
/******/ delete installedModules[id];
/******/ __webpack_require__.m[id] = (module) => {
/******/ delete __webpack_require__.c[id];
/******/ throw error;
/******/ }
/******/ };
/******/ try {
/******/ var promise = moduleToHandlerMapping[id]();
/******/ if(promise.then) {
/******/ promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));
/******/ } else onFactory(promise);
/******/ } catch(e) { onError(e); }
/******/ }
/******/ });
/******/ }
/******/ }
/******/ })();
/******/
/******/ /* webpack/runtime/css loading */
/******/ (() => {
/******/ if (typeof document === "undefined") return;
/******/ var createStylesheet = (chunkId, fullhref, oldTag, resolve, reject) => {
/******/ var linkTag = document.createElement("link");
/******/
/******/ linkTag.rel = "stylesheet";
/******/ linkTag.type = "text/css";
/******/ if (__webpack_require__.nc) {
/******/ linkTag.nonce = __webpack_require__.nc;
/******/ }
/******/ var onLinkComplete = (event) => {
/******/ // avoid mem leaks.
/******/ linkTag.onerror = linkTag.onload = null;
/******/ if (event.type === 'load') {
/******/ resolve();
/******/ } else {
/******/ var errorType = event && event.type;
/******/ var realHref = event && event.target && event.target.href || fullhref;
/******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + errorType + ": " + realHref + ")");
/******/ err.name = "ChunkLoadError";
/******/ err.code = "CSS_CHUNK_LOAD_FAILED";
/******/ err.type = errorType;
/******/ err.request = realHref;
/******/ if (linkTag.parentNode) linkTag.parentNode.removeChild(linkTag)
/******/ reject(err);
/******/ }
/******/ }
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
/******/ document.head.appendChild(linkTag);
/******/ }
/******/ return linkTag;
/******/ };
/******/ var findStylesheet = (href, fullhref) => {
/******/ var existingLinkTags = document.getElementsByTagName("link");
/******/ for(var i = 0; i < existingLinkTags.length; i++) {
/******/ var tag = existingLinkTags[i];
/******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
/******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return tag;
/******/ }
/******/ var existingStyleTags = document.getElementsByTagName("style");
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
/******/ var tag = existingStyleTags[i];
/******/ var dataHref = tag.getAttribute("data-href");
/******/ if(dataHref === href || dataHref === fullhref) return tag;
/******/ }
/******/ };
/******/ var loadStylesheet = (chunkId) => {
/******/ return new Promise((resolve, reject) => {
/******/ var href = __webpack_require__.miniCssF(chunkId);
/******/ var fullhref = __webpack_require__.p + href;
/******/ if(findStylesheet(href, fullhref)) return resolve();
/******/ createStylesheet(chunkId, fullhref, null, resolve, reject);
/******/ });
/******/ }
/******/ // object to store loaded CSS chunks
/******/ var installedCssChunks = {
/******/ "main": 0
/******/ };
/******/
/******/ __webpack_require__.f.miniCss = (chunkId, promises) => {
/******/ var cssChunks = {"src_main_js":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
/******/ promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(() => {
/******/ installedCssChunks[chunkId] = 0;
/******/ }, (e) => {
/******/ delete installedCssChunks[chunkId];
/******/ throw e;
/******/ }));
/******/ }
/******/ };
/******/
/******/ var oldTags = [];
/******/ var newTags = [];
/******/ var applyHandler = (options) => {
/******/ return { dispose: () => {
/******/ for(var i = 0; i < oldTags.length; i++) {
/******/ var oldTag = oldTags[i];
/******/ if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);
/******/ }
/******/ oldTags.length = 0;
/******/ }, apply: () => {
/******/ for(var i = 0; i < newTags.length; i++) newTags[i].rel = "stylesheet";
/******/ newTags.length = 0;
/******/ } };
/******/ }
/******/ __webpack_require__.hmrC.miniCss = (chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) => {
/******/ applyHandlers.push(applyHandler);
/******/ chunkIds.forEach((chunkId) => {
/******/ var href = __webpack_require__.miniCssF(chunkId);
/******/ var fullhref = __webpack_require__.p + href;
/******/ var oldTag = findStylesheet(href, fullhref);
/******/ if(!oldTag) return;
/******/ promises.push(new Promise((resolve, reject) => {
/******/ var tag = createStylesheet(chunkId, fullhref, oldTag, () => {
/******/ tag.as = "style";
/******/ tag.rel = "preload";
/******/ resolve();
/******/ }, reject);
/******/ oldTags.push(oldTag);
/******/ newTags.push(tag);
/******/ }));
/******/ });
/******/ }
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = __webpack_require__.hmrS_jsonp = __webpack_require__.hmrS_jsonp || {
/******/ "main": 0
/******/ };
/******/
/******/ __webpack_require__.f.j = (chunkId, promises) => {
/******/ // JSONP chunk loading for javascript
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ if(!/^webpack_container_remote_home_(Button|Content)$/.test(chunkId)) {
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ if(installedChunkData) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ installedChunkData[1](error);
/******/ }
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ } else installedChunks[chunkId] = 0;
/******/ }
/******/ }
/******/ };
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/
/******/ self["webpackHotUpdatevue3_demo_layout"] = (chunkId, moreModules, runtime) => {
/******/ for(var moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ currentUpdate[moduleId] = moreModules[moduleId];
/******/ if(currentUpdatedModulesList) currentUpdatedModulesList.push(moduleId);
/******/ }
/******/ }
/******/ if(runtime) currentUpdateRuntime.push(runtime);
/******/ if(waitingUpdateResolves[chunkId]) {
/******/ waitingUpdateResolves[chunkId]();
/******/ waitingUpdateResolves[chunkId] = undefined;
/******/ }
/******/ };
/******/
/******/
/******/ // no on chunks loaded
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkvue3_demo_layout"] = self["webpackChunkvue3_demo_layout"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/ var __webpack_exports__ = __webpack_require__("./src/index.js");
/******/
/******/ })()
;
3.2.3.3 remoteEntry.js文件
var home;
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "webpack/container/entry/home":
/*!***********************!*\
!*** container entry ***!
***********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
"use strict";
var moduleMap = {
"./Content": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Content_vue-_cddc0")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Content */ "./src/components/Content.vue")))));
},
"./Button": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Button_js")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Button */ "./src/components/Button.js")))));
}
};
var get = (module, getScope) => {
__webpack_require__.R = getScope;
getScope = (
__webpack_require__.o(moduleMap, module)
? moduleMap[module]()
: Promise.resolve().then(() => {
throw new Error('Module "' + module + '" does not exist in container.');
})
);
__webpack_require__.R = undefined;
return getScope;
};
var init = (shareScope, initScope) => {
if (!__webpack_require__.S) return;
var name = "default"
var oldScope = __webpack_require__.S[name];
if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");
__webpack_require__.S[name] = shareScope;
return __webpack_require__.I(name, initScope);
};
// This exports getters to disallow modifications
__webpack_require__.d(exports, {
get: () => (get),
init: () => (init)
});
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
/******/ __webpack_require__.i.forEach(function(handler) { handler(execOptions); });
/******/ module = execOptions.module;
/******/ execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = __webpack_module_cache__;
/******/
/******/ // expose the module execution interceptor
/******/ __webpack_require__.i = [];
/******/
/******/
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
/******/
/******/
/******/
/******/ /* webpack/runtime/get mini-css chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.miniCssF = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return undefined;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/load script */
/******/ (() => {
/******/ var inProgress = {};
/******/ var dataWebpackPrefix = "vue3-demo_home:";
/******/ // loadScript function to load a script via script tag
/******/ __webpack_require__.l = (url, done, key, chunkId) => {
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
/******/ var script, needAttach;
/******/ if(key !== undefined) {
/******/ var scripts = document.getElementsByTagName("script");
/******/ for(var i = 0; i < scripts.length; i++) {
/******/ var s = scripts[i];
/******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
/******/ }
/******/ }
/******/ if(!script) {
/******/ needAttach = true;
/******/ script = document.createElement('script');
/******/
/******/ script.charset = 'utf-8';
/******/ script.timeout = 120;
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
/******/
/******/ script.src = url;
/******/ }
/******/ inProgress[url] = [done];
/******/ var onScriptComplete = (prev, event) => {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var doneFns = inProgress[url];
/******/ delete inProgress[url];
/******/ script.parentNode && script.parentNode.removeChild(script);
/******/ doneFns && doneFns.forEach((fn) => (fn(event)));
/******/ if(prev) return prev(event);
/******/ }
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ script.onload = onScriptComplete.bind(null, script.onload);
/******/ needAttach && document.head.appendChild(script);
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/remotes loading */
/******/ (() => {
/******/ var chunkMapping = {};
/******/ var idToExternalAndNameMapping = {};
/******/ __webpack_require__.f.remotes = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ var getScope = __webpack_require__.R;
/******/ if(!getScope) getScope = [];
/******/ var data = idToExternalAndNameMapping[id];
/******/ if(getScope.indexOf(data) >= 0) return;
/******/ getScope.push(data);
/******/ if(data.p) return promises.push(data.p);
/******/ var onError = (error) => {
/******/ if(!error) error = new Error("Container missing");
/******/ if(typeof error.message === "string")
/******/ error.message += '\nwhile loading "' + data[1] + '" from ' + data[2];
/******/ __webpack_require__.m[id] = () => {
/******/ throw error;
/******/ }
/******/ data.p = 0;
/******/ };
/******/ var handleFunction = (fn, arg1, arg2, d, next, first) => {
/******/ try {
/******/ var promise = fn(arg1, arg2);
/******/ if(promise && promise.then) {
/******/ var p = promise.then((result) => (next(result, d)), onError);
/******/ if(first) promises.push(data.p = p); else return p;
/******/ } else {
/******/ return next(promise, d, first);
/******/ }
/******/ } catch(error) {
/******/ onError(error);
/******/ }
/******/ }
/******/ var onExternal = (external, _, first) => (external ? handleFunction(__webpack_require__.I, data[0], 0, external, onInitialized, first) : onError());
/******/ var onInitialized = (_, external, first) => (handleFunction(external.get, data[1], getScope, 0, onFactory, first));
/******/ var onFactory = (factory) => {
/******/ data.p = 1;
/******/ __webpack_require__.m[id] = (module) => {
/******/ module.exports = factory();
/******/ }
/******/ };
/******/ handleFunction(__webpack_require__, data[2], 0, 0, onExternal, 1);
/******/ });
/******/ }
/******/ }
/******/ })();
/******/
/******/ /* webpack/runtime/sharing */
/******/ (() => {
/******/ __webpack_require__.S = {};
/******/ var initPromises = {};
/******/ var initTokens = {};
/******/ __webpack_require__.I = (name, initScope) => {
/******/ if(!initScope) initScope = [];
/******/ // handling circular init calls
/******/ var initToken = initTokens[name];
/******/ if(!initToken) initToken = initTokens[name] = {};
/******/ if(initScope.indexOf(initToken) >= 0) return;
/******/ initScope.push(initToken);
/******/ // only runs once
/******/ if(initPromises[name]) return initPromises[name];
/******/ // creates a new share scope if needed
/******/ if(!__webpack_require__.o(__webpack_require__.S, name)) __webpack_require__.S[name] = {};
/******/ // runs all init snippets from all modules reachable
/******/ var scope = __webpack_require__.S[name];
/******/ var warn = (msg) => {
/******/ if (typeof console !== "undefined" && console.warn) console.warn(msg);
/******/ };
/******/ var uniqueName = "vue3-demo_home";
/******/ var register = (name, version, factory, eager) => {
/******/ var versions = scope[name] = scope[name] || {};
/******/ var activeVersion = versions[version];
/******/ if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };
/******/ };
/******/ var initExternal = (id) => {
/******/ var handleError = (err) => (warn("Initialization of sharing external failed: " + err));
/******/ try {
/******/ var module = __webpack_require__(id);
/******/ if(!module) return;
/******/ var initFn = (module) => (module && module.init && module.init(__webpack_require__.S[name], initScope))
/******/ if(module.then) return promises.push(module.then(initFn, handleError));
/******/ var initResult = initFn(module);
/******/ if(initResult && initResult.then) return promises.push(initResult['catch'](handleError));
/******/ } catch(err) { handleError(err); }
/******/ }
/******/ var promises = [];
/******/ switch(name) {
/******/ case "default": {
/******/ register("vue", "3.3.7", () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! ../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js"))))));
/******/ }
/******/ break;
/******/ }
/******/ if(!promises.length) return initPromises[name] = 1;
/******/ return initPromises[name] = Promise.all(promises).then(() => (initPromises[name] = 1));
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/consumes */
/******/ (() => {
/******/ var parseVersion = (str) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ var p=p=>{return p.split(".").map((p=>{return+p==p?+p:p}))},n=/^([^-+]+)?(?:-([^+]+))?(?:+(.+))?$/.exec(str),r=n[1]?p(n[1]):[];return n[2]&&(r.length++,r.push.apply(r,p(n[2]))),n[3]&&(r.push([]),r.push.apply(r,p(n[3]))),r;
/******/ }
/******/ var versionLt = (a, b) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ a=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++}
/******/ }
/******/ var rangeToString = (range) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ var r=range[0],n="";if(1===range.length)return"*";if(r+.5){n+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,n+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return n}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^((.+))$/,"$1")}
/******/ }
/******/ var satisfy = (range, version) => {
/******/ // see webpack/lib/util/semver.js for original code
/******/ if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o();
/******/ }
/******/ var exists = (scope, key) => {
/******/ return scope && __webpack_require__.o(scope, key);
/******/ }
/******/ var get = (entry) => {
/******/ entry.loaded = 1;
/******/ return entry.get()
/******/ };
/******/ var eagerOnly = (versions) => {
/******/ return Object.keys(versions).reduce((filtered, version) => {
/******/ if (versions[version].eager) {
/******/ filtered[version] = versions[version];
/******/ }
/******/ return filtered;
/******/ }, {});
/******/ };
/******/ var findLatestVersion = (scope, key, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ var key = Object.keys(versions).reduce((a, b) => {
/******/ return !a || versionLt(a, b) ? b : a;
/******/ }, 0);
/******/ return key && versions[key];
/******/ };
/******/ var findSatisfyingVersion = (scope, key, requiredVersion, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ var key = Object.keys(versions).reduce((a, b) => {
/******/ if (!satisfy(requiredVersion, b)) return a;
/******/ return !a || versionLt(a, b) ? b : a;
/******/ }, 0);
/******/ return key && versions[key]
/******/ };
/******/ var findSingletonVersionKey = (scope, key, eager) => {
/******/ var versions = eager ? eagerOnly(scope[key]) : scope[key];
/******/ return Object.keys(versions).reduce((a, b) => {
/******/ return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;
/******/ }, 0);
/******/ };
/******/ var getInvalidSingletonVersionMessage = (scope, key, version, requiredVersion) => {
/******/ return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"
/******/ };
/******/ var getInvalidVersionMessage = (scope, scopeName, key, requiredVersion, eager) => {
/******/ var versions = scope[key];
/******/ return "No satisfying version (" + rangeToString(requiredVersion) + ")" + (eager ? " for eager consumption" : "") + " of shared module " + key + " found in shared scope " + scopeName + ".\n" +
/******/ "Available versions: " + Object.keys(versions).map((key) => {
/******/ return key + " from " + versions[key].from;
/******/ }).join(", ");
/******/ };
/******/ var fail = (msg) => {
/******/ throw new Error(msg);
/******/ }
/******/ var failAsNotExist = (scopeName, key) => {
/******/ return fail("Shared module " + key + " doesn't exist in shared scope " + scopeName);
/******/ }
/******/ var warn = /*#__PURE__*/ (msg) => {
/******/ if (typeof console !== "undefined" && console.warn) console.warn(msg);
/******/ };
/******/ var init = (fn) => (function(scopeName, key, eager, c, d) {
/******/ var promise = __webpack_require__.I(scopeName);
/******/ if (promise && promise.then && !eager) {
/******/ return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], key, false, c, d));
/******/ }
/******/ return fn(scopeName, __webpack_require__.S[scopeName], key, eager, c, d);
/******/ });
/******/
/******/ var useFallback = (scopeName, key, fallback) => {
/******/ return fallback ? fallback() : failAsNotExist(scopeName, key);
/******/ }
/******/ var load = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ return get(findLatestVersion(scope, key, eager));
/******/ });
/******/ var loadVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
/******/ if (satisfyingVersion) return get(satisfyingVersion);
/******/ warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager))
/******/ return get(findLatestVersion(scope, key, eager));
/******/ });
/******/ var loadStrictVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
/******/ if (satisfyingVersion) return get(satisfyingVersion);
/******/ if (fallback) return fallback();
/******/ fail(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager));
/******/ });
/******/ var loadSingleton = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ return get(scope[key][version]);
/******/ });
/******/ var loadSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ if (!satisfy(requiredVersion, version)) {
/******/ warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
/******/ }
/******/ return get(scope[key][version]);
/******/ });
/******/ var loadStrictSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
/******/ if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
/******/ var version = findSingletonVersionKey(scope, key, eager);
/******/ if (!satisfy(requiredVersion, version)) {
/******/ fail(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
/******/ }
/******/ return get(scope[key][version]);
/******/ });
/******/ var installedModules = {};
/******/ var moduleToHandlerMapping = {
/******/ "webpack/sharing/consume/default/vue/vue": () => (loadSingletonVersion("default", "vue", false, [1,3,0,11], () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! vue */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js")))))))
/******/ };
/******/ // no consumes in initial chunks
/******/ var chunkMapping = {
/******/ "webpack_sharing_consume_default_vue_vue": [
/******/ "webpack/sharing/consume/default/vue/vue"
/******/ ]
/******/ };
/******/ var startedInstallModules = {};
/******/ __webpack_require__.f.consumes = (chunkId, promises) => {
/******/ if(__webpack_require__.o(chunkMapping, chunkId)) {
/******/ chunkMapping[chunkId].forEach((id) => {
/******/ if(__webpack_require__.o(installedModules, id)) return promises.push(installedModules[id]);
/******/ if(!startedInstallModules[id]) {
/******/ var onFactory = (factory) => {
/******/ installedModules[id] = 0;
/******/ __webpack_require__.m[id] = (module) => {
/******/ delete __webpack_require__.c[id];
/******/ module.exports = factory();
/******/ }
/******/ };
/******/ startedInstallModules[id] = true;
/******/ var onError = (error) => {
/******/ delete installedModules[id];
/******/ __webpack_require__.m[id] = (module) => {
/******/ delete __webpack_require__.c[id];
/******/ throw error;
/******/ }
/******/ };
/******/ try {
/******/ var promise = moduleToHandlerMapping[id]();
/******/ if(promise.then) {
/******/ promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));
/******/ } else onFactory(promise);
/******/ } catch(e) { onError(e); }
/******/ }
/******/ });
/******/ }
/******/ }
/******/ })();
/******/
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = __webpack_require__.hmrS_jsonp = __webpack_require__.hmrS_jsonp || {
/******/ "home": 0
/******/ };
/******/
/******/ __webpack_require__.f.j = (chunkId, promises) => {
/******/ // JSONP chunk loading for javascript
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ if("webpack_sharing_consume_default_vue_vue" != chunkId) {
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ if(installedChunkData) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ installedChunkData[1](error);
/******/ }
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ } else installedChunks[chunkId] = 0;
/******/ }
/******/ }
/******/ };
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ var currentUpdatedModulesList;
/******/ var waitingUpdateResolves = {};
/******/ function loadUpdateChunk(chunkId, updatedModulesList) {
/******/ currentUpdatedModulesList = updatedModulesList;
/******/ return new Promise((resolve, reject) => {
/******/ waitingUpdateResolves[chunkId] = resolve;
/******/ // start update chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.hu(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(waitingUpdateResolves[chunkId]) {
/******/ waitingUpdateResolves[chunkId] = undefined
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading hot update chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ reject(error);
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded);
/******/ });
/******/ }
/******/
/******/ self["webpackHotUpdatevue3_demo_home"] = (chunkId, moreModules, runtime) => {
/******/ for(var moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ currentUpdate[moduleId] = moreModules[moduleId];
/******/ if(currentUpdatedModulesList) currentUpdatedModulesList.push(moduleId);
/******/ }
/******/ }
/******/ if(runtime) currentUpdateRuntime.push(runtime);
/******/ if(waitingUpdateResolves[chunkId]) {
/******/ waitingUpdateResolves[chunkId]();
/******/ waitingUpdateResolves[chunkId] = undefined;
/******/ }
/******/ };
/******/ };
/******/
/******/
/******/ // no on chunks loaded
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunkvue3_demo_home"] = self["webpackChunkvue3_demo_home"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // module cache are used so entry inlining is disabled
/******/ // startup
/******/ // Load entry module and return exports
/******/ __webpack_require__("../../node_modules/.pnpm/webpack-dev-server@5.0.4_webpack-cli@5.1.4_webpack@5.96.1/node_modules/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=0.0.0.0&port=3002&pathname=%2Fws&logging=info&overlay=true&reconnect=10&hot=true&live-reload=true");
/******/ __webpack_require__("../../node_modules/.pnpm/webpack@5.96.1_@swc+core@1.9.2_webpack-cli@5.1.4/node_modules/webpack/hot/dev-server.js");
/******/ var __webpack_exports__ = __webpack_require__("webpack/container/entry/home");
/******/ home = __webpack_exports__;
/******/
/******/ })()
;
3.2.3.4 main.js文件
<!---->
3.2.3.4.1 源码
import { createApp, defineAsyncComponent } from 'vue';
import Layout from './Layout.vue';
const Content = defineAsyncComponent(() => import('home/Content'));
const Button = defineAsyncComponent(() => import('home/Button'));
const app = createApp(Layout);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
3.2.3.4.2 构建后代码
"use strict";
(self["webpackChunkvue3_demo_layout"] = self["webpackChunkvue3_demo_layout"] || []).push([["src_main_js"],{
/***/ "./src/main.js":
/*!*********************!*\
!*** ./src/main.js ***!
*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "webpack/sharing/consume/default/vue/vue");
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Layout_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Layout.vue */ "./src/Layout.vue");
const Content = (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(() => __webpack_require__.e(/*! import() */ "webpack_container_remote_home_Content").then(__webpack_require__.t.bind(__webpack_require__, /*! home/Content */ "webpack/container/remote/home/Content", 23)));
const Button = (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(() => __webpack_require__.e(/*! import() */ "webpack_container_remote_home_Button").then(__webpack_require__.t.bind(__webpack_require__, /*! home/Button */ "webpack/container/remote/home/Button", 23)));
const app = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createApp)(_Layout_vue__WEBPACK_IMPORTED_MODULE_1__["default"]);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
/***/ })
}]);
3.2.4 过程解析
<!---->
3.2.4.1 webpack异步模块的加载流程前置
前面流程跟webpack异步模块的加载流程相同,简单过一下
- 通过\_\_webpack\_require\_\_("./src/index.js"),方法,同步加载入口文件index.js
- 执行index.js里面异步加载'src/main.js'文件的逻辑,具体执行
__webpack_require__.e函数, - 执行并遍历\_webpack\_require\_\_.f对象上挂载的所有方法。
到遍历执行\_webpack\_require\_\_.f上所有方法时,开始不同了,
多了\_\_webpack\_require\_\_.f.remotes 和\_\_webpack\_require\_\_.f.resumes方法,
__webpack_require__.f.resumes
__webpack_require__.f.remotes
__webpack_require__.f.MiniCss
__webpack_require__.f.l
3.2.4.2 webpack\_require.f.consumes
var parseVersion = (str) => {
// see webpack/lib/util/semver.js for original code
var p=p=>{return p.split(".").map((p=>{return+p==p?+p:p}))},n=/^([^-+]+)?(?:-([^+]+))?(?:+(.+))?$/.exec(str),r=n[1]?p(n[1]):[];return n[2]&&(r.length++,r.push.apply(r,p(n[2]))),n[3]&&(r.push([]),r.push.apply(r,p(n[3]))),r;
}
var versionLt = (a, b) => {
// see webpack/lib/util/semver.js for original code
a=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++}
}
var rangeToString = (range) => {
// see webpack/lib/util/semver.js for original code
var r=range[0],n="";if(1===range.length)return"*";if(r+.5){n+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,n+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return n}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^((.+))$/,"$1")}
}
var satisfy = (range, version) => {
// see webpack/lib/util/semver.js for original code
if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o();
}
var exists = (scope, key) => {
return scope && __webpack_require__.o(scope, key);
}
var get = (entry) => {
entry.loaded = 1;
return entry.get()
};
var eagerOnly = (versions) => {
return Object.keys(versions).reduce((filtered, version) => {
if (versions[version].eager) {
filtered[version] = versions[version];
}
return filtered;
}, {});
};
var findLatestVersion = (scope, key, eager) => {
var versions = eager ? eagerOnly(scope[key]) : scope[key];
var key = Object.keys(versions).reduce((a, b) => {
return !a || versionLt(a, b) ? b : a;
}, 0);
return key && versions[key];
};
var findSatisfyingVersion = (scope, key, requiredVersion, eager) => {
var versions = eager ? eagerOnly(scope[key]) : scope[key];
var key = Object.keys(versions).reduce((a, b) => {
if (!satisfy(requiredVersion, b)) return a;
return !a || versionLt(a, b) ? b : a;
}, 0);
return key && versions[key]
};
var findSingletonVersionKey = (scope, key, eager) => {
var versions = eager ? eagerOnly(scope[key]) : scope[key];
return Object.keys(versions).reduce((a, b) => {
return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;
}, 0);
};
var getInvalidSingletonVersionMessage = (scope, key, version, requiredVersion) => {
return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"
};
var getInvalidVersionMessage = (scope, scopeName, key, requiredVersion, eager) => {
var versions = scope[key];
return "No satisfying version (" + rangeToString(requiredVersion) + ")" + (eager ? " for eager consumption" : "") + " of shared module " + key + " found in shared scope " + scopeName + ".\n" +
"Available versions: " + Object.keys(versions).map((key) => {
return key + " from " + versions[key].from;
}).join(", ");
};
var fail = (msg) => {
throw new Error(msg);
}
var failAsNotExist = (scopeName, key) => {
return fail("Shared module " + key + " doesn't exist in shared scope " + scopeName);
}
var warn = /*#__PURE__*/ (msg) => {
if (typeof console !== "undefined" && console.warn) console.warn(msg);
};
var init = (fn) => (function(scopeName, key, eager, c, d) {
var promise = __webpack_require__.I(scopeName);
if (promise && promise.then && !eager) {
return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], key, false, c, d));
}
return fn(scopeName, __webpack_require__.S[scopeName], key, eager, c, d);
});
var useFallback = (scopeName, key, fallback) => {
return fallback ? fallback() : failAsNotExist(scopeName, key);
}
var load = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
return get(findLatestVersion(scope, key, eager));
});
var loadVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
if (satisfyingVersion) return get(satisfyingVersion);
warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager))
return get(findLatestVersion(scope, key, eager));
});
var loadStrictVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var satisfyingVersion = findSatisfyingVersion(scope, key, requiredVersion, eager);
if (satisfyingVersion) return get(satisfyingVersion);
if (fallback) return fallback();
fail(getInvalidVersionMessage(scope, scopeName, key, requiredVersion, eager));
});
var loadSingleton = /*#__PURE__*/ init((scopeName, scope, key, eager, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var version = findSingletonVersionKey(scope, key, eager);
return get(scope[key][version]);
});
var loadSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var version = findSingletonVersionKey(scope, key, eager);
if (!satisfy(requiredVersion, version)) {
warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
}
return get(scope[key][version]);
});
var loadStrictSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var version = findSingletonVersionKey(scope, key, eager);
if (!satisfy(requiredVersion, version)) {
fail(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
}
return get(scope[key][version]);
});
var installedModules = {};
var moduleToHandlerMapping = {
"webpack/sharing/consume/default/vue/vue": () => (loadSingletonVersion("default", "vue", false, [1,3,0,11], () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! vue */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js")))))))
};
// no consumes in initial chunks
// 模块依赖的共享依赖
var chunkMapping = {
"src_main_js": [
"webpack/sharing/consume/default/vue/vue"
]
};
var startedInstallModules = {};
__webpack_require__.f.consumes = (chunkId, promises) => {
if(__webpack_require__.o(chunkMapping, chunkId)) {
chunkMapping[chunkId].forEach((id) => {
if(__webpack_require__.o(installedModules, id)) return promises.push(installedModules[id]);
if(!startedInstallModules[id]) {
var onFactory = (factory) => {
installedModules[id] = 0;
__webpack_require__.m[id] = (module) => {
delete __webpack_require__.c[id];
module.exports = factory();
}
};
startedInstallModules[id] = true;
var onError = (error) => {
delete installedModules[id];
__webpack_require__.m[id] = (module) => {
delete __webpack_require__.c[id];
throw error;
}
};
try {
var promise = moduleToHandlerMapping[id]();
if(promise.then) {
promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));
} else onFactory(promise);
} catch(e) { onError(e); }
}
});
}
}
项目里面shared 共享依赖,所以在执行到__webpack_require__.f.consumes开始检查模块是否有对应的共享依赖,这里可以发现就是webpack/sharing/consume/default/vue/vue
接着从moduleToHandlerMapping 对象里面,寻找共享依赖的加载和版本对比逻辑, 通过loadSingletonVersion 函数进行加载,主要我们在配置中设置了singleton: true
var moduleToHandlerMapping = {
"webpack/sharing/consume/default/vue/vue":
() => (loadSingletonVersion("default", "vue", false, [1,3,0,11], () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! vue */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js")))))))
};
<!---->
var loadSingletonVersion = /*#__PURE__*/ init((scopeName, scope, key, eager, requiredVersion, fallback) => {
if (!exists(scope, key)) return useFallback(scopeName, key, fallback);
var version = findSingletonVersionKey(scope, key, eager);
if (!satisfy(requiredVersion, version)) {
warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));
}
return get(scope[key][version]);
});
在执行 loadSingletonVersion之前,首先要执行了 init方法,
var init = (fn) => (function(scopeName, key, eager, c, d) {
var promise = __webpack_require__.I(scopeName);
if (promise && promise.then && !eager) {
return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], key, false, c, d));
}
return fn(scopeName, __webpack_require__.S[scopeName], key, eager, c, d);
});
继续走到init方法,里面有__webpack_require__.I,接着看I函数,它是一个独立的模块,在runtime/share
3.2.4.3 webpack\_require.I
__webpack_require__.S = {};
var initPromises = {};
var initTokens = {};
__webpack_require__.I = (name, initScope) => {
if(!initScope) initScope = [];
// handling circular init calls
var initToken = initTokens[name];
if(!initToken) initToken = initTokens[name] = {};
if(initScope.indexOf(initToken) >= 0) return;
initScope.push(initToken);
// only runs once
if(initPromises[name]) return initPromises[name];
// creates a new share scope if needed
if(!__webpack_require__.o(__webpack_require__.S, name)) __webpack_require__.S[name] = {};
// runs all init snippets from all modules reachable
var scope = __webpack_require__.S[name];
var warn = (msg) => {
if (typeof console !== "undefined" && console.warn) console.warn(msg);
};
var uniqueName = "vue3-demo_layout";
var register = (name, version, factory, eager) => {
var versions = scope[name] = scope[name] || {};
var activeVersion = versions[version];
if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };
};
var initExternal = (id) => {
var handleError = (err) => (warn("Initialization of sharing external failed: " + err));
try {
var module = __webpack_require__(id);
if(!module) return;
var initFn = (module) => (module && module.init && module.init(__webpack_require__.S[name], initScope))
if(module.then) return promises.push(module.then(initFn, handleError));
var initResult = initFn(module);
if(initResult && initResult.then) return promises.push(initResult['catch'](handleError));
} catch(err) { handleError(err); }
}
var promises = [];
switch(name) {
case "default": {
register("vue", "3.3.7", () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! ../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js"))))));
initExternal("webpack/container/reference/home");
}
break;
}
if(!promises.length) return initPromises[name] = 1;
return initPromises[name] = Promise.all(promises).then(() => (initPromises[name] = 1));
};
执行到register里面,可以看到还是将共享依赖,包括具体版本号,设置到了全局变量__webpack_require__.S上面,数据结构就是
__webpack_require__.S[version] = { get: factory, from: uniqueName, eager: !!eager }
里面包括了依赖的
- 版本号3.3.7,
- from:vue3-demo\_layout 来源、
- Get: 获取方法
() => (__webpack_require__.e("vendors-
具体到我们的demo,可以看一下
{
"default": {
"vue": {
"3.3.7": {
"from": "vue3-demo_layout",
"eager": false
// get 包括了具体vue如何请求到
get: () => (__webpack_require__.e("vendors-node_modules_pnpm_vue_3_3_7_typescript_5_6_3_node_modules_vue_dist_vue_runtime_esm-bu-3fdf17").then(() => (() => (__webpack_require__(/*! ../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js */ "../../node_modules/.pnpm/vue@3.3.7_typescript@5.6.3/node_modules/vue/dist/vue.runtime.esm-bundler.js")))))
}
}
}
}
<!---->
__webpack_require__ .S
register后,接着就是加载远程应用
__webpack_require__(webpack/container/reference/home),这个模块在前面已经注册过了
{
/***/ "webpack/container/reference/home":
/*!************************************************************!*\
!*** external "home@http://localhost:3002/remoteEntry.js" ***!
************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
var __webpack_error__ = new Error();
module.exports = new Promise((resolve, reject) => {
if(typeof home !== "undefined") return resolve();
__webpack_require__.l("http://localhost:3002/remoteEntry.js", (event) => {
if(typeof home !== "undefined") return resolve();
var errorType = event && (event.type === 'load' ? 'missing' : event.type);
var realSrc = event && event.target && event.target.src;
__webpack_error__.message = 'Loading script failed.\n(' + errorType + ': ' + realSrc + ')';
__webpack_error__.name = 'ScriptExternalLoadError';
__webpack_error__.type = errorType;
__webpack_error__.request = realSrc;
reject(__webpack_error__);
}, "home");
}).then(() => (home));
/***/ }
其实通过__webpack_require__.l 函数,加载远程模块入口文件http://localhost:3002/remoteEntry.js
var moduleMap = {
"./Content": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Content_vue-_cddc0")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Content */ "./src/components/Content.vue")))));
},
"./Button": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Button_js")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Button */ "./src/components/Button.js")))));
}
};
var init = (shareScope, initScope) => {
if (!__webpack_require__.S) return;
var name = "default"
var oldScope = __webpack_require__.S[name];
if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");
__webpack_require__.S[name] = shareScope;
return __webpack_require__.I(name, initScope);
};
var get = (module, getScope) => {
__webpack_require__.R = getScope;
getScope = (
__webpack_require__.o(moduleMap, module)
? moduleMap[module]()
: Promise.resolve().then(() => {
throw new Error('Module "' + module + '" does not exist in container.');
})
);
__webpack_require__.R = undefined;
return getScope;
};
// This exports getters to disallow modifications
__webpack_require__.d(exports, {
get: () => (get),
init: () => (init)
});
加载完成后,执行加载模块remoteEntry.js里面暴露的init方法, 把当前上下文中的__webpack_require__.S和initScope作为参数
var initFn = (module) => (module && module.init && module.init(__webpack_require__.S[name], initScope))
接下来执行init函数时,需要明确一下是在remoteEntry.js这个文件上下文中执行的。里面也有一套同样的webpack模块加载函数和存储变量,虽然命名一样。
init方法里面,通过内部\_\_webpack\_require\_\_.S进行存储共享依赖,name也是对应'default',直接复用前面注册在S上的vue依赖,再次调用\_\_webpack\_require.I\_\_, 注册自己的依赖。
__webpack_require__.S[name] = shareScope;
里面的这段很重要shareScope是在host应用中把__webpack_require__.S[name]作为参数传入的,本质上是src/main.js(host)文件和remoteEntry.js(remote)文件之间,通过全局变量,传递各自上下文中的内部变量(__webpack_require__.S)上的共享依赖。
所以等价于
remote___webpack_require__.S[name] = host___webpack_require__.S[name]
消费者和生产者里面注册的模块是同一个所以注册完成后\_\_webpack\_require\_\_.S里面还是只有一个3.3.7版本的vue
到这里共享依赖初始化完成了。
3.2.4.4 webpack\_require.f.j
继续执行f上挂载的方法remoes,此时src/main.js模块,没有在chunkMapping里面没有映射到对应的共享依赖,直接跳过了remotes方法,继续走后面的处理逻辑,这里可以直接跳过,最后通过\_\_webpack\_require\_\_.f.j 函数加载src/main.js文件。同前面异步加载逻辑一样,放到\_\_webpack\_module\_\_变量里面,
{
/***/ "./src/main.js":
/*!*********************!*\
!*** ./src/main.js ***!
*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "webpack/sharing/consume/default/vue/vue");
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Layout_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Layout.vue */ "./src/Layout.vue");
const Content = (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(() => __webpack_require__.e(/*! import() */ "webpack_container_remote_home_Content").then(__webpack_require__.t.bind(__webpack_require__, /*! home/Content */ "webpack/container/remote/home/Content", 23)));
const Button = (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(() => __webpack_require__.e(/*! import() */ "webpack_container_remote_home_Button").then(__webpack_require__.t.bind(__webpack_require__, /*! home/Button */ "webpack/container/remote/home/Button", 23)));
const app = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createApp)(_Layout_vue__WEBPACK_IMPORTED_MODULE_1__["default"]);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
/***/ })
}
main.js里面引用Content和Button组件,构建时转换成 __webpack_require__.e(/*! import() */ "webpack_container_remote_home_Content")函数,跟[前面的src\_main\_js加载类似],开始遍历执行\_\_webpack\_require\_\_.f上的挂载方法,执行到\_\_webpack\_require\_\_.f.consumes时,没有映射到共享依赖跳过,继续执行到__webpack_require__.f.remotes
3.2.4.5 webpack\_require.f.remotes
var chunkMapping = {
"webpack_container_remote_home_Content": [
"webpack/container/remote/home/Content"
],
"webpack_container_remote_home_Button": [
"webpack/container/remote/home/Button"
]
};
var idToExternalAndNameMapping = {
"webpack/container/remote/home/Content": [
"default",
"./Content",
"webpack/container/reference/home"
],
"webpack/container/remote/home/Button": [
"default",
"./Button",
"webpack/container/reference/home"
]
};
__webpack_require__.f.remotes = (chunkId, promises) => {
if(__webpack_require__.o(chunkMapping, chunkId)) {
chunkMapping[chunkId].forEach((id) => {
var getScope = __webpack_require__.R;
if(!getScope) getScope = [];
var data = idToExternalAndNameMapping[id];
if(getScope.indexOf(data) >= 0) return;
getScope.push(data);
if(data.p) return promises.push(data.p);
var onError = (error) => {
if(!error) error = new Error("Container missing");
if(typeof error.message === "string")
error.message += '\nwhile loading "' + data[1] + '" from ' + data[2];
__webpack_require__.m[id] = () => {
throw error;
}
data.p = 0;
};
var handleFunction = (fn, arg1, arg2, d, next, first) => {
try {
var promise = fn(arg1, arg2);
if(promise && promise.then) {
var p = promise.then((result) => (next(result, d)), onError);
if(first) promises.push(data.p = p); else return p;
} else {
return next(promise, d, first);
}
} catch(error) {
onError(error);
}
}
var onExternal = (external, _, first) => (external ? handleFunction(__webpack_require__.I, data[0], 0, external, onInitialized, first) : onError());
var onInitialized = (_, external, first) => (handleFunction(external.get, data[1], getScope, 0, onFactory, first));
var onFactory = (factory) => {
data.p = 1;
__webpack_require__.m[id] = (module) => {
module.exports = factory();
}
};
handleFunction(__webpack_require__, data[2], 0, 0, onExternal, 1);
});
}
}
可以发现webpack_container_remote_home_Content在chunkMapping里面已经声明了,chunkMapping保存依赖的远程应用具体模块id,idToExternalAndNameMapping则保存远程模块的具体信息,看最后的执行入口函数
handleFunction(__webpack_require__, data[2], 0, 0, onExternal, 1);
var handleFunction = (fn, arg1, arg2, d, next, first) => {
try {
var promise = fn(arg1, arg2);
if(promise && promise.then) {
var p = promise.then((result) => (next(result, d)), onError);
if(first) promises.push(data.p = p); else return p;
} else {
return next(promise, d, first);
}
} catch(error) {
onError(error);
}
}
data[2]表示依赖的远程应用资源 "webpack/container/reference/home",直接执行
var promise = fn(arg1, arg2);
=>
__webpack_require__("webpack/container/reference/home", 0)
这个require在前面已经执行完成了,主要请求remoteEntry.js文件,存在缓存,直接从__webpack_module_cache__里面获取执行结果,也就是export上抛出的get和init方法。
正在promise.then方法里面,执行传入的next函数,也就是第5个参数onExternal
var onExternal = (external, _, first) => (external ? handleFunction(__webpack_require__.I, data[0], 0, external, onInitialized, first) : onError());
继续执行handleFunction函数
handleFunction(__webpack_require__.I, 'default', 0, external, onInitialized, first)
<!---->
var promise = fn(arg1, arg2);
=>
__webpack_require__.I('default', 0),
就是前面在consumes方法里面,寻找并注册共享依赖,执行完成后继续执行next方法,也就是第5个参数onInitialized
<!---->
var onInitialized = (_, external, first) => (handleFunction(external.get, data[1], getScope, 0, onFactory, first));
<!---->
handleFunction(external.get, './Content', getScope, 0, onFactory, first )
这里external就是第一次执行\_\_webpack\_require\_\_("webpack/container/reference/home", 0),返回的promise结果,也就是远程应用remoteEntry.js里面的内容
回到remoteEntry.js里面,可以发现get方法
var moduleMap = {
"./Content": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Content_vue-_cddc0")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Content */ "./src/components/Content.vue")))));
},
"./Button": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Button_js")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Button */ "./src/components/Button.js")))));
}
};
var get = (module, getScope) => {
__webpack_require__.R = getScope;
getScope = (
__webpack_require__.o(moduleMap, module)
? moduleMap[module]()
: Promise.resolve().then(() => {
throw new Error('Module "' + module + '" does not exist in container.');
})
);
__webpack_require__.R = undefined;
return getScope;
};
moduleMap['./Content'](),这里同样有__webpack_require__.e,但在是在远程应用的执行上下文里面,跟当前主应用的执行环境不同,这里是远程应用根据自己的webpack配置生成的webpack\_require相关函数,也是真正打包构建‘./Content’共享组件的地方。
继续递归,这个get方法执行完成后,promise.then里面的next方法,也就是onFactory函数,
var onFactory = (factory) => {
data.p = 1;
__webpack_require__.m[id] = (module) => {
module.exports = factory();
}
};
__webpack_require__.m = __webpack_modules__;
把获取到的./Content函数主体,从远程应用的上下文,重新赋值到当前host应用的\_\_webpack\_modules\_\_变量下,
后续再遇到引入./Content组件的场景,直接从\_\_webpack\_modules\_\_上获取,
[回到src\_main\_js的实现部分],继续引入Button.js组件,执行后续操作
3.2.5 整体组件加载执行过程

3.3 Module Federation Runtime API 加载流程
3.3.1 概述
官方提供的Runtime API进行模块注册和加载,很大程度上打破了构建工具的限制,在一些老版本的项目上,也可以直接使用共享模块。从构建插件转向自定义的API提供加载,同时提供了更多的自定义配置和生命钩子函数。
深入理解API模型加载,可以发现实际上面模拟了前面构建时加载里面的动态创建script标签和通过全局的S变量进行共享库传递等核心功能。
3.3.2 初始化请求链路
跟前面module federation构建时加载流程有一点区别,remoteEntry.js文件的请求发起者是前置的基础库,也就是@module-federation/runtime-core。这是因为修改成Runtime API形式,使用官方库提供的loadRemote方法动态加载组件,而构建版本通过插件,在构建时已经将发起请求的逻辑注入到了前置的main.js文件中了。
这里主要关注host,也就是消费者(Layout)应用,在使用官方提供的API动态加载时的流程,所以在host应用中去掉webpack配置文件中的ModuleFederationPlugin 插件。
//const { ModuleFederationPlugin } = require('webpack').container;
...
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
// new ModuleFederationPlugin({
// name: 'layout',
// filename: 'remoteEntry.js',
// remotes: {
// home: 'home@http://localhost:3002/remoteEntry.js',
// },
// exposes: {},
// shared: {
// vue: {
// singleton: true,
// },
// },
// }),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './index.html'),
chunks: ['main'],
}),
new VueLoaderPlugin(),
],
在入口main.js里面修改引入远程的组件的方法(红色部分为改动)
用了init和loadRemote两个Runtime API
import { createApp, defineAsyncComponent } from 'vue';
import Layout from './Layout.vue';
import { init, loadRemote } from '@module-federation/runtime';
init({
name: 'layout',
remotes: [
{
name: 'home',
entry: 'http://localhost:3002/remoteEntry.js',
},
],
shared: {
vue: {
singleton: true,
},
},
});
const Content = defineAsyncComponent(async () => await loadRemote('home/Content'));
const Button = defineAsyncComponent(async () => await loadRemote('home/Button'));
const app = createApp(Layout);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
3.3.3 源码与构建后代码对照
大部分代码跟构建时类似,只有在正式初始化和加载远程组件时,需要调用前置加载的module-federation/runtime-core基础库
3.3.3.1 依赖库
http://localhost:3001/vendors-node_modules_pnpm_mini-css-extr...
"use strict";
(self["webpackChunkvue3_demo_layout"] = self["webpackChunkvue3_demo_layout"] || []).push([["vendors-node_modules_pnpm_mini-css-extract-plugin_2_9_2_webpack_5_96_1__swc_core_1_9_2__swc_h-8958a1"],{
"../../node_modules/.pnpm/@module-federation+runtime@0.20.0/node_modules/@module-federation/runtime/dist/index.esm.js":
/*!****************************************************************************************************************************!*\
!*** ../../node_modules/.pnpm/@module-federation+runtime@0.20.0/node_modules/@module-federation/runtime/dist/index.esm.js ***!
****************************************************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Module: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.Module),
/* harmony export */ ModuleFederation: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.ModuleFederation),
/* harmony export */ createInstance: () => (/* binding */ createInstance),
/* harmony export */ getInstance: () => (/* binding */ getInstance),
/* harmony export */ getRemoteEntry: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.getRemoteEntry),
/* harmony export */ getRemoteInfo: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.getRemoteInfo),
/* harmony export */ init: () => (/* binding */ init),
/* harmony export */ loadRemote: () => (/* binding */ loadRemote),
/* harmony export */ loadScript: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.loadScript),
/* harmony export */ loadScriptNode: () => (/* reexport safe */ _module_federation_runtime_core__WEBPACK_IMPORTED_MODULE_0__.loadScriptNode),
/* harmony export */ loadShare: () => (/* binding */ loadShare),
/* harmony export */ loadShareSync: () => (/* binding */ loadShareSync),
/* harmony export */ preloadRemote: () => (/* binding */ preloadRemote),
...
})
3.3.3.2 main.js文件
3.3.3.2.1 源码
import { createApp, defineAsyncComponent } from 'vue';
import Layout from './Layout.vue';
import { init, loadRemote } from '@module-federation/runtime';
init({
name: 'layout',
remotes: [
{
name: 'home',
entry: 'http://localhost:3002/remoteEntry.js',
},
],
shared: {
vue: {
singleton: true,
},
},
});
const Content = defineAsyncComponent(async () => await loadRemote('home/Content'));
const Button = defineAsyncComponent(async () => await loadRemote('home/Button'));
const app = createApp(Layout);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
3.3.3.2.2 构建后代码
"use strict";
(self["webpackChunkvue3_demo_layout"] = self["webpackChunkvue3_demo_layout"] || []).push([["src_main_js"], {
/***/
"./src/main.js": /*!*********************!*\
!*** ./src/main.js ***!
*********************/
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */
/* harmony import */
var _Layout_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Layout.vue */
"./src/Layout.vue");
/* harmony import */
var _module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @module-federation/runtime */
"../../node_modules/.pnpm/@module-federation+runtime@0.20.0/node_modules/@module-federation/runtime/dist/index.esm.js");
(0,
_module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__.init)({
name: 'layout',
remotes: [{
name: 'home',
entry: 'http://localhost:3002/remoteEntry.js',
}, ],
shared: {
vue: {
singleton: true,
},
},
});
const Content = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(async () => await (0,
_module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__.loadRemote)('home/Content'));
const Button = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(async () => await (0,
_module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__.loadRemote)('home/Button'));
const app = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.createApp)(_Layout_vue__WEBPACK_IMPORTED_MODULE_1__["default"]);
app.component('content-element', Content);
app.component('button-element', Button);
app.mount('#app');
/***/
}
)
}]);
3.3.4 过程分析
分析这里的init和loadRemote API就不用从入口文件加载开始,按照顺序分析,重点关注方法本身就行,也就是@module-federation/runtime里面的代码
还是看一下原始的main.js里面,init和loadRemote方法构建后源码;
"./src/main.js": /*!*********************!*\
/***/
( (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */
/* harmony import */
var _module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @module-federation/runtime */
"../../node_modules/.pnpm/@module-federation+runtime@0.20.0/node_modules/@module-federation/runtime/dist/index.esm.js");
(0,
_module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__.init)({
name: 'layout',
remotes: [{
name: 'home',
entry: 'http://localhost:3002/remoteEntry.js',
}, ],
shared: {
vue: {
singleton: true,
},
},
});
const Content = (0,
vue__WEBPACK_IMPORTED_MODULE_0__.defineAsyncComponent)(async () => await (0,
_module_federation_runtime__WEBPACK_IMPORTED_MODULE_2__.loadRemote)('home/Content'));
/***/
}
)
提前获取@module-federation/runtime module,这个module在前置的公共chunk里面,也就是demo里面对应的http://localhost:3001/vendors-node_modules_pnpm_mini-css-extr... 文件。
异步模块加载的流程这里就不细讲了,聚焦到@module-federation/runtime仓库。
3.3.4.1 init方法
<!---->
3.3.4.1.1 传入参数
查看源码位置:core/packages/runtime/src/index.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-federation/c
export function createInstance(options: UserOptions) {
// Retrieve debug constructor
const ModuleFederationConstructor =
getGlobalFederationConstructor() || ModuleFederation;
const instance = new ModuleFederationConstructor(options);
setGlobalFederationInstance(instance);
return instance;
}
let FederationInstance: ModuleFederation | null = null;
/**
* @deprecated Use createInstance or getInstance instead
*/
export function init(options: UserOptions): ModuleFederation {
// Retrieve the same instance with the same name
const instance = getGlobalFederationInstance(options.name, options.version);
if (!instance) {
FederationInstance = createInstance(options);
return FederationInstance;
} else {
// Merge options
instance.initOptions(options);
if (!FederationInstance) {
FederationInstance = instance;
}
return instance;
}
}
官方文档里面推荐使用createInstance方法取代init.
init方法只做 一次单实例的前置校验,通过getGlobalFederationInstance方法,判断相同name命名的实例是否已经注册过。没有注册则用createInstance 传入配置项初始化一个实例
3.3.4.1.2 runtime-core中执行构造函数
实例对应的构造函数ModuleFederation,在另一个依赖里面@module-federation/runtime-core 实现,
对应源码位置 https://github.com/module-federation/core/blob/cfae7c06bd0f19aea0757fb2bcb7088ac29457cb/packages/runtime-core/src/core.ts#L171
constructor(userOptions: UserOptions) {
const plugins = USE_SNAPSHOT
? [snapshotPlugin(), generatePreloadAssetsPlugin()]
: [];
// TODO: Validate the details of the options
// Initialize options with default values
// 合并用户选项和默认选项
const defaultOptions: Options = {
id: getBuilderId(),
name: userOptions.name,
plugins,
remotes: [],
shared: {},
inBrowser: isBrowserEnv(),
};
this.name = userOptions.name;
this.options = defaultOptions;
// 2. 初始化各个处理器
this.snapshotHandler = new SnapshotHandler(this);
this.sharedHandler = new SharedHandler(this);
this.remoteHandler = new RemoteHandler(this);
this.shareScopeMap = this.sharedHandler.shareScopeMap;
// 3. 注册传入的插件
this.registerPlugins([
...defaultOptions.plugins,
...(userOptions.plugins || []),
]);
this.options = this.formatOptions(defaultOptions, userOptions);
}
前面参数传递到这里的constructor并执行。
创建完成后setGlobalFederationInstance(instance); 存储到全局变量,方便后面的loadRemote使用
core/packages/runtime-core/src/global.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-federa
export function setGlobalFederationInstance(
FederationInstance: ModuleFederation,
): void {
CurrentGlobal.__FEDERATION__.__INSTANCES__.push(FederationInstance);
}
3.3.4.2 loadRemote方法
3.3.4.2.1 外层调用查看
函数初始化在外层,具体代码:core/packages/runtime/src/index.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-federation/c
export function loadRemote<T>(
...args: Parameters<ModuleFederation['loadRemote']>
): Promise<T | null> {
assert(FederationInstance, getShortErrorMsg(RUNTIME_009, runtimeDescMap));
const loadRemote: typeof FederationInstance.loadRemote<T> =
FederationInstance.loadRemote;
// eslint-disable-next-line prefer-spread
return loadRemote.apply(FederationInstance, args);
}
继续转到runtime-core的实例构造函数里面查看真正的loadRemote方法。
core/packages/runtime-core/src/core.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-federati
async loadRemote<T>(
id: string,
options?: { loadFactory?: boolean; from: CallFrom },
): Promise<T | null> {
return this.remoteHandler.loadRemote(id, options);
}
this.remoteHandler 已经在前面实例化时,执行了初始化,再转到remote文件里面
github.com
async loadRemote<T>(
id: string,
options?: { loadFactory?: boolean; from: CallFrom },
): Promise<T | null> {
const { host } = this;
try {
const { loadFactory = true } = options || {
loadFactory: true,
};
// 1. 获取 Module 实例和相关配置信息
const { module, moduleOptions, remoteMatchInfo } =
await this.getRemoteModuleAndOptions({
id,
});
..
// 2. 执行module.get
const moduleOrFactory = (await module.get(
idRes,
expose,
options,
remoteSnapshot,
)) as T;
// 3. 调用对应的生命周期钩子
const moduleWrapper = await this.hooks.lifecycle.onLoad.emit({
id: idRes,
pkgNameOrAlias,
expose,
exposeModule: loadFactory ? moduleOrFactory : undefined,
exposeModuleFactory: loadFactory ? undefined : moduleOrFactory,
remote,
options: moduleOptions,
moduleInstance: module,
origin: host,
});
this.setIdToRemoteMap(id, remoteMatchInfo);
// 4. 返回远程组件的具体实现
return moduleOrFactory;
} catch (error) {
return failOver as T;
}
}
remoteHandle.loadRemote管理整个远程应用加载的执行顺序,并最终返回共享组件的具体内容。
3.3.4.2.2 New Module
通过getRemoteModuleAndOptions获取Module实例和相关配置信息,getRemoteModuleAndOptions里面除了初始化Module实例 new Module(moduleOptions);前面还有各种钩子函数的执行。
3.3.4.2.3 Module.get
核心逻辑都在Module.get函数里面,后面主要分析这个get方法
Module实例可以简单理解成管理和加载远程模块remoteEntry.js的构造函数,
具体看Module 构造函数后面的get方法
core/packages/runtime-core/src/module/index.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-
async get(
id: string,
expose: string,
options?: { loadFactory?: boolean },
remoteSnapshot?: ModuleInfo,
) {
const { loadFactory = true } = options || { loadFactory: true };
// 获取remoteEntry.js
const remoteEntryExports = await this.getEntry();
....
await remoteEntryExports.init(
initContainerOptions.shareScope,
initContainerOptions.initScope,
initContainerOptions.remoteEntryInitOptions,
);
await this.host.hooks.lifecycle.initContainer.emit({
...initContainerOptions,
id,
remoteSnapshot,
remoteEntryExports,
});
}
this.lib = remoteEntryExports;
this.inited = true;
let moduleFactory;
moduleFactory = await this.host.loaderHook.lifecycle.getModuleFactory.emit({
remoteEntryExports,
expose,
moduleInfo: this.remoteInfo,
});
// get exposeGetter
if (!moduleFactory) {
moduleFactory = await remoteEntryExports.get(expose);
}
assert(
moduleFactory,
`${getFMId(this.remoteInfo)} remote don't export ${expose}.`,
);
// keep symbol for module name always one format
const symbolName = processModuleAlias(this.remoteInfo.name, expose);
const wrapModuleFactory = this.wraperFactory(moduleFactory, symbolName);
if (!loadFactory) {
return wrapModuleFactory;
}
const exposeContent = await wrapModuleFactory();
return exposeContent;
}
module.get里面也包括了对应的生命周期钩子函数,主要关注几个核心的流程,注意这里的钩子函数主要方便用户进行自定义的远程模块加载,而我们主要讨论的是runtime-core提供的默认加载顺序,所以暂时忽略这些钩子的影响
- this.getEntry(): 异步加载remoteEntry.js,在浏览器环境下通过动态创建script标签的方式异步加载远程应用,并执行
- remoteEntryExports.init:加载并执行完成后,拿到remoteEntry.js对外暴露出来的init方法并执行,这一步就是进行共享依赖传递融合,在远程应用中提前传入宿主的共享依赖库,并检查远程应用是否有统一的共享库,为后面的共享组件加载做准备
- remoteEntryExports.get(expose): 执行远程应用对我暴露的get方法,在远程应用的执行上下文中拿到共享组件
<!---->
3.3.4.2.3.1 通过getEntry,异步加载remoteEntry.js
async getEntry(): Promise<RemoteEntryExports> {
...
remoteEntryExports = await getRemoteEntry({
origin: this.host,
remoteInfo: this.remoteInfo,
remoteEntryExports: this.remoteEntryExports,
});
...
this.remoteEntryExports = remoteEntryExports as RemoteEntryExports;
return this.remoteEntryExports;
}
core/packages/runtime-core/src/utils/load.ts at cfae7c06bd0f19aea0757fb2bcb7088ac29457cb · module-fe
export async function getRemoteEntry(params: {
origin: ModuleFederation;
remoteInfo: RemoteInfo;
remoteEntryExports?: RemoteEntryExports | undefined;
getEntryUrl?: (url: string) => string;
_inErrorHandling?: boolean; // Add flag to prevent recursion
}): Promise<RemoteEntryExports | false | void> {
const uniqueKey = getRemoteEntryUniqueKey(remoteInfo);
if (!globalLoading[uniqueKey]) {
const loadEntryHook = origin.remoteHandler.hooks.lifecycle.loadEntry;
const loaderHook = origin.loaderHook;
globalLoading[uniqueKey] = loadEntryHook
.emit({
loaderHook,
remoteInfo,
remoteEntryExports,
})
.then((res) => {
if (res) {
return res;
}
// Use ENV_TARGET if defined, otherwise fallback to isBrowserEnv, must keep this
const isWebEnvironment =
typeof ENV_TARGET !== 'undefined'
? ENV_TARGET === 'web'
: isBrowserEnv();
return isWebEnvironment
? loadEntryDom({
remoteInfo,
remoteEntryExports,
loaderHook,
getEntryUrl,
})
: loadEntryNode({ remoteInfo, loaderHook });
})
.catch(async (err) => {
throw err;
});
}
return globalLoading[uniqueKey];
}
这里有个钩子loadEntryHook.emit,就是支持用户自定义加载remoteEntry.js函数,如果没有配置,则继续判断是否在浏览器环境,是则通过loadEntryDom进行动态创建script标签。
async function loadEntryDom({
remoteInfo,
remoteEntryExports,
loaderHook,
getEntryUrl,
}: {
remoteInfo: RemoteInfo;
remoteEntryExports?: RemoteEntryExports;
loaderHook: ModuleFederation['loaderHook'];
getEntryUrl?: (url: string) => string;
}) {
const { entry, entryGlobalName: globalName, name, type } = remoteInfo;
switch (type) {
case 'esm':
case 'module':
return loadEsmEntry({ entry, remoteEntryExports });
case 'system':
return loadSystemJsEntry({ entry, remoteEntryExports });
default:
return loadEntryScript({
entry,
globalName,
name,
loaderHook,
getEntryUrl,
});
}
}
loadEntryDom里面区别了不同的加载方法,默认走到loadEntryScript, 加载并执行remoteEntry.js
async function loadEntryScript({
name,
globalName,
entry,
loaderHook,
getEntryUrl,
}: {
name: string;
globalName: string;
entry: string;
loaderHook: ModuleFederation['loaderHook'];
getEntryUrl?: (url: string) => string;
}): Promise<RemoteEntryExports> {
// if getEntryUrl is passed, use the getEntryUrl to get the entry url
const url = getEntryUrl ? getEntryUrl(entry) : entry;
return loadScript(url, {
attrs: {},
createScriptHook: (url, attrs) => {
const res = loaderHook.lifecycle.createScript.emit({ url, attrs });
},
})
.then(() => {
return handleRemoteEntryLoaded(name, globalName, entry);
})
}
3.3.4.2.3.2 执行remoteEntryExports.init,进行共享依赖传递融合
拿到remoteEntryExports内容后,继续Module.get后面的逻辑,后面开始处理远程应用的共享依赖shareScope了,其中shareScrope是我们初始化配置,同时也支持钩子函数设置,最后将处理的shareScope传入remoteEntryExports.init,开始共享依赖库跨应用传递
await remoteEntryExports.init(
initContainerOptions.shareScope,
initContainerOptions.initScope,
initContainerOptions.remoteEntryInitOptions,
);
这里对应了前面构建时加载的[module.init], 有点类似
var initFn = (module) => (module && module.init && module.init(__webpack_require__.S[name], initScope))
回到remoteEntry.js文件,再看一次里面的init和get方法
var moduleMap = {
"./Content": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Content_vue-_94460")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Content */ "./src/components/Content.vue")))));
},
"./Button": () => {
return Promise.all([__webpack_require__.e("webpack_sharing_consume_default_vue_vue"), __webpack_require__.e("src_components_Button_js")]).then(() => (() => ((__webpack_require__(/*! ./src/components/Button */ "./src/components/Button.js")))));
}
};
var get = (module, getScope) => {
__webpack_require__.R = getScope;
getScope = (
__webpack_require__.o(moduleMap, module)
? moduleMap[module]()
: Promise.resolve().then(() => {
throw new Error('Module "' + module + '" does not exist in container.');
})
);
__webpack_require__.R = undefined;
return getScope;
};
var init = (shareScope, initScope) => {
if (!__webpack_require__.S) return;
var name = "default"
var oldScope = __webpack_require__.S[name];
if(oldScope && oldScope !== shareScope) throw new Error("Container initialization failed as it has already been initialized with a different share scope");
__webpack_require__.S[name] = shareScope;
return __webpack_require__.I(name, initScope);
};
这里执行的init函数
__webpack_require__.S是 Webpack 运行时内部用来存储所有共享作用域 (Share Scopes) 的地方,表示当前运行环境不支持共享功能,
var oldScope = __webpack_require__.S[name];表示远程应用上进行共享配置项目,并进行缓存处理,这里进行oldScope && oldScope !== shareScope判断,主要兼容remoteEntry.js被加载多次的场景,比如远程应用在当前页面被多个宿主(host)引入并初始化,host-a 和host-b在一个页面被加载,他们都依赖同一个remote,远程应用的运行时只能有统一的远程应用的share scope。
如何进行共享依赖呢?其实获取保存宿主传递过来的shareScope,__webpack_require__.S[name] = shareScope,这里通常是vue、react这些共享库。
这里共享依赖init函数就执行完成后,继续Module.get函数后面的流程
3.3.4.2.3.3 执行远程应用remoteEntryExports暴露出来的get方法,加载共享组件Content,并返回给宿主应用
moduleFactory = await remoteEntryExports.get(expose);
关键的一步就是执行remoteEntryExports.get('home/Content')
继续到moduleMap['./Content'](),找到content远程组件真实的地址,并通过__webpack_require__.e进行异步获取src_components_Content_vue-_94460
3.3.4.2.4 Return moduleFactory
到这里远程组件才真正获取完成。moduleFactory返回给宿主。
3.3.5 整体组件加载执行过程

4. 项目实操
<!---->
4.1 如何动态引入远程应用的remoteEntry.js如何进行控制?
- 通过构建时注入变量进行控制,达到版本迭代的效果
- 直接固定一个加时间戳的cdn资源,进行实时更新
4.2 远程应用加载失败如何处理?
- 在runtime API里面,通过了自定义的钩子进行远程应用加载及加载失败的回调上报
- 远程组件尽量包裹在React/Vue 的Suspense组件里面。
4.3 js/css作用域控制?
- 人为约定控制,BEM、css scope、css in js、Shadow DOM
4.4 其他一些类似的模块组件级加载方案
<!---->
const app = await Garfish.loadApp('vue-app', {
cache: true,
basename,
domGetter: '#container',
// 子应用的入口资源地址,支持 HTML 和 JS
entry: 'http://localhost:8092',
});
setApp(app);
<!---->
this.microApp = loadMicroApp({
name: 'app1',
entry: '//localhost:1234',
container: this.containerRef.current,
props: { brand: 'qiankun' },
});