Qwik+Vite模块联邦跨站导入组件遇ESM及require错误
基于Qwik+Vite的模块联邦组件复用问题解决方案
问题背景
- 技术栈:两个Qwik项目(基于Vite、ESM、TypeScript),Node.js 22.3.20
- 需求:网站B(Host)导入网站A(Remote)暴露的组件,实现跨站组件复用
- 核心问题:
- 使用
vite-plugin-federation时,触发ESM默认加载器不支持HTTP协议错误 - 改用
module-federation-vite时,出现require未定义错误
- 使用
问题1:vite-plugin-federation的ESM HTTP协议错误
错误原因
Node.js默认ESM加载器仅支持file:和data:协议的URL,SSR阶段直接导入HTTP地址的remoteEntry.js会触发该限制。
解决方案
通过区分客户端与SSR的远程配置,避免在Node环境中加载HTTP资源:
Host端Vite配置调整
根据ssrBuild变量切换远程地址的加载方式,SSR阶段使用本地可访问的remoteEntry.js路径(需确保Remote的dist目录可被Host访问,或通过静态资源服务代理):import { defineConfig } from 'vite'; import { qwikVite } from '@builder.io/qwik/optimizer'; import qwikCity from '@builder.io/qwik-city/vite'; import tsconfigPaths from 'vite-tsconfig-paths'; import federation from '@originjs/vite-plugin-federation'; export default defineConfig(({ ssrBuild }) => ({ plugins: [ qwikCity(), qwikVite(), tsconfigPaths(), federation({ name: "b", remotes: { a: { external: 'http://localhost:5173/dist/assets/remoteEntry.js', import: ssrBuild ? './path/to/remote/dist/assets/remoteEntry.js' // SSR用本地路径 : 'http://localhost:5173/dist/assets/remoteEntry.js' // 客户端用HTTP地址 } } }) ] }));代码中客户端按需加载
在Host的组件中,仅在客户端环境加载远程组件,避免SSR阶段执行HTTP导入:import { component$, useSignal, useClientEffect$ } from '@builder.io/qwik'; export default component$(() => { const RemoteHeading = useSignal(null); // 仅在浏览器环境加载远程组件 useClientEffect$(() => { import('a/Heading').then(mod => { RemoteHeading.value = mod.default; }); }); return <>{RemoteHeading.value && <RemoteHeading.value />}</>; });
问题2:module-federation-vite的require未定义错误
错误原因
插件生成的虚拟加载文件使用了CommonJS的require语法,但Qwik项目为纯ESM环境,Node.js在ESM模式下不支持require。
解决方案
强制生成ESM兼容代码
在Host的Vite配置中明确指定输出格式为ESM,并配置插件启用模块模式:import { defineConfig } from 'vite'; import { qwikVite } from '@builder.io/qwik/optimizer'; import qwikCity from '@builder.io/qwik-city/vite'; import tsconfigPaths from 'vite-tsconfig-paths'; import federation from 'module-federation-vite'; export default defineConfig({ plugins: [ qwikCity(), qwikVite(), tsconfigPaths(), federation({ name: "b", remotes: { a: { type: 'module', name: 'a', entry: 'http://localhost:5173/dist/assets/remoteEntry.js', shareScope: "default" } }, output: { format: 'es' } }) ], build: { rollupOptions: { output: { format: 'esm' } } } });手动修复虚拟文件的require语法
通过Vite的transform钩子,将插件生成的虚拟文件中的require替换为import:export default defineConfig({ plugins: [ // ...其他插件 { name: 'fix-mf-require', transform(code, id) { if (id.includes('__mf__virtual')) { return code.replace(/require\(/g, 'import('); } return code; } } ] });
内容的提问来源于stack exchange,提问作者Justin Slijkhuis
相关产品推荐
相关产品推荐

