用 qiankun Agent Skill 让编码 Agent 自动搭建微前端项目:安装、使用与源码解析
【免费下载链接】qiankun📦 🚀 Blazing fast, simple and complete solution for micro frontends.项目地址: https://gitcode.com/gh_mirrors/qi/qiankun
qiankun 在主仓库中随附了一套面向编码 Agent 的 Agent Skill 技能包(skills/qiankun/),采用 Agent Skills 格式,直接从主仓库分发。安装后,Claude Code、Cursor 等编码 Agent 可以按照官方约定为你创建主应用(host)与微应用(micro-app),或将现有 Vite 应用转换为微应用。读完本文,你将掌握该技能包的安装方式、内部结构与任务路由机制、Agent 执行任务时的完整操作链路,以及它与仓库源码(Vite/Webpack 打包插件、React/Vue UI 绑定)之间的对应关系,从而让 Agent 生成的工程与官方教程手工搭建的结果保持一致。
Agent Skill 是什么:qiankun 的 Agent 使用手册
Agent Skill 是一种把"使用手册"打包给编码 Agent 执行的格式:技能包内包含描述文件与参考文档,Agent 在收到自然语言任务后按其中的步骤、模板和约定执行。qiankun 将这一手册随主仓库一起维护,目录结构如下:
- skills/qiankun/SKILL.md:技能入口,包含任务路由表、开始前必读的关键约定与包版本表;
- skills/qiankun/references/create-micro-app.md:创建微应用 / 转换现有 Vite 应用的详细步骤与 React、Vue 入口模板;
- skills/qiankun/references/create-main-app.md:创建主应用的三种加载方式与验证清单。
该技能与本文档站点同步维护:Agent 生成的项目结构与教程:手工构建主应用与微应用所搭建的完全一致——技能本质上是把这份"应用契约"交给 Agent 去执行。文档站点中还给出了对它的引用提示,见 Prepare a Vite micro-app 开头的说明:新建应用时可以直接交给 Agent 生成,而该篇指南则面向手工改造现有 React/Vue 应用的场景。
安装:一条命令将技能装进 Agent
在计划创建项目的目录中执行:
npx skills add umijs/qiankun该命令从 qiankun 仓库拉取名为qiankun的技能,并安装到 Agent 的技能目录(例如.claude/skills/)。仓库始终分发与最新文档匹配的技能版本,因此不需要管理技能版本号——升级文档即升级技能。
安装后的技能包即为仓库中的 skills/qiankun 目录:SKILL.md通过 front-matter 声明技能名称与描述("Usage manual for building micro-frontend projects with qiankun 3.x"),Agent 会根据该描述判断何时启用此技能。
任务路由与开始前必读
SKILL.md的核心是一张任务路由表:Agent 只读取当前任务需要的参考文件,避免上下文浪费。
| 任务 | 应读取的参考文件 |
|---|---|
| 创建微应用,或转换现有 Vite 应用 | create-micro-app.md |
| 创建主应用 | create-main-app.md |
| 其他主题(迁移、样式隔离、沙箱、调试) | 查阅本站点对应文档与examples/目录 |
开始任何创建任务前,Agent 需先确定四项信息(无法从上下文推断时才询问用户):
- 应用类型:主应用(host/shell)还是微应用(sub/micro app)。
- 应用名称:小写字母、数字、连字符。主应用注册时使用的名称必须与微应用在 classic 模式 fallback 中使用的名称完全一致(下文入口模板中的
<app-name>)。 - 框架:React 或 Vue;TypeScript 或 JavaScript。参考文件中的模板为 TS,若选 JS 则去除类型标注。
- 开发端口:必须固定且每个应用唯一,因为主应用在
entry中硬引用该端口。约定:主应用7099,微应用7101、7102……依次递增。
包版本也有明确约定——在 qiankun 3.0 稳定版发布前,核心包使用rc作为 dist-tag:
| 包 | Dist-tag | 安装位置 |
|---|---|---|
qiankun | rc | 主应用dependencies |
@qiankunjs/react/@qiankunjs/vue | rc | 主应用dependencies(可选 UI 绑定) |
@qiankunjs/bundler-plugin | rc | 微应用devDependencies |
必须牢记的 Key Facts
技能中的"关键事实"是所有任务的前提,理解它们才能正确使用技能(也对应着仓库的实际行为):
- Vite 微应用无需专用构建模式。qiankun 3 通过 ESM 沙箱原生加载
<script type="module">,常规vite dev/vite build产物开箱即用。这一点在 Vite 插件源码 中有明确注释:不涉及 legacy/SystemJS 转换。 - JS 沙箱默认开启;CSS 隔离按应用开启,通过
styleIsolation: true启用运行时 CSS@scope。 - 微应用必须保持可独立运行:当未被 qiankun 加载(
window.__POWERED_BY_QIANKUN__为 undefined)时,它直接渲染自身——这就是入口模板中的 standalone 分支。 - 挂载了就必须卸载:
loadMicroApp返回的句柄在应用离开时必须调用.unmount();MicroApp组件绑定在组件卸载时自动完成。 - Webpack 微应用使用
@qiankunjs/bundler-plugin/webpack而非 Vite 插件,详见 @qiankunjs/bundler-plugin。
每个创建任务完成后,都必须按照所用参考文件末尾的验证清单检查结果;若 Agent 有浏览器工具,应自行验证而不是让用户代劳。
使用方式:一句自然语言启动
安装后,直接用自然语言向 Agent 描述目标即可,例如:
Use qiankun to create a React host app (port 7099) and a Vue micro-app (port 7101)
按照技能指示,Agent 会执行以下完整动作:
- 用 create-vite 创建项目(React 或 Vue、TS 或 JS);
- 微应用侧:安装
@qiankunjs/bundler-plugin,在 Vite 插件中注册qiankun()并固定端口,将入口模块改写为导出bootstrap/mount/update/unmount生命周期,同时保留 standalone 分支; - 主应用侧:安装
qiankun及可选的 React/VueMicroApp组件绑定,并接入加载代码; - 启动两个 dev server,验证微应用既能独立运行,也能被主应用挂载和卸载。
微应用创建与现有 Vite 应用转换
新建应用从第 1 步开始;转换现有 Vite 应用则直接跳到第 2 步——转换恰好就是第 2~4 步,不触碰其他任何文件(index.html、App组件、构建脚本均无需改动)。
第 1 步:脚手架(官方 Vite 脚手架,模板支持react-ts、react、vue-ts、vue):
pnpm create vite <app-name> --template react-ts第 2 步:安装打包插件:
pnpm add -D @qiankunjs/bundler-plugin@rc第 3 步:编辑vite.config.ts——注册插件并固定端口:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; // vue: @vitejs/plugin-vue import { qiankun } from '@qiankunjs/bundler-plugin/vite'; export default defineConfig({ plugins: [react(), qiankun()], server: { port: 7101, strictPort: true, }, });Vite 插件无任何选项,其两个可观察行为都能在插件源码中找到印证:其一,通过config()钩子为 dev/preview server 注入Access-Control-Allow-Origin: *的 CORS 头,使主应用可以跨源拉取 HTML 入口与模块图;其二,通过transformIndexHtml钩子在构建产物中为入口模块脚本打上entry属性(与QiankunWebpackPlugin的约定一致),让加载器确定性地识别入口,而不是回退到最后一个 module script。注意导入路径必须为@qiankunjs/bundler-plugin/vite——该包的裸导入指向的是 Webpack 插件,bundler-plugin 文档 对此有明确的导出表。
第 4 步:改写入口导出生命周期。以 React 模板(src/main.tsx)为例(将两处<app-name>替换为实际注册名):
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import './index.css'; declare global { interface Window { __POWERED_BY_QIANKUN__?: boolean; [key: string]: unknown; } } let root: ReactDOM.Root | undefined; function render(props: { container?: Element } = {}) { // 被 qiankun 加载时,在宿主提供的 container 内解析 #root,而不是顶层 document const container = props.container?.querySelector('#root') ?? document.getElementById('root'); if (!container) return; root = ReactDOM.createRoot(container); root.render( <React.StrictMode> <App /> </React.StrictMode>, ); } export async function bootstrap() {} export async function mount(props: { container?: Element }) { render(props); } // 宿主在 props 变化时重新投递,响应变化时无需重挂载 export async function update(_props: Record<string, unknown>) {} export async function unmount(_props: { container?: Element }) { root?.unmount(); root = undefined; } if (window.__POWERED_BY_QIANKUN__) { // classic 模式 fallback:以注册名暴露生命周期到 window window['<app-name>'] = { bootstrap, mount, update, unmount }; } else { render(); }Vue 模板(src/main.ts)采用同样的结构,差异在于使用createApp(App, { hostProps })并利用reactive的hostProps承接宿主 props:mount与update均通过Object.assign(hostProps, props)保持数据最新,容器选择器为#app:
import { createApp, reactive } from 'vue'; import App from './App.vue'; import './style.css'; declare global { interface Window { __POWERED_BY_QIANKUN__?: boolean; [key: string]: unknown; } } let app: ReturnType<typeof createApp> | undefined; // 宿主投递的 props——mount 时播种,update 时保持最新 const hostProps = reactive<Record<string, unknown>>({}); function render(props: { container?: Element } = {}) { const container = props.container?.querySelector('#app') ?? document.getElementById('app'); if (!container) return; app = createApp(App, { hostProps }); app.mount(container); } export async function bootstrap() {} export async function mount(props: { container?: Element }) { Object.assign(hostProps, props); render(props); } export async function update(props: Record<string, unknown>) { Object.assign(hostProps, props); } export async function unmount(_props: { container?: Element }) { app?.unmount(); app = undefined; } if (window.__POWERED_BY_QIANKUN__) { window['<app-name>'] = { bootstrap, mount, update, unmount }; } else { render(); }验证清单:在微应用内运行pnpm dev,打开http://localhost:7101,必须能独立渲染(走入口的非 qiankun 分支);若主应用已存在,则同时运行并确认微应用在宿主内正常挂载、控制台无报错(见 create-main-app.md 的验证清单)。
主应用创建与三种加载方式
第 1 步:搭建 shell 并安装依赖(以下假设 React + TS、端口7099):
pnpm create vite <main-app-name> --template react-ts pnpm add qiankun@rc @qiankunjs/react@rc # vue shell: @qiankunjs/vue@rc同样在vite.config.ts中固定端口(server: { port: 7099, strictPort: true })。
第 2 步:选择一种加载方式(三选一):
MicroApp组件(React/Vue shell 推荐)——渲染时挂载、组件卸载时自动卸载,内置 loading/error 插槽;额外 props 会转发给微应用(变化时通过其update生命周期投递):
import { MicroApp } from '@qiankunjs/react'; // @qiankunjs/vue 中组件同名 export default function SubAppPage() { return <MicroApp name="<app-name>" entry="//localhost:7101" autoSetLoading />; }该组件在仓库中的实现位于 MicroApp.tsx:它通过 effect 链串行化挂载/卸载(专门处理 StrictMode 下 mount 未完成即触发 cleanup 的竞态),以name定义挂载身份、用深度比较(useDeepCompare)判断 props 变化以触发updateMicroApp,并在 wrapper 内先渲染容器再渲染插槽,避免条件渲染的 loader/error 面板改变容器 XPath 导致 parcel 缓存分裂。
路由驱动注册(框架无关)——qiankun 在 URL 匹配activeRule时挂载/卸载应用,在 shell 入口只放一次:
import { registerMicroApps, start } from 'qiankun'; registerMicroApps([ { name: '<app-name>', entry: '//localhost:7101', container: '#micro-app-container', // shell 始终渲染的元素 activeRule: '/<app-name>', }, ]); start();完全手动控制——loadMicroApp({ name, entry, container }, configuration)返回句柄,由你负责在应用离开时调用.unmount():
import { loadMicroApp } from 'qiankun'; const microApp = loadMicroApp({ name: '<app-name>', entry: '//localhost:7101', container: document.getElementById('micro-app-slot')!, }); // 不再需要时: await microApp.unmount();这些 API 均可从 qiankun 包入口 中看到统一导出(loadMicroApp、registerMicroApps、start相关 effect 等)。
第 3 步:按应用配置——loadMicroApp的第三参数、MicroApp组件的configurationprop、或registerMicroApps的逐应用字段均可用:sandbox默认为开启;添加styleIsolation: true以@scope限定微应用 CSS。
验证清单:同时运行两个 dev server,打开主应用http://localhost:7099,导航到微应用路由——必须无报错地挂载进 shell;离开微应用路由——其 DOM 必须被移除(说明 unmount 确实执行了);微应用在http://localhost:7101仍可独立渲染。
覆盖范围与边界
当前版本的技能覆盖项目创建:搭建新的 host/micro-app 以及转换现有 Vite 应用。其余主题——迁移、样式隔离、问题排查——请查阅本站点对应章节:
- 快速开始
- 教程:构建主应用与微应用,其中 run-and-verify 步骤 还给出了常见首跑问题的排查表(容器空白查端口与
entry、CORS 报错查 Vite 插件、找不到生命周期查导出、无法干净重挂载查 unmount 清理、端口漂移加strictPort: true) - 准备一个 Vite 微应用
- @qiankunjs/bundler-plugin(Vite/Webpack 双插件、
packageName选项与入口约束) - 可参考的成品示例位于 examples 目录(React、Vue、vue-host、webpack、streaming、standalone-sandbox 等)
与源码对应的实现要点小结
| 技能中的步骤 | 仓库中的对应实现 |
|---|---|
微应用安装qiankun()Vite 插件 | packages/bundler-plugin/src/vite/index.ts(CORS 头 +entry属性标记) |
Webpack 微应用使用QiankunWebpackPlugin | packages/bundler-plugin/src/webpack/index.ts(配置 window 全局 library 并标记入口脚本) |
主应用使用MicroApp组件 | packages/ui-bindings/react/src/MicroApp.tsx(挂载/卸载串行化、props 更新、插槽渲染) |
主应用调用loadMicroApp/registerMicroApps/start | packages/qiankun/src/index.ts(统一导出) |
技能生成的项目与文档教程手工搭建的契约完全一致:主应用提供name、entry(指向微应用 HTML)、container(已存在的HTMLElement);微应用提供bootstrap、mount(必要时含update)与unmount;qiankun 连接两侧并返回句柄,主应用负责在实例不再需要时调用句柄的unmount()。理解了这条契约,你就能审阅、修改甚至绕过 Agent 生成的项目——所有模板与步骤都沉淀在 skills/qiankun 目录中,随时可供查阅。
【免费下载链接】qiankun📦 🚀 Blazing fast, simple and complete solution for micro frontends.项目地址: https://gitcode.com/gh_mirrors/qi/qiankun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考