彻底搞懂 Module Federation(中上):Webpack 异步加载流程

2 阅读18分钟

本文是《彻底搞懂 Module Federation》系列的第2篇,深入分析 Webpack 异步加载的底层原理。

📚 系列文章

  • 📖 第1篇:概述与实战示例
  • 第2篇(本文):原理分析 - Webpack 异步加载流程
  • 📖 第3篇:原理分析 - MF 模块加载(上)
  • 📖 第4篇:原理分析 - MF 模块加载(下)
  • 📖 第5篇:原理分析 - Runtime API + 项目实操

3. 原理分析

not magic, just async chunk

大白话解释一下,共享组件单独打包成一个异步chunk里面,共享的依赖会在加载组件之前进行前置加载,中间有一些复杂的依赖版本号比较,依赖库加载的逻辑通过shared字段进行配置。

这里的加载模块流程分析准备分三部分,首先介绍最基础的webpack异步模块加载流程,后面分别介绍module federation两个引入方式对应不同的加载流程

3.1 webpack异步模块加载流程

3.1.1 按需加载

按需加载,也叫异步加载、动态导入,即只在有需要的时候才去下载相应的资源文件。

在 webpack 中可以使用 importrequire.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加载过程,大致可以推测一下,它主要任务有两个

  1. 通过创建一个script标签,并设置到html里面,发起请求main.js文件,并自动执行main.js
  2. ...
  3. __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 整体组件加载执行过程

image-8.png


👉 下一篇彻底搞懂 Module Federation(中中):MF 模块加载(上)