ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

qiankun v3 接入 Vite 微应用完整指南:原生 ESM 生命周期、插件配置与跨域部署

qiankun v3 接入 Vite 微应用完整指南:原生 ESM 生命周期、插件配置与跨域部署 qiankun v3 接入 Vite 微应用完整指南原生 ESM 生命周期、插件配置与跨域部署【免费下载链接】qiankun Blazing fast, simple and complete solution for micro frontends.项目地址: https://gitcode.com/gh_mirrors/qi/qiankun本文以 qiankun v3 中「接入 Vite 应用」的官方实战指南为核心系统讲解如何把现有的 React / Vue 应用改造成可被 qiankun 主应用加载的微应用。你将掌握 Vite 构建插件的安装与配置、从入口模块导出原生 ESM 生命周期、保持模块化 HTML 入口、使用loadMicroApp从主应用加载以及开发与生产环境的跨域部署和验证流程。与 qiankun 2.x 时代「Webpack UMD 全局库」的接入方式不同v3 直接以原生 ESM 方式运行 Vite 应用全程无需 UMD 包装、SystemJS 转换或全局生命周期对象。1. v3 接入 Vite 应用的整体思路在 qiankun v3 中Vite 应用的接入只有一条路径在微应用安装并配置 Vite 构建插件qiankunjs/bundler-plugin从index.html直接引用的入口模块导出微应用生命周期bootstrap、mount、unmount主应用通过loadMicroApp以 Vite 开发服务器地址或生产部署地址作为entry加载。整个过程不涉及 UMD 包装、SystemJS 转换也不需要把生命周期对象挂到window上——入口模块的原生export本身就是生命周期契约见 微应用生命周期与 props 与 原生 ESM 支持。提示如果你是从零创建新应用可以让 coding agent 通过 Agent skill 自动生成这套配置本指南面向「改造已有的 React 或 Vue 应用」这一场景。在仓库中可以看到这套思路的完整落地examples/react/vite.config.ts、examples/vue/vite.config.ts都同时启用了框架插件与qiankun()插件examples/react/src/main.tsx与examples/vue/src/main.ts则从入口模块导出了完整生命周期。2. 安装并配置 Vite 插件2.1 安装在 Vite 应用中安装构建插件仅微应用需要安装主应用无需安装npm install --save-dev qiankunjs/bundler-pluginrc该包将 Vite 声明为可选对等依赖peerDependencies项目只需安装实际使用的构建工具支持 Vite 5 及以上版本详见 qiankunjs/bundler-plugin 参考。2.2 配置vite.config.ts将qiankun()与框架插件一同加入plugins并指定固定的开发服务器端口::: code-groupimport { qiankun } from qiankunjs/bundler-plugin/vite; import react from vitejs/plugin-react; import { defineConfig } from vite; export default defineConfig({ plugins: [react(), qiankun()], server: { port: 7101, strictPort: true, }, });import { qiankun } from qiankunjs/bundler-plugin/vite; import vue from vitejs/plugin-vue; import { defineConfig } from vite; export default defineConfig({ plugins: [vue(), qiankun()], server: { port: 7101, strictPort: true, }, });:::两点配置说明固定端口portstrictPort主应用需要以「开发服务器地址 端口」作为entry因此端口必须固定且不可被占用时自动切换。strictPort: true确保端口被占用时直接报错而不是换端口避免主应用入口失效。导入路径必须是qiankunjs/bundler-plugin/vite该包同时提供 Vite 与 Webpack 两套插件插件不会自动判断构建工具。包根路径qiankunjs/bundler-plugin导出的是QiankunWebpackPlugin只有/vite子路径导出 Vite 插件qiankun具名与默认导出均可。2.3 插件做了什么源码级解读Vite 插件不接收任何参数它只为 qiankun 提供两项能力对应实现见 packages/bundler-plugin/src/vite/index.ts为开发服务器与预览服务器配置 CORS 响应头。插件在config()钩子中同时为server与preview设置cors: true并注入{ Access-Control-Allow-Origin: * }响应头使主应用能够跨源获取 HTML 入口与模块依赖图。需要说明这只覆盖 Vite 自己的开发/预览服务器不替代生产服务器的 CORS 配置。在生产构建中标记入口模块脚本。插件通过transformIndexHtmlorder: post在构建产物中为唯一的入口模块脚本添加entry属性。其标记逻辑是先筛选script[typemodule][src]的外部模块脚本如果其中已有带entry属性的脚本则跳过否则优先匹配与入口 chunk 文件名entryChunk.fileName一致的脚本匹配不到时回退到最后一个模块脚本并为其添加entry属性。从源码注释可以确认开发环境的 HTML 无需显式entry标记——ESM 引擎会根据生命周期导出解析入口且 Vite 开发转换阶段本就会丢弃未知属性生产构建标记entry是为了让加载器确定性地选中入口而不是回退到最后一个模块脚本。整套流程不涉及任何 legacy/SystemJS 转换qiankun 通过自身的 ESM 沙箱原生加载 Vite 应用开发与生产构建皆然。3. 从入口模块导出原生 ESM 生命周期3.1 React 示例src/main.tsx从index.html直接引用的入口模块中导出bootstrap、mount和unmount。框架实例在mount中创建渲染到props.container内并在unmount中销毁import React from react; import ReactDOM from react-dom/client; import App from ./App; declare global { interface Window { __POWERED_BY_QIANKUN__?: boolean; } } type MountProps { container: HTMLElement }; let root: ReactDOM.Root | undefined; function render(scope: ParentNode) { const node scope.querySelector(#root); if (!node) throw new Error(#root not found); root ReactDOM.createRoot(node); root.render(App /); } export async function bootstrap() {} export async function mount({ container }: MountProps) { render(container); } export async function unmount() { root?.unmount(); root undefined; } if (!window.__POWERED_BY_QIANKUN__) { render(document); }3.2 Vue 示例src/main.tsimport { createApp, type App as VueApp } from vue; import App from ./App.vue; declare global { interface Window { __POWERED_BY_QIANKUN__?: boolean; } } type MountProps { container: HTMLElement }; let app: VueAppElement | undefined; function render(scope: ParentNode) { const node scope.querySelector(#app); if (!node) throw new Error(#app not found); app createApp(App); app.mount(node); } export async function bootstrap() {} export async function mount({ container }: MountProps) { render(container); } export async function unmount() { app?.unmount(); app undefined; } if (!window.__POWERED_BY_QIANKUN__) { render(document); }3.3 实现生命周期的四项原则原生 ESM 导出即为生命周期约定具名导出bootstrap/mount/unmount与默认导出的生命周期对象均受支持但不应再将生命周期对象赋值给window。仓库示例examples/react/src/main.tsx与examples/vue/src/main.ts中保留了window[react] {...}的写法但那只是为 Classic 模式提供的 fallback 分支仅当__POWERED_BY_QIANKUN__为真时执行ESM 接入路径完全不需要它。props.container属于当前微应用实例应在该容器内查询#root或#app而不应使用页面级全局选择器。这样能保证多实例运行与重新挂载时不会误挂到主应用文档结构上。__POWERED_BY_QIANKUN__用于分流渲染qiankun 环境下即将由mount接管入口模块不应自行渲染应用通过自身开发服务器独立运行时该标志为undefined走render(document)立即渲染保证独立开发体验不受影响。每次mount创建完整实例、每次unmount彻底销毁重新挂载时模块顶层代码不会再次执行详见下文第 5 节因此框架根节点与视图状态必须在mount中创建、在unmount中销毁。仓库示例在这一点上做得更完整examples/react/src/main.tsx额外实现了update生命周期主应用 props 变化如切换语言时无需重新挂载即可通过root.render更新界面examples/vue/src/main.ts则用reactive的hostProps承接主应用传入的 props。完整的生命周期约定见 微应用生命周期与 props。4. 保持原生模块入口保留 Vite 常规的 HTML 结构与单一模块入口。挂载节点的 ID 必须与生命周期代码中的选择器一致div idroot/div script typemodule src/src/main.tsx/script要点源码中无需手动添加entry属性生产构建时Vite 插件会自动将该属性添加到生成的入口脚本上见第 2.3 节。每份构建产物恰好包含一个带entry属性的脚本HTML 入口约束要求「一个 HTML 入口最多只能有一个带entry属性的脚本」插件标记后请勿再手动添加入口标记约束清单见 qiankunjs/bundler-plugin 参考 与 HTML 入口。入口必须是外部脚本entry标记的脚本必须包含src或data-src内联脚本不能作为生命周期入口。entry标记仅用于指定负责导出生命周期的脚本文档中仍可包含其他普通脚本。如果应用部署在子路径下或资源通过独立域名提供应配置 Vite 的base确保浏览器能够访问dist/index.html中生成的资源 URL。仓库中的主应用examples/main/src/apps.ts展示了这种「双模式入口」的实践开发模式下每个微应用运行在独立端口的开发服务器如 React 应用在7100、Vue 应用在7101部署模式下则统一构建为站点/apps/name/子路径下的静态产物——这正是通过 Vitebase与构建模式配合实现的。5. 从主应用加载loadMicroApp5.1 基本用法将 Vite 开发服务器地址或生产环境部署地址配置为loadMicroApp的entry保存返回的实例句柄并在移除容器之前卸载应用import { loadMicroApp } from qiankun; const container document.getElementById(micro-app-slot); if (!container) throw new Error(micro-app-slot not found); const microApp loadMicroApp({ name: account-app, entry: http://localhost:7101/, container, props: { accountId: 42 }, }); await microApp.mountPromise; // 主应用视图销毁时 await microApp.unmount();使用loadMicroApp时无需同时配置registerMicroApps也无需显式调用start()——它调用后立即开始加载与挂载。React 和 Vue 主应用也可以使用对应的MicroApp集成qiankunjs/react/qiankunjs/vue的MicroApp组件由组件生命周期管理实例句柄组件内部与loadMicroApp使用相同的实例模型。5.2 参数与返回值要点app对象的三个必填字段为name微应用名称多个实例可复用名称、entryHTML 入口 URL 字符串v3 不再支持 2.x 的{ scripts, styles }对象形式、container必须是HTMLElement实际元素不再是string | HTMLElement传入选择器字符串会导致类型错误且运行时无法挂载。返回值为 single-spa 的 Parcel 句柄mount()/unmount()/getStatus()以及loadPromise、bootstrapPromise、mountPromise、unmountPromise等阶段 Promise仅当微应用导出update时句柄才提供update()。加载或挂载失败时这些 Promise 会被拒绝应通过.catch或try...catch处理避免未处理的 Promise 拒绝。5.3 重新挂载与实例复用源码级佐证为什么「模块顶层代码在重新挂载时不会再次执行」从 loadMicroApp 实现可以看到qiankun 以「应用名 容器 XPath」作为微应用实例 IDgetContainerXPathKey并维护appConfigPromiseGetterMap与containerMicroAppsMap两张缓存表。当同一容器再次加载同一应用时会命中缓存的 Parcel 配置并复用已加载的生命周期模块只重新执行mount——这正是「bootstrap只执行一次、mount可多次执行、unmount必须清理干净」这一生命周期契约的底层来源。另外当多个微应用实例挂载到同一容器时源码中的 mount 包装逻辑会先等待前序实例的unmountPromise完成再挂载新实例避免并发冲突。这也解释了文档中「一个容器在同一时刻只承载一个应用」的行为约定。6. 配置跨域部署插件仅为 Vite开发服务器和预览服务器启用 CORS且Access-Control-Allow-Origin为通配符*。在生产环境中服务器或 CDN 必须允许主应用所在的源获取以下资源HTML 入口JavaScript 模块和动态导入的代码块CSS、图片以及应用引用的其他资源。部署前应从主应用页面实际测试最终资源 URL、重定向、MIME 类型和 CORS 响应头参见 HTML 入口 中的跨域与部署边界一节。特别要注意凭据Cookie场景如果应用请求需要携带 Cookie则不能将Access-Control-Allow-Origin配置为通配符需要同时做三件事在服务端指定明确的允许来源不能是*返回支持凭据的响应头如Access-Control-Allow-Credentials: true在主应用侧配置自定义fetchloadMicroApp第二参configuration.fetch用于请求入口及加载器处理的脚本、模块和样式。此外qiankun 的 HTML 入口机制不会绕过浏览器安全策略CSP、混合内容限制、身份认证与网络错误仍按浏览器规则处理ESM 路径要求内容安全策略允许blob:脚本但不要求unsafe-eval详见 原生 ESM 支持。7. 验证开发与生产环境按以下顺序逐项验证确保开发与生产两种形态都正常工作单独运行 Vite 应用确认应用在独立运行模式下未挂__POWERED_BY_QIANKUN__标志能够正常渲染即npm run dev后浏览器直接访问能出页面。主应用加载运行主应用以http://localhost:7101/为入口调用loadMicroApp确认应用渲染在传入的容器内。挂载/卸载循环依次调用await microApp.unmount()和await microApp.mount()确认没有重复的根节点、监听器或残留界面。构建产物检查在 Vite 应用中执行npm run build检查dist/index.html应当恰好有一个生成的模块脚本带有entry属性。预览验证执行npm run preview将主应用入口指向预览服务器地址预览服务器同样由插件注入了 CORS 头重复检查挂载与卸载过程。发布前回归在所有受支持的浏览器中使用各主应用的实际源访问生产入口确认应用能够正常加载。浏览器限制见 原生 ESM 支持——较新版本的 Chromium、Edge 与 Safari 已支持所需能力Firefox 默认未启用相关能力如需支持 Firefox 请采用 Classic/Webpack 构建。8. 开发体验与已知行为接入 Vite 应用后还有几个值得注意的运行时行为详见 原生 ESM 支持Vite HMR 会被关闭qiankun 可以运行 Vite 开发服务器提供的原生模块图但会关闭微应用内部的 Vite HMR 连接。开发过程中需要手动刷新页面不应依赖热更新或 React Fast Refresh 保留状态。模块顶层代码只执行一次对于同一个应用实例unmount后重新挂载时仅再次调用mount不会重新初始化模块作用域因此不要用模块顶层初始化替代mount。JS 注入样式的重新挂载风险Vite 可能通过模块顶层代码注入 CSS此类样式可能在卸载后丢失依赖 JavaScript 注入样式的应用应专门验证重新挂载场景。严格模式约束ESM 强制严格模式feature true这类隐式全局写入会抛出ReferenceError应显式声明变量或使用window.feature。错误定位生产环境错误栈中可能出现blob:URL请保留源码映射source map并配置错误上报系统还原栈帧。9. 相关内容HTML 入口——入口约定与 CORS 要求原生 ESM 支持——ESM 的运行行为与兼容性qiankunjs/bundler-plugin——插件参考Vite 与 Webpack 导出路径、入口约束loadMicroApp API——句柄与 Promise 完整参考微应用生命周期与 props——生命周期契约与清理职责运行多个微应用实例——重新挂载与清理模式接入 Webpack 应用——Classic 脚本构建方案ESM 沙箱实现——供维护者阅读的实现细节仓库中可对照的实际代码插件实现 packages/bundler-plugin/src/vite/index.ts、加载 API 实现 packages/qiankun/src/apis/loadMicroApp.ts、React/Vue 微应用示例 examples/react/src/main.tsx 与 examples/vue/src/main.ts、以及主应用配置 examples/main/src/apps.ts。【免费下载链接】qiankun Blazing fast, simple and complete solution for micro frontends.项目地址: https://gitcode.com/gh_mirrors/qi/qiankun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表