Vue.js Module Federation微前端:远程组件加载后如何注册使用?
Vue 3 + Module Federation 远程组件注册与使用方案
核心问题分析
你的代码主要问题在于:
- 直接赋值
Header = res不是响应式状态,模板无法识别这个动态组件; - 模板中直接写
<Header>会被Vue视为原生HTML标签,而非Vue组件; defineAsyncComponent的用法错误,没有结合你自定义的loadComponent流程来封装远程组件加载逻辑。
方法一:响应式变量+动态组件(最简洁方案)
这是Vue 3中动态渲染异步组件的标准方式,适合你的场景:
<script setup> import { ref, onMounted } from 'vue' // 用响应式变量存储远程组件 const Header = ref(null) const modules = [ { protocol: 'http', host: 'localhost', port: 8080, moduleName: 'Company', fileName: 'remoteEntry.js', componentNames: ['Header'], }, ] onMounted(() => { modules.forEach((uiApplication) => { const remoteURL = `${uiApplication.protocol}://${uiApplication.host}:${uiApplication.port}/${uiApplication.fileName}` const { componentNames, moduleName } = uiApplication const element = document.createElement('script') element.type = 'text/javascript' element.async = true element.src = remoteURL element.onload = async () => { for (const componentName of componentNames || []) { const componentLoader = loadComponent(moduleName, `./${componentName}`) const remoteComponent = await componentLoader() // 注意:远程组件如果是export default导出,需要取.default;命名导出则取对应属性 Header.value = remoteComponent.default || remoteComponent } } document.head.appendChild(element) }) }) function loadComponent(scope, module) { return async () => { await __webpack_init_sharing__('default') const container = window[scope] await container.init(__webpack_share_scopes__.default) const factory = await container.get(module) const Module = factory() return Module } } </script> <template> <div> <!-- 使用Vue动态组件渲染远程组件,v-if确保组件加载完成后再渲染 --> <component v-if="Header" :is="Header" title="Test shop" /> <h2>Our Shop Page</h2> </div> </template>
方法二:预定义异步组件(提前注册方案)
如果想像使用本地组件一样直接在模板中调用,可通过defineAsyncComponent封装远程组件加载流程:
<script setup> import { defineAsyncComponent } from 'vue' // 预定义远程Header组件 const RemoteHeader = defineAsyncComponent(() => { return new Promise(async (resolve) => { // 先加载remoteEntry.js,避免重复加载 await loadRemoteEntry('http://localhost:8080/remoteEntry.js', 'Company') // 再加载目标组件 const componentLoader = loadComponent('Company', './Header') const component = await componentLoader() resolve(component.default || component) }) }) // 封装remoteEntry加载逻辑,加缓存避免重复请求 async function loadRemoteEntry(url, scope) { if (window[scope]) return return new Promise((resolve, reject) => { const element = document.createElement('script') element.type = 'text/javascript' element.async = true element.src = url element.onload = resolve element.onerror = reject document.head.appendChild(element) }) } function loadComponent(scope, module) { return async () => { await __webpack_init_sharing__('default') const container = window[scope] await container.init(__webpack_share_scopes__.default) const factory = await container.get(module) const Module = factory() return Module } } </script> <template> <div> <!-- 直接使用预定义的远程组件 --> <RemoteHeader title="Test shop" /> <h2>Our Shop Page</h2> </div> </template>
关键注意事项
- 响应式要求:动态获取的组件必须存储在响应式变量中,模板才能感知到组件加载完成的状态变化;
- 组件导出格式:远程组件如果是
export default导出,需取.default属性;如果是命名导出,则对应取命名属性; - 重复加载防护:添加判断逻辑,确保
remoteEntry.js只加载一次,避免重复创建script标签; - 错误处理:建议在异步流程中添加
try/catch,处理网络错误、组件不存在等异常情况。
内容的提问来源于stack exchange,提问作者by Neznayka
相关产品推荐
相关产品推荐

