带有 Webpack 模块联合的 Vue 3 CLI:组件从错误的主机加载

Posted

技术标签:

【中文标题】带有 Webpack 模块联合的 Vue 3 CLI:组件从错误的主机加载【英文标题】:Vue 3 CLI with Webpack Module Federation: Components load from wrong host 【发布时间】:2021-09-17 17:13:49 【问题描述】:

我目前正在尝试建立一个使用 Webpack 的 Module Federation 来共享组件的项目。

为此,我使用 cli 设置了两个基本的 vue 项目,并在两个项目中添加了一个 vue.config.js 文件:

宿主项目(将包含共享组件)(在 localhost:8000 上运行)

const  ModuleFederationPlugin  = require('webpack').container

module.exports = 
  configureWebpack: 
    plugins: [
      new ModuleFederationPlugin(
        name: 'shell',
        filename: 'remoteEntry.js',
        remotes: 
          component: 'component@http://localhost:8001/remoteEntry.js'
        ,
        exposes: ,
        shared: 
      )
    ]
  

组件项目(共享组件)(在 localhost:8001 上运行):

const  ModuleFederationPlugin  = require('webpack').container

module.exports = 
  configureWebpack: 
    plugins: [
      new ModuleFederationPlugin(
        name: 'component',
        filename: 'remoteEntry.js',
        remotes: ,
        exposes: 
          './HelloWorld': './src/components/HelloWorld.vue'
        ,
        shared: 
      )
    ]
  

我尝试在我的 App.vue 中加载组件:

<template>
  <img  src="./assets/logo.png" />
  <HelloWorld msg="Welcome to Your Vue.js App" />
  <otherComp />
</template>

<script>
import  defineAsyncComponent  from "vue";
import HelloWorld from "./components/HelloWorld.vue";

const otherComp = defineAsyncComponent(() => import("component/HelloWorld"));

export default 
  name: "App",
  components: 
    HelloWorld,
    otherComp,
  ,
;
</script>

确实它会尝试加载组件,但不是从 localhost:8001(组件所在的位置)加载它,而是尝试从 localhost:8000 加载它:

localhost:8001 上的相同路径确实存在。一些调试显示,webpack publicPath 似乎设置为“/”(导致 localhost:8000 的托管应用程序将 url 设置为/js/src_components_HelloWorld_vue.js

/******/    /* webpack/runtime/publicPath */
/******/    !function() 
/******/        __webpack_require__.p = "/";
/******/    ();

我相信这是由于 vue-cli 与 webpack 交互的方式。这是一个已知问题吗?如何解决?

【问题讨论】:

我认为您的问题很清楚,但是,我认为宿主项目是托管其他人可以使用的组件的项目。另一方面,您有一个使用主机组件的消费项目。我在回答中这样指定它以明确区分两者。 【参考方案1】:

您是否尝试更改 publicPath 变量 (source)?它采用绝对路径 / 作为默认值,但您必须在两个项目的 vue.config.js 中明确设置它们。我描述了一个关于如何配置它的详细示例。为简单起见,host 项目是公开组件的项目。 consumer 项目是使用这些远程组件的项目。

    host 项目应该公开组件。因此,您明确需要将 publicPath 变量设置为完整的主机名。请注意,devServer.port 设置为 8000,因此您不必手动执行此操作。

     // vue.config.js host project 
    
     const ModuleFederationPlugin =
       require("webpack").container.ModuleFederationPlugin;
    
     module.exports = 
       publicPath: "http://localhost:8000/",
       configureWebpack: 
         plugins: [
           new ModuleFederationPlugin(
             name: "host",
             filename: "remoteEntry.js",
             exposes: 
               "./HelloWorld": "./src/components/HelloWorld",
             ,
           ),
         ],
       ,
       devServer: 
         port: 8000,
       ,
     ;
    

    另一方面,我们有一个使用这些组件的项目,通过remotes 字段指定。为了简单起见,这是 consumer 项目。同样,我们将publicPath 设置为运行它的主机。请注意,要使用远程组件,我们必须知道宿主项目的名称、主机名和端口:host@http://localhost:8000/remoteEntry.js

     // vue.config.js consumer project
    
     const ModuleFederationPlugin =
       require("webpack").container.ModuleFederationPlugin;
    
     module.exports = 
       publicPath: "http://localhost:8001/",
       configureWebpack: 
         plugins: [
           new ModuleFederationPlugin(
             name: "consumer",
             filename: "remoteEntry.js",
             remotes: 
               host: "host@http://localhost:8000/remoteEntry.js",
             ,
           ),
         ],
       ,
       devServer: 
         port: 8001,
       ,
     ;
    

您可以在Github 存储库中找到 Webpack Module Federation 的作者提供的一个非常详细的示例。这个示例项目同时使用了 Vue 和 Webpack。您可能还需要一些额外的功能:

    使用remotes 选项,您可以指定多个远程源。这就是拥有许多微前端的想法。例如:

     new ModuleFederationPlugin(
       // ...
       remotes: 
         host: "host@http://localhost:8000/remoteEntry.js",
         other: "other@http://localhost:9000/remoteEntry.js",
       
     )
    

    shared 选项允许您在实例之间共享依赖关系。例如,您可以共享 UIkit,以便两个实例具有相同的样式。但是,在共享 vue、react 或 angular 等软件包时仍有一些注意事项。您可能会遇到以下错误:Shared module is not available for eager consumption。此post 描述了解决此问题的几种方法,这是其中之一:

     const deps = require('./package.json').dependencies
    
     new ModuleFederationPlugin(
       // ...
       shared: 
         ...deps,
         vue: 
           eager: true,
           singleton: true,
           requiredVersion: deps.vue,
           strictVersion: true,
         ,
       ,
     )
    

注意:ModuleFederation 仅包含在 webpack 5(及更高版本)中。

【讨论】:

@RoarS。他正在向 OP 提出这个建议,当 OP 可以在 30 多岁时做到这一点时,他不会尝试在本地复制他的设置。而且,并不是因为它是 500rep,所以你也不需要花几天时间。

以上是关于带有 Webpack 模块联合的 Vue 3 CLI:组件从错误的主机加载的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS 和 Webpack 模块联合应用程序在部署到云端时包含未定义的 url

Vue09 Webpack Part5 Vue组件化开发

在vue-cli3.0中配置webpack

Vue-Router路由Vue-CLI脚手架和模块化开发 之 Vue-CLI 2.x脚手架工具基于webpack simple模板与基于webpack模板构建项目

@vue/cli 3 安装搭建及 webpack 配置

Webpack 5 模块联合:使用身份验证访问远程模块