vue.js - 带有 Webpack 模块联合 : Components load from wrong host 的 Vue 3 CLI

标签 vue.js webpack vue-cli webpack-module-federation

我目前正在尝试建立一个使用 Webpack 的模块联合来共享组件的项目。
为此,我使用 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 alt="Vue logo" 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 交互的方式。这是一个已知问题,如何解决?

最佳答案

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

  • 主持人项目应该公开组件。所以你明确需要设置 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 指定的。 field 。为了简单起见,这是 消费者 项目。我们再次设置 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(及更高版本)中。

    关于vue.js - 带有 Webpack 模块联合 : Components load from wrong host 的 Vue 3 CLI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68281259/

    相关文章:

    typescript - Vue-CLI、TypeScript 和 monorepo : how to declare types outside of/src?

    vue.js - 如何在vue-cli生成的vue.config.js中设置mini-css-extract-plugin的配置

    javascript - Javascript 中的 HTML

    webpack - 错误的 list 预缓存位置

    javascript - 具有不同 bundle 的 Webpack 多个入口点

    javascript - 将 css 文件注入(inject)到使用 HtmlWebpackPlugin 生成的 html 文件的头部

    javascript - vue-cli项目修改端口号的方法

    javascript - 如何从 javascript/typescript 模块文件(导入/导出)访问 Vuex 存储?

    javascript - 局部变量在 eventBus.emit 之后更新

    vue.js - VueJS 复选框上的切换功能