带有 Webpack 模块联合的 Vue 3 CLI:组件从错误的主机加载
Vue 3 CLI with Webpack Module Federation: Components load from wrong host
我目前正在尝试建立一个使用 Webpack 的 Module Federation 来共享组件的项目。
为此,我使用 cli 设置了两个基本的 vue 项目,并在两个项目中添加了一个 vue.config.js 文件:
宿主项目(将包含共享组件)(运行 on 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: {}
})
]
}
}
组件项目(共享组件)(运行 on 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
中明确设置它们。我描述了一个关于如何配置它的详细示例。为了简单起见,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(及更高版本)中。
我目前正在尝试建立一个使用 Webpack 的 Module Federation 来共享组件的项目。
为此,我使用 cli 设置了两个基本的 vue 项目,并在两个项目中添加了一个 vue.config.js 文件:
宿主项目(将包含共享组件)(运行 on 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: {}
})
]
}
}
组件项目(共享组件)(运行 on 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
中明确设置它们。我描述了一个关于如何配置它的详细示例。为了简单起见,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(及更高版本)中。