@axewo/fin-micro
统一页签式微前端库:无框架 core/SDK、Wujie 应用运行时、Vue 页级缓存适配、浏览器恢复和独立 iframe RPC。
快速开始
本说明直接提供创建、运行、接入和部署步骤,无需访问其他文档。运行环境要求 Node.js 18 及以上,并安装与生成项目配置兼容的 pnpm。
第一步:创建基座和子应用
在同一个父目录下执行,目标目录必须不存在:
npx @axewo/fin-micro@latest create my-host --template host --layout standard
npx @axewo/fin-micro@latest create my-business --template vue --app-id business --port 7101 --layout standard
基座默认端口为 7100,默认登记的子应用标识为 business、入口为 http://localhost:7101。子应用标识与基座注册表必须一致。命令只生成文件,不自动安装依赖。
第二步:安装依赖并启动
分别在两个终端中执行:
# 终端一:启动基座
cd my-host
pnpm install
pnpm dev
# 终端二:启动子应用
cd my-business
pnpm install
pnpm dev
打开 http://localhost:7100,使用开发演示账号 demo、密码 123456 登录,应进入本地主页。此时不需要后端;子应用离线也不影响基座本地主页。
打开 http://localhost:7101 可以单独访问子应用。子应用默认需要真实认证接口,不会自动沿用基座的演示登录;要完成嵌入业务页面验收,还需完成下一步的认证配置。
第三步:配置业务入口与认证
- 基座在
src/configs/microApps.ts维护子应用注册表;修改标识或端口时,同步修改注册项及对应环境配置。新增应用不能只增加环境变量。 - 基座真实认证在项目根目录
.env.local设置VITE_AUTH_DEMO=false,按src/platform/中的适配实现对接会话、登录、菜单和退出接口。 - 子应用独立认证在
src/apis/auth.ts对接实际接口;根目录.env.local的VITE_MICRO_AUTH_MODE可设为auto、host或independent。 - 默认注册项
shareToken:false不提供宿主凭据能力。只有确认子应用完全可信且需要共享认证时,才在基座注册表显式设为true,并确保当前会话授予该应用权限。不能仅修改子应用认证模式来获取宿主凭据。 - 按生成项目的
.env.example配置接口目录;VITE_API_BASE与VITE_API_TRUSTED_BASE必须一致,且以/结尾。环境变量会进入前端产物,禁止写入密码或访问凭据。
基座认证返回 { user: { id, name }, permissions: string[], appIds: string[], accessToken?: string };菜单接口返回 { apps: [{ appId, menus }] },必须完整覆盖所有已授权应用。菜单叶子示例:
{
"menuId": "records",
"name": "业务列表",
"target": {
"tabId": "business:list",
"route": "/list"
}
}
验收:独立登录后能访问子应用列表;基座登录后能从菜单打开已授权子应用;未登录或未授权访问被拒绝。演示模式仅用于本地开发,生产构建不会启用演示身份,也不会在真实接口失败后回退演示。
第四步:检查、构建与部署
在基座和子应用目录中分别执行:
pnpm check:runtime
pnpm typecheck
pnpm build
将各项目生成的 dist 分别部署,并在构建前配置基座注册表中的正式子应用入口。非本机应用入口使用 HTTPS,不能保留本地开发地址。
基座服务器需把 /login、/home、/profile、/micro/ 下的业务深链等前端路由回退到基座入口页面;静态资源和接口请求不能回退为页面。子目录部署还需同步配置构建基础路径。开发服务器的接口代理不会随构建产物发布,生产环境必须自行配置接口网关、跨源策略与认证防护。
部署后检查:基座深链刷新、子应用独立访问、嵌入菜单导航、详情关闭返回、页签恢复、退出登录及无权限访问。升级依赖后需要重新构建和发布;已生成项目的源文件不会被自动覆盖。
能力与配置参考
以下内容说明运行库与生成项目的主要配置,按实际接入需求查阅。
可配置业务区水印
@axewo/fin-ui 导出 FinWatermark、WatermarkConfig、normalizeWatermarkConfig。host/vue 的 standard/custom 模板均接入,配置在生成项目 src/utils/watermarkConfig.ts:
export const watermarkConfig = reactive<WatermarkConfig>({
enabled: true,
text: ['内部资料', '自定义文字'],
color: '#64748b',
opacity: 0.12,
rotate: -22,
fontSize: 16,
fontFamily: 'sans-serif',
gap: [100, 80], // 水平/垂直间距,越小越密
})
当前为前端配置;后续由项目 apis/ 适配真实接口并 Object.assign(watermarkConfig, result),无需更换组件,也没有预设后端协议。不要把 Token 等凭据当水印内容。字号限制 10~64、角度 -180~180、间距 16~600、透明度 0~1,文字最多四行、每行 120 字。
水印只覆盖右侧稳定业务视口,业务长页滚动不带走水印,不覆盖头部、侧栏和页签;登录页不绘制。Vue 嵌入运行由基座统一绘制,独立运行才挂载自己的水印。自定义接入需将组件置于 position: relative 的非滚动视口内,与业务滚动容器作为兄弟节点;公共 StandaloneShell 提供 workspace-overlay 插槽。
组件使用 Canvas 平铺、pointer-events: none,观察自身属性和直接父容器的节点删除,并定时检查常见隐藏样式。合法配置更新、关闭和卸载均清理观察器和定时器。Canvas 不可用或绘制失败会触发 error 事件并告警,本轮不启动无限重试;应用可按合规要求自行决定是否阻断业务。
纯前端水印不能保证无法通过 JS、样式或开发者工具移除:祖先容器被隐藏、脚本停用、截图后处理等均不受此机制保障,自动恢复只能提高篡改成本,不能当安全边界。下载文件需要水印时应在服务端生成;更强溯源需配合服务端审计与权限控制。
标准公共外壳与自定义布局
宿主模板的业务地址统一使用 /micro/{appId}/{子应用内路径}?query,例如 /micro/business/detail?id=1001;基座本地页面仍使用 /home、/profile。/workspace 只表示无参数的工作区入口,不再解析旧 /workspace?tab=... 链接。嵌入子应用仍使用 memory history,独立运行仍使用自身 hash 路由。
地址不携带 tabId:模板在授权菜单中查回静态页签的原 ID,演示详情仍使用 ${appId}:detail:${id};真实业务需在 src/router/targets.ts 中实现与菜单及子应用导航一致的动态身份策略,并由 platform/access.ts 校验权限。完整业务路径与 query 仍交给子应用;query 按键排序,重复参数保留顺序。完全相同的 URL 对应一个业务页签,不能靠不同的随机 tabId 创建可区分的同地址副本。
该变更利用现有 connectMicroHostRouter 的 target/location 映射,不修改核心缓存或生命周期协议。已有项目需同步 router/index.ts、targets.ts、guards.ts、workspace.ts;只升级 npm 不会覆盖项目源文件。生产服务器须将 /micro/ 下的深链回退到基座 index.html,子应用静态资源另用独立目录。
CLI 支持 --layout standard|custom,省略时默认 standard;交互创建时也可选择。
npx @axewo/fin-micro@latest create my-host --template host --layout standard
npx @axewo/fin-micro@latest create my-business --template vue --layout custom
- standard:生成项目从
@axewo/fin-micro/layout导入HostShell或StandaloneShell,并显式导入@axewo/fin-micro/layout/style.css。默认头部、菜单、页签等展示由包维护,升级依赖并重新构建后获得未覆盖区域的公共修复。 - custom:保留完整可运行的本地布局 SFC 与样式,功能基线一致;展示代码的后续变更需要项目自行合并,不会被 npm 升级覆盖。
- 宿主侧栏菜单名称前展示图标:菜单
icon使用HomeFilled、Folder、List、User等 Element Plus 图标标识;未配置或不在本地映射白名单中的名称会安全回退到文件/文件夹图标。后台只传标识字符串,不传组件代码、HTML 或远程图标 URL。独立 Vue 菜单使用路由meta.icon组件。 - 两种模式的认证、授权、Token、唯一 host/runtime、路由连接、页签事务和卸载逻辑仍由项目原有装配管理。公共外壳不创建第二套状态机,不导入项目的
platform.ts或localPages.ts。 - 子应用只有独立运行时使用独立外壳;嵌入模式即使暂未连接 bridge,也不显示自己的头部、侧栏。独立菜单仍由本地 router meta 映射,不额外请求菜单接口。
配置与插槽的升级边界
HostShell 支持 brand(title、mark、workspaceTitle)、受控 collapsed、isFixedTab 展示规则,以及 brand、header-actions、message-trigger、messages、user-trigger、user-menu、header、sidebar、tabs 插槽。业务内容使用默认插槽。StandaloneShell 支持 brand、header-actions、sidebar 和默认内容插槽。
<HostShell :apps="apps" :tabs="tabs" :active-key="activeKey" user-name="张三"
:brand="{ title: '业务工作台' }" @operate="operate" @open="open"
@logout="signOut" @profile="openProfile">
<template #header-actions><button @click="openHelp">帮助</button></template>
<HostWorkspace />
</HostShell>
上例只示意展示扩展,实际项目继续使用生成模板中完整的属性、事件和认证接线。局部插槽不会把整个应用变成 custom;替换整个 header 后,仅该区域的默认展示升级不再体现,其他默认区域继续升级。插槽动作只发出事件,项目处理器仍必须执行原有核心授权和离页守卫;不得直接调用可信底层原语绕过事务。固定页签谓词也仅控制按钮,真正约束继续由项目的 workspaceOperation 实施。
头部消息通过两个独立插槽扩展;可只替换按钮或只替换内容,未覆盖的部分保留默认铃铛和原有空态。标准与自定义 host 模板的 HostLayout 均透传这两个插槽,项目可在 src/views/workspace/index.vue 的 <HostLayout> 上使用。
| 插槽 | 作用域(HostMessageScope) | 默认内容 |
|---|---|---|
message-trigger | expanded、pending、toggle()、close() | 铃铛按钮 |
messages | 同上,仅展开时挂载 | 消息标题与尚未接入消息服务的空态 |
<!-- 放在已有 HostShell 或模板 HostLayout 内,保留原有属性、事件及业务区。 -->
<template #message-trigger="{ expanded, pending, toggle }">
<button type="button" :disabled="pending" :aria-expanded="expanded"
aria-label="消息通知" @click="toggle">消息 {{ unreadCount }}</button>
</template>
<template #messages="{ close }">
<ProjectMessageList :items="messages" @select="item => selectMessage(item, close)" />
</template>
unreadCount、messages、ProjectMessageList 与 selectMessage 由项目提供;消息接口、轮询或 WebSocket 不由外壳创建。项目可在点击处理后调用 close(),页面跳转继续使用项目现有的核心导航事务。toggle() 会检查 pending;自定义按钮仍应绑定 disabled 与 aria-expanded。弹层容器、内容滚动、点击遮罩、Esc、搜索/账号/页签菜单互斥和退出等待时关闭继续由外壳管理。内容插槽关闭时卸载,需长期保留的消息数据应放在项目状态中。
已有项目升级新版公共外壳即可在 HostShell 内使用消息插槽;要在生成的 HostLayout 外部传入,需补上上述两处插槽透传。custom 项目的本地 HostHeader 也需迁移这次模板改动,升级 npm 不会覆盖项目文件。
顶栏的 show-search、show-messages、show-user 均默认 true,分别控制搜索、消息和用户入口。关闭入口会卸载对应插槽并关闭已经打开的弹层。popover 继续由外壳内部维护,无需在项目中修改其类型。user-trigger 和 user-menu 可以分别替换账号入口和菜单内容;作用域类型为 HostUserScope,除 expanded、pending、toggle()、close() 外,还提供 userName、profile()、logout()。后两个动作先关闭弹层,再触发原有事件,项目继续复用导航和退出处理器。
<!-- 在已有 HostShell 内增加开关和插槽,其他属性、事件与业务区保持原有接线。 -->
<HostShell :apps="apps" :tabs="tabs" :active-key="activeKey" :user-name="userName"
:pending="exiting" :show-search="false" @open="open" @operate="operate"
@profile="openProfile" @logout="signOut">
<template #user-menu="{ userName, close, pending, profile, logout }">
<strong>{{ userName }}</strong>
<button :disabled="pending" @click="profile">个人资料</button>
<button :disabled="pending" @click="close(); openSettings()">账号设置</button>
<button :disabled="pending" @click="logout">退出登录</button>
</template>
<HostWorkspace />
</HostShell>
openSettings 由项目实现。自定义用户按钮应绑定 :disabled="pending"、:aria-expanded="expanded" 并调用 toggle();关闭入口或 pending 期间,保留的 toggle/profile/logout 回调也不会触发操作。隐藏入口只影响展示,不改变权限。standard/custom 生成模板的 HostLayout 均透传三个显示开关及用户插槽,因此也可以在已有 <HostLayout :session="session" ...> 上使用。已有项目须同步这些模板接线;完整覆盖 header 时,顶栏由项目实现,显示开关仅作用于默认顶栏。
公共样式限定 .fin-micro-shell / .fin-micro-standalone,不写全局 body/reset,不把主页业务样式放进公共库。可在外层设置 --fin-shell-accent、--fin-shell-border、--fin-shell-muted;独立外壳还支持 --fin-shell-surface、--fin-shell-sidebar-width。Element Plus 与图标是 layout 入口的可选 peer;仅使用 core/SDK 不会导入布局、Element 或 CSS。按需指构建依赖隔离,不是 npm 选择性下载包内容。
已有项目接入
升级依赖不会自动改写已经复制到项目中的模板。已有 custom 项目需要一次性迁移:保留认证/host/runtime/router/业务工作区,将头部、侧栏和页签展示改为公共 HostShell,接回原有事件处理器,并导入公共 CSS;Vue 独立布局可改用 StandaloneShell。不要重新生成覆盖现有项目。迁移后,再次升级依赖才会同步公共外壳未覆盖区域。反向切换 custom 时,把当前版本布局源码复制到项目并改回本地导入,核心接线不变。
刷新启动占位
启动动画的结构与样式由生成项目根目录的 index.html 维护,不需要为了修改动画而升级运行库。保留外层 data-fin-startup="loading" 标记;需要自动更新国际化提示的文字节点保留 data-fin-startup-text 标记。启动逻辑首次读取并保存占位,后续挂载和失败重试克隆恢复;未提供占位时回退为文字。已有项目需要同步标记并升级到包含该逻辑的版本,不能仅修改模板文件。
公共 HTML 在模块加载前显示根节点内的启动提示;认证恢复和 router.isReady() 等待期间不提前渲染未授权工作区。Vue 挂载后自然替换。启动失败显示脱敏文案与重试,重试恢复 loading;取消可重试,旧导入、卸载后的按钮和迟到失败均受代次隔离。占位不使用 fixed 全屏遮罩,嵌入子应用只影响自身根区域。本次不是普通业务 HTTP 请求的全局遮罩,也不实现自动 Token 刷新。
按需获取当前 Token
import { getToken } from '@axewo/fin-micro/sdk'
const token = await getToken({ bridge, signal, timeoutMs: 5000 })
// 已登录 Cookie 模式返回 null;未登录、无桥、会话已变化均有独立错误码。
基座通过 createTokenCapability({ apps, getSession, provider }) 显式授权可信应用,每次读取私有凭据,异步后复查会话 revision 与调用存活。Token 不进入公开会话或事件广播。CLI host 模板默认保留 HttpOnly Cookie,后台 login/session 可选返回 accessToken;退出、初始化失败及卸载清除内存。base 请求只在安装 provider 后动态注入,vue bootstrap 在挂载时安装当前会话、卸载时取消并还原;嵌入时按桥能力协商凭据来源,独立时使用 apis/auth.ts 验证的会话。默认仅可信 /api/ 请求可携带 Token,绝对 URL 和被覆盖的 baseURL 不自动注入。
子应用生命周期与环境判断
import { isMicroFrontend, setupWujieLifecycle } from '@axewo/fin-micro/runtime'
import { mount, unmount } from './bootstrap'
// 仅检测当前 Wujie 环境,不代表 bridge 连接、身份或权限。
console.log(isMicroFrontend())
const dispose = setupWujieLifecycle({ mount, unmount })
if (import.meta.hot) import.meta.hot.dispose(dispose)
setupWujieLifecycle 统一注册 Wujie 回调、通知嵌入挂载、独立启动、pagehide 和幂等清理;重复注册会释放旧注册。pagehide.persisted === true 时保留实例与监听,避免 BFCache 返回后留下已销毁的应用;普通离开才释放注册和应用。Wujie 显式 unmount、dispose 与 HMR 清理不受 persisted 影响,不注册 unload,也不通过放宽 Permissions-Policy 掩盖警告。dispose() 返回 Promise,可等待清理完成。错误会报告至 console.error,显式调用生命周期回调可接收失败。bootstrap 自身仍须在 unmount 时使异步初始化失效,封装不能撤销回调内部副作用。SSR 检测为 false,注册不启动应用。环境检测不会把普通 iframe 或自行注册的挂载函数误认为微前端,不探测其他未适配的微前端框架。
基座使用普通启动入口,只有 vue 子应用模板接入上述封装;不再在 base 中注册子应用专属全局回调。
创建命令与项目维护
运行库与创建命令使用同一个包。交互创建或参数创建均可使用:
# 交互式:依次输入目录、选择 host/vue、选择布局、输入子应用 app-id 和端口
npx @axewo/fin-micro@latest create
# 参数式:适合脚本和 CI,不触发问答
npx @axewo/fin-micro create my-host --template host
npx @axewo/fin-micro create order-app --template vue --app-id order --port 7101
host 默认端口 7100,vue 默认端口 7101;项目名与 appId 只接受小写字母、数字和连字符。子应用示例建议指定 --app-id business,与基座默认登记保持一致;或调整基座的环境变量。目标目录必须不存在,父目录必须已存在;命令不覆盖文件、不自动安装依赖、不自动注册远端应用、不执行发布。进入生成项目后运行 pnpm install、pnpm dev 和 pnpm build。生成源码属于项目,CLI 不升级或覆盖既有源码。
基座多应用可信注册表
生成的 host 在 src/configs/microApps.ts 集中维护 microApps,standard/custom 共用同一配置。默认仅启用 business(http://localhost:7101),兼容 .env.local 的 VITE_MICRO_APP_ID/ENTRY;已附上注释的第二应用 report(http://localhost:7102),不会误加载尚未启动的地址。先创建并启动对应子应用,再取消配置注释。该示例实际读取 VITE_REPORT_APP_ENTRY,未配置时回退本机 7102;生产须在构建环境或 .env.local 设置自己的 HTTPS 入口,不能沿用 localhost。仅增加环境变量不会自动登记应用:
npx @axewo/fin-micro create my-report --template vue --app-id report --port 7102
注册项显式包含 appId/name/entry/shareToken。defineMicroApps 统一校验 appId 唯一、禁止宿主保留 host-local、入口 HTTP(S) 和地址安全规则;非本机入口必须 HTTPS。shareToken 必须为布尔值,业务和报表示例默认均为 false;确认完全可信且需要宿主认证后才显式开启。它只决定 Token 读取和认证失败上报能力,不决定应用或菜单授权;为 false 的应用仍可挂载和导航,但不能使用宿主 Token/失效协调,业务请求需采用自己的合法认证方案,不能把能力拒绝当成读取成功。能力白名单始终取当前会话应用与本地 shareToken:true 的交集,后台不能通过 entry 或 shareToken 字段改变代码地址或扩大凭据权限。
登记不等于授权:开发演示会为每个已启用注册项生成自己的菜单和 ${appId}:list 页签,并示范 /detail?id=1;真实模式的 /api/session 与 /api/login 返回 {user:{id,name},permissions:string[],appIds:string[],accessToken?:string},appIds 必须是注册表中的唯一子集。随后 /api/menus 必须完整返回 {apps:[{appId,menus:MicroMenu[]}]},每个已授权应用都要有一项,无菜单时传 [];未知、重复、未授权或遗漏的应用均拒绝初始化。分组为非空 children,叶子为 target,两者互斥;menuId 在应用内唯一、tabId 在整个宿主(含本地主页)内唯一,建议使用 ${appId}:业务标识。名称和 entry 始终来自本地注册表。
子应用 router.meta.hidden 仅控制独立运行的菜单展示,不影响基座后台菜单,也不授予或撤销页面权限。嵌入菜单由后台协议决定;详情等不展示入口在 platform/access.ts 的 canOpenRoute 显式授权,默认仅有带 demo:read 且具备 records 列表菜单的详情规则。详情策略优先于普通菜单,后台返回详情菜单也不能绕过;route 的数字 ID 必须与 tabId 一致。增加报表真实业务路由时同时替换演示菜单和详情规则,不能仅隐藏菜单来保护路由;后台 API 仍须校验登录、操作权限和资源归属。
业务功能目录
生成项目的业务页按功能聚合:Vue overlay 的 views/demo/index.vue 是 /list 列表装配层,views/demo/configs/table.ts 维护 fin-ui 表格/表单配置,views/demo/hooks/useRecordNavigation.ts 处理权限与详情导航,views/demo/types.ts 定义仅本功能使用的类型,views/demo/modules/detail/index.vue 是二级详情页。base 中被覆盖的计数页、demo store 与 demo 路由已移除。宿主的 views/login/index.vue 编排登录会话,表单展示位于 views/login/components/LoginForm.vue;主页、个人中心、工作区和 404 分别在各自的 views/{功能}/index.vue。按实际职责扩展 api/、configs/、hooks/、components/、modules/,不建立空目录或纯转发 hook。功能独有请求放功能 api/,可复用请求遵循项目约定放 src/apis;已生成项目的旧路径不会被包升级自动改写。
vue 独立布局与本地路由菜单
Vue 子应用独立运行显示头部、Element Plus 左侧菜单和内容区:standard 模式由公共 StandaloneShell 展示,custom 模式保留 layout/Header.vue、Sidebar.vue 和 StandaloneLayout.vue 本地源码;嵌入基座时均隐藏子应用头部和菜单。AppProviders 始终包裹全树,两种模式共用原业务页面、会话和 SDK 生命周期;嵌入继续使用原 MicroTabCache / MicroRouteView 及 tab.key 缓存契约。布局和 history 均使用 SDK isMicroFrontend() 判断 Wujie 环境,不以 bridge 是否连接、URL 或端口推断;缺桥的嵌入运行仍隐藏外壳并使用 memory history。
独立菜单由 router.options.routes 的本地声明树生成,不请求后台菜单,并按当前已验证会话过滤权限。meta.title 为回退菜单文字,titleKey 从 fin-locale 的业务映射翻译,permissions 声明访问要求,icon 为 Vue 图标组件(示例使用 @element-plus/icons-vue),order 按同级升序排列(默认 0,同值保留声明顺序),hidden 隐藏整棵菜单子树,activeMenu 指定活动菜单完整路径。默认登录后展示“主页 / 业务列表”,登录页隐藏;详情 /detail 设置 hidden: true, activeMenu: '/list', permissions: ['demo:read'],验证身份且具备权限后可访问并高亮列表。默认跳转、404、动态参数路由不生成菜单;无标题父级提升可见子项,有标题且有可见子项的父级递归显示 Element 子菜单,相对子路径拼为完整路径。菜单展示不代替路由准入;独立守卫与嵌入 MicroRouteView 均检查同一权限元信息,宿主仍负责 canOpen 授权。
生成后执行项目内的 check:runtime、typecheck 与 build,再验收独立与嵌入运行、菜单排序、权限过滤、递归菜单及详情高亮。库的 prepack 执行类型、构建和发布清单检查;这些检查不安装消费者项目依赖,也不代替业务浏览器验收。
host 本地登录与主页体验
使用 pnpm 12.3.4 安装时,生成项目自带 pnpm-workspace.yaml,通过 allowBuilds 仅批准 [email protected]、[email protected] 的安装脚本,不必为这两个版本重复执行 pnpm approve-builds。其他包或版本仍需审核,不启用全量脚本放行。已生成的项目须手动合并该配置;若项目已有 pnpm-workspace.yaml,保留原设置,只合并 allowBuilds,再执行 pnpm install。pnpm 低于 10.26 的版本需按其版本支持的方式授权;不要混用已移除的旧配置。
打开 Vite 输出的本机地址(默认端口 7100),在现有账号密码表单中使用 demo / 123456(开发模拟时默认预填),点击“演示登录,进入主页”。开发默认启用模拟登录,不需要后端或子应用,严格校验演示账号密码,错误或空凭据拒绝登录,成功后固定显示“演示用户”。此凭据仅用于开发模拟,请勿输入真实凭据;提交即清空密码输入,加载期间禁止重复提交。登录后默认打开真正的本地主页;左侧 Element 菜单、顶部搜索、个人菜单均可打开“主页 / 个人中心”。个人页展示公开身份,可回主页或退出。主页与 apps/micro-host 一样属于唯一 core tabs,而非独立入口或第二套标签状态:认证后在恢复前同步登记,初始、直链和刷新恢复均固定首位且不重复;缺少主页或主页顺序错误的旧快照自动迁移,业务页之间的顺序不变。主页无关闭按钮,右键菜单禁用刷新与关闭;“关闭全部业务页 / 其他 / 左侧 / 右侧”始终排除主页(个人中心也属于可关闭页)。业务页仍可正常刷新;关闭活动页在一次核心事务内回落主页,URL 经同一 Vue Router 更新,守卫拒绝则保持原页和 URL。不放置虚假业务数据或未实现业务按钮。
刷新仅凭当前标签页 sessionStorage 的 fin-micro:demo-session:v1=1 标记恢复固定演示身份,随后通过原 connectMicroBrowser 恢复已授权页签,产生新的生命周期 key。它不是 Token,不含账号密码,不访问认证接口。禁用浏览器存储时仍可登录,但无法跨刷新恢复。退出先显示一次系统 FDialog 确认;确认后清除演示标记与私有凭据,dispose 工作区,不逐页重复确认。认证失效也清除标记,组件卸载不清除标记以支持刷新。
如需真实后端联调,在 .env.local 设置 VITE_AUTH_DEMO=false。生产构建始终禁止演示,即使设置 true;请求 /api/session、/api/login、/api/menus、/api/logout,任何网络、认证或菜单失败均不降级演示。平台实现拆分到 platform/ 的 auth.ts、session.ts、menu.ts、access.ts,platform.ts 保留旧导出。权限最多 500 项,授权应用数不超过本地注册表,菜单响应必须完整覆盖,每应用最多 500 节点、8 层。生产平台登录/注销默认要求 configs/platformSecurity.ts 提供服务端 CSRF Token,缺失时拒绝发送;跨源凭据请求需要服务端配置精确来源、允许凭据与 CSRF 校验,不能使用通配来源。后台菜单只提供授权路由,应用执行地址来自可信本地注册表。
本地页使用明确的 { kind: 'local', appId: 'host-local' } 注册,禁止 entry;host-local 为宿主保留 appId,不能配置给远端应用。localPages.ts 固定 route/tabId 白名单,HostWorkspace 直接使用 HomeView/ProfileView SFC,Wujie 明确拒绝 local;不会把本地页面伪装成 HTTP 远端。两类页面复用同一 core 的标识、激活、关闭、刷新、守卫和 browser 恢复。远端仍按 appId 单实例挂载,Token 与 Auth 失败能力只向当前会话和本地 shareToken:true 注册表交集授权。可选业务入口需要启动子应用,但它离线不影响本地工作台。
scaffold/base 保存公共骨架,scaffold/host、scaffold/vue 按类型覆盖差异文件;两类模板统一接入 fin-ui。基座仅包含登录、公开用户信息、菜单与微前端平台编排,不包含系统管理业务。认证示例不是生产认证,需替换接口适配并补齐服务端鉴权;应用入口、appId、菜单权限需按实际配置。
运行库通过 npm 依赖导入,不复制 core 源码。公开包使用 files 白名单,仅交付运行库 JS、类型声明、创建命令与可公开的骨架源码,不交付运行库 src 或 sourcemap。编译 JavaScript 仍然可被分析,不应含密钥或保密逻辑。库升级需回归、构建、部署,无需重新创建项目;模板更新不会自动迁移生成项目。
生成项目的 src 统一保留 stores/router/layout/locales/hooks/utils/types/components/views/styles;Vue 子应用额外提供 apis/auth.ts 适配独立认证后端。每轮 bootstrap 创建独立 router、Pinia、fin-locale 与会话,卸载清理凭据读取、订阅和 history。AppProviders 直接使用 fin-ui 的 FinLocaleProvider,项目通过 src/locales/index.ts 统一组装业务词条、安装并返回 i18n,语言切换通过 @axewo/fin-locale。认证请求、地址校验和脱敏错误分类归 fin-core;会话、权限与启动生命周期归 fin-micro。utils 只保留兼容入口和业务配置,
地址栏修改仍经过基座 canOpen;子应用本地路由也通过统一公开身份检查 meta.permissions。独立模板统一先登录,列表不额外要求功能权限,详情要求 demo:read。前端准入不能代替后台接口的登录、操作权限与资源归属验证。standard 公共布局与 custom 模板仅面向桌面,使用 100vh 与工作区内部滚动,不提供移动断点或 dvh 适配。
host 真实路由与 URL 所有权
/login:真实登录路由;登录成功只允许跳转到当前会话已授权的内部目标,外链、协议相对地址、反斜杠、登录循环、未知或未授权目标均回落/home。/home、/profile:已认证工作区中的本地页;远端活动页使用/micro/{appId}/{子应用内路径}?query,地址不携带页签标识;/workspace仅作为工作区入口。/重定向主页,未匹配路径展示 404。bootstrap每个 App 仅创建一个createPlatformSession(),一次恢复 Promise 供初始路由守卫等待;usePlatformSession()仅注入,不重复 restore 或注册 401 监听。正常退出经一次系统确认再撤销会话、清理工作区并进入/login;401 失效立即撤销,不被离页确认阻断。- host 的
connectWorkspaceBrowser先登记固定主页,再使用connectMicroBrowser(host, { url: false, initialLocation, storageKey })仅恢复/持久化用户隔离页签。router/workspace.ts统一协调 Vue Router 和 core:UI 导航写入 router,直链/返回经过路由与页签守卫。连接器不再监听或覆盖 host 的 hash;未配置url:false的旧使用方式仍保留 hash 协议。 - 首次深链优先于存储,恢复逐项经过
canOpen;整页刷新产生新的 core key,不恢复 Token、草稿或沙箱实例。生产服务器必须将/login、/home、/profile、/workspace及其他 SPA 路径回退到该应用index.html,静态资源与/api/不应被改写。子目录部署需同时配置 Vite base 和服务器回退目录。
交互关闭统一通过宿主 workspaceOperation 加上 exclude 与 closeFallback,不修改通用库的默认关闭规则。close/closeMany.closeFallback 是可选的生命周期引用:只在活动页被关闭且目标仍存活时同事务回落,不创建页面;旧 key 不复活重开页,页面 SDK 不能借它跨应用导航。正常退出单独确认后 dispose 工作区;真实失效直接清理全部,不被固定页策略阻断。固定不是权限或资源保留机制;底层宿主原语仍允许显式清理。模板与运行库需使用本次配套构建,不能仅更新模板沿用旧 dist。
host 统一路由守卫与扩展
router/guards.ts 是唯一 beforeEach 注册入口,执行顺序为:等待 controller.ready → 读取最新身份 → 登录与安全 redirect → 固定路由/远端授权和可选 meta.permissions → beforeEnter 业务扩展 → 当前 workspace 核心事务。router/index.ts 只声明路由并安装守卫,router/workspace.ts 使用 attachWorkspaceGuard 挂接现有 core operate/beforeLeave,不再注册第二个前置守卫。未登录受保护页进入 /login?redirect=...;已登录访问 /login 只返回经过 authorizedRedirect 检查的内部授权目标。404 保持独立兜底;已登录工作区离开到 404 仍须通过业务未保存确认。
公开结构:
installHostGuards(router, controller, options?) → dispose:每个 router 只允许一个安装;返回幂等撤销函数。HostGuardOptions.beforeEnter({ to, from, session, signal }) → boolean | void | Promise<boolean | void>:在内置授权后执行,返回 false 取消,true/void 继续;抛错或拒绝会取消并报告,不能凭扩展放宽内置白名单。HostGuardOptions.onError(error):供宿主脱敏展示,不直接把原始异常写入 UI。attachWorkspaceGuard(router, delegate) → detach:只供工作区桥接核心离页事务,重复连接拒绝;卸载撤销旧委托,不能通过组件另建 beforeEach。createAppRouter(controller, history?, options?) → router & { disposeGuards() }:bootstrap 在卸载、启动失败和重挂载时显式撤销守卫,再销毁 history。
可在 bootstrap 的原 createAppRouter 调用处增加业务限制,不要另调 router.beforeEach:
const router = createAppRouter(controller, undefined, {
onError: reportError,
beforeEnter: ({ to, session, signal }) => {
if (signal.aborted) return false
// 示例:业务条件只能进一步限制已获本地路由白名单授权的入口。
return to.path !== '/profile' || Boolean(session.user.id)
},
})
路由记录可加 meta: { authenticated: true, permissions: ['demo:read'] },表示必须具备全部声明权限;生产替换为真实权限码,同时补齐本地 route/tabId 白名单与页面映射,不能仅靠 meta 添加任意受保护页面。该前端检查不代替后台授权。
新导航、身份替换或撤销会中止旧守卫等待;每次异步边界后复查导航代次和身份对象,迟到恢复/扩展结果不能放行旧导航。取消信号只撤销导航等待,不自动取消已经发生的保存或外部副作用。正常退出先完成一次系统确认;真实失效及注销撤销身份后跳过旧 workspace 委托,优先清理资源。首次恢复提交身份属于 ready 本身,不会误取消首次直链或刷新导航。
启动依赖门禁
生成项目在 npm run dev/build 前自动执行 scripts/check-runtime.mjs,也可单独运行 npm run check:runtime。它加载实际安装包并校验模板使用的导出,host 额外要求 @axewo/fin-micro 导出 hostRouterProtocol === 1(local、认证能力、仅存储连接器),缺失时在 Vite 链接前明确报告模块/API。版本号由生成器实际 package.json 注入;同版本的旧构建仍可能缺能力,不能靠版本字符串保证可用。请安装配套构建的 core/UI/micro 包,模板不会自动升级或降级依赖,也不能以源码 alias 验证代替实际安装验证。直接运行 vite 会绕过 npm 的前置门禁,不推荐。
公共启动入口 @axewo/fin-micro/startup 支持 { development: true } 显示固定阶段和白名单错误名;默认关闭,生产保持脱敏。界面不回显原始异常 message、Token、请求/响应或堆栈。配置类错误需核对公开环境配置;能力门禁不代表后端连通性或接口协议正确。
公共配置、错误边界与登录失效
公共 utils/appConfig.ts 集中校验 VITE_API_BASE(默认 /api/)、VITE_API_TRUSTED_BASE(默认与 API 一致)、VITE_API_TIMEOUT(默认 30000 毫秒)及 VITE_API_CREDENTIALS(仅接受字符串 true/false,默认 false)。两个 API 目录必须完全一致、以 / 结尾;拒绝 userinfo、查询、片段、路径穿越及编码分隔符。跨源生产网关与应用代码入口使用 HTTPS,本机开发允许 HTTP。环境变量是公开部署配置,不能包含秘密。跨源 Cookie 需后端精确 CORS 与 CSRF 防护;默认相对 API 属于当前子应用运行源,并非自动代理到宿主。
utils/errorUtils.ts 将 Axios/HTTP/SDK 错误统一映射为取消、未登录、无权限、超时、网络及未知错误。界面与日志仅消费固定安全文案,不展示原始 message、响应体、URL、头、Token 或堆栈;取消静默。Vue errorHandler、登录表单、导航与连接失败使用相同分类。入口动态加载 bootstrap,因此模块加载/配置校验错误也有纯文本启动兜底与重试;卸载使晚到导入失效,失败与重挂载继续清理 router/Pinia/凭据订阅。构建配置错误需要更正环境并重新构建/刷新;重试不保证浏览器重新求值已失败的 ESM 模块。
Vue 嵌入时协商并安装 getToken/beginAuthRequest/reportAuthFailure。createAuthFailureCapabilities 是 SDK 正式契约,复用 callHost 白名单和生命周期;每次可信请求先获取不含凭据的不透明内存票据,绑定宿主私有凭据版本与可信 appId。401 或 Token 未登录按原票据报告,宿主核验后立即撤销身份、推进版本;并发仅失效一次,旧响应不能退出新登录。票据不得复制、序列化、持久化或用于 iframe RPC。平台自身请求也在发送时捕获私有版本。正常主动退出经一次系统确认,真实认证失效不允许被未保存守卫阻止。模板不刷新 Token、不自动重放任何请求,也不新增总线或请求库。
独立 Vue 应用通过 src/apis/auth.ts 接入真实会话、登录、恢复和退出。模板内置 /login 登录页,成功后进入 /home 主页;账号密码登录不再使用弹窗,菜单由本地路由生成,不请求后台菜单。未登录与会话失效回到登录页,功能权限不足显示 403。开发服务器独立运行时顶栏仍提供「开发设置」,Token 经 GET /api/session 验证后保存到按 appId 隔离的 localStorage;刷新自动验证恢复,无需重复设置。清除、退出和当前请求 401 删除本地值;卸载保留它以支持刷新。生产构建和宿主嵌入均不读取开发 Token 存储。嵌入时不注册独立登录页、主页,身份和菜单仍来自宿主。基座自己的 DEV 演示身份配置保持原协议,真实接口失败不会降级为演示登录。
平台认证适配器与模板更新
@axewo/fin-micro/vue 导出 createPlatformAuth,创建时提供直接返回响应体的独立认证请求客户端 http 和公开客户端标识 clientId。默认使用 auth/code、auth/login、system/user/getInfo 和 auth/logout;可通过 paths 覆盖,通过 parsers 转换完整响应体,或通过 identity 转换默认响应中的身份数据。认证客户端不能使用依赖当前会话的凭据拦截器,否则登录可能等待自身会话。验证码通过 loadCaptcha(signal) 获取,登录通过 signIn(session, username, password, answer?) 交由公共会话管理;适配器本身不会自动接入生成项目,需在项目认证配置中显式装配并验证后台协议。
默认响应要求状态码为 200,登录返回有效访问令牌、匹配的客户端标识及有效期,随后验证用户身份;验证码仅接受受限的图片格式。自定义转换结果仍经过校验。认证和权限校验不能替代服务端鉴权,不要将凭据放入前端环境变量。
新生成模板的开发服务器提供 @ 源码别名,并根据 VITE_API_BASE、VITE_API_AUTH_BASE 和 VITE_API_PROXY_TARGET 配置开发代理;代理仅在开发时生效,生产网关需自行配置。模板补充图标及类型依赖,调整启动动画颜色,并将独立登录页表单逻辑移至功能目录的钩子。已有项目不会因升级依赖自动更新这些文件,应按需合并并重新检查、构建。
认证模式、启动就绪与运行状态
子应用公开配置 VITE_MICRO_AUTH_MODE 支持 auto(默认)、host、independent。auto 在宿主完整授权 getToken/beginAuthRequest/reportAuthFailure 时接入宿主认证,三项均未授权时使用应用自己的认证;只授权部分能力会明确失败。host 必须获得全部能力;independent 不读取宿主 Token。三种模式仍校验桥协议,独立认证也不授予任何业务权限。这样 shareToken:false 的子应用可正常挂载,但独立认证接口及权限由项目实现。
createWujieRuntime(host, { waitForReady: true, mountTimeoutMs: 30000, readyTimeoutMs: 30000 }) 将资源启动与业务初始化分开等待。资源阶段完成后,子应用通过 setupWujieLifecycle 在异步 mount() 完成时回报就绪,失败回报 BOOTSTRAP_FAILED。入口自行捕获初始化异常时,须调用 /sdk 的 getMicroAppLifecycle()?.fail();模板启动边界已接入。旧应用未实现回报时保留默认 waitForReady:false,不要直接开启等待。
返回的 runtime 增加 getState(appId) 和 subscribe(listener),快照包含 appId/attemptId/status/elapsedMs/errorCode。状态依次反映 loading → initializing → ready,卸载为 unmounting → idle,失败为 failed。错误码包括 LOAD_FAILED、LOAD_TIMEOUT、READY_TIMEOUT、BOOTSTRAP_FAILED、MOUNT_CANCELLED、UNMOUNT_FAILED。订阅仅通知后续变更,监听器异常不改变挂载结果。每次重试使用独立回报通道;旧实例晚到的回报不能覆盖新尝试。operate() 提交导航仍不等于应用就绪,加载与失败展示使用 runtime / MicroAppContainer。
公共工作区与运行时资源治理
导航先准备再等待 Router 成功后提交,覆盖 beforeEnter、异步组件和 beforeResolve 拒绝;取消排队任务立即结束。宿主新增 navigationTimeoutMs(120000ms)和 maxPendingNavigations(100),分别报告 NAVIGATION_TIMEOUT 和 QUEUE_FULL。
运行时支持 unmountTimeoutMs(5000ms)、maxMountedApps(16)和 maxConcurrentMounts(4),通过 getResources() 读取实例、加载与残留沙箱数量。预算不足以 RESOURCE_LIMIT 拒绝,不自动关闭脏页。每次挂载注入独立可撤销 bridge,旧实例的 PageSDK、订阅和未提交调用随卸载释放。原始 Wujie 异常统一转为 MicroRuntimeError,销毁异常/超时为 UNMOUNT_FAILED/UNMOUNT_TIMEOUT。
卸载超时结束公开等待并隔离旧 DOM,不代表强制终止第三方 JavaScript;不能确认清理完成的沙箱继续计入预算。
模板与运行库保留同一发布包,通过 sdk/core/runtime/vue 子入口维护边界。useMicroWorkspace(apps, { host, runtime, onError }) 统一创建宿主、运行时及关闭重开代次 epochs;own(cleanup) 登记连接器释放,dispose() 幂等且立即撤销宿主能力,再异步销毁沙箱。Vue 组件卸载自动清理。connectMicroHostRouter(host, router, options) 处理核心事务与 Vue Router 同步,并在断开时取消挂起导航;认证守卫注册、路由映射、固定页策略仍由项目回调提供。后台接口、菜单和业务权限继续保留在生成项目。
生成项目的 fin-micro.json 记录模板版本、生成器版本、布局与应用标识。已有项目应按实际源码完成迁移,不要仅修改版本标记。可在项目目录执行以下只读检查:
npx @axewo/fin-micro@latest doctor .
doctor 离线只读检查模板身份、appId、安装依赖可解析性以及 SDK/Vue/runtime 实际能力;失败返回非零状态,不自动改文件或联网安装。它不检查后端权限、部署入口、CORS/CSP 或浏览器兼容性,这些仍由联调验收负责。
离页守卫的等待上限
createMicroHost(apps, { guardTimeoutMs: 60000 }) 为每个异步守卫设置等待上限。超时以 NavigationError.code === 'GUARD_TIMEOUT' 取消本次导航,不自动放行、不重试保存。宿主销毁立即以 HOST_DISPOSED 结束挂起守卫,调用方取消同样释放队列。beforeLeave(({ signal }) => ...) 的信号可传给保存请求以协作清理;迟到结果不能提交已取消的导航,已经发生的服务端副作用仍由业务处理。
未保存表单
import { useUnsavedChanges } from '@axewo/fin-micro/vue'
const { dirty, setBaseline } = useUnsavedChanges(() => form, {
label: '基础信息',
message: { title: '离开编辑页?', content: '修改尚未保存,是否放弃?' },
})
// setup 调用一次,自动追踪字段;查询赋值后 setBaseline()。
// 保存成功后 setBaseline(本次提交的独立快照),保存失败不重置。
模板通过 installMicroConfirmation 与项目 ConfirmationDialog.vue 统一使用 fin-ui FDialog。嵌入页面按固定 tab.key 登记,不把表单数据传给基座;缓存页签切换不提示,关闭/刷新/替换时聚合一次确认,批量关闭列出所有受影响页面。独立运行由 connectUnsavedChangesRouter 保护路由切换。退出只进行一次系统确认,取消保留原状态,确认后直接清理工作区,不重复执行逐页守卫。第二参数支持 enabled/formId/label/message,文案可用 getter;content/html 二选一,富文本经受限标签清理。
响应式权限示例
新生成的 host/vue × standard/custom 模板已注册 v-hasPermi,列表的「打开详情」按钮使用 demo:read 演示显隐。已有项目需在当前 app.mount 前补充注册;installMicroSession 不会自动安装指令:
import { installMicroSession, installPermissionDirectives } from '@axewo/fin-micro/vue'
// 沿用 bootstrap 中当前 app 和 createBridgeSession() 得到的 session。
installMicroSession(app, session)
installPermissionDirectives(app, session.identity) // 传 ref,不传 .value 快照
host 使用平台控制器:installPermissionDirectives(app, () => controller.session.value ? publicSession(controller.session.value) : null),其中 publicSession 从项目的 ./platform 导入。每个 App 注册一次并使用自己的响应式会话,嵌入子应用沿用桥同步,无需重新请求或复制权限。
<template>
<el-button v-hasPermi="'button_001'">查看</el-button>
<el-button v-hasPermi="['button_002', 'button_003']">新增或删除,任意一项满足即可</el-button>
</template>
字符串表示单项,非空合法数组表示任意一项;标识全局唯一即可,不要求「应用:资源:操作」格式。已认证会话的 permissions: ['*:*:*'] 表示管理员,放行全部有效标识,*、order:* 没有此含义。未登录、空白绑定、空数组或含非法项的数组均隐藏,管理员也必须使用有效绑定。
指令随登录、授权、撤权和退出更新,通过 CSS 隐藏并在授权后恢复原 display,组件仍会创建;只用在原生元素或单根组件(如 el-button),不与同元素 v-show 混用。需要全部权限或不创建组件时使用 v-if:
import { computed } from 'vue'
import { usePermission } from '@axewo/fin-micro/vue'
// setup 中默认使用 installMicroSession 注入的身份;也可显式传 identity ref/getter。
const permission = usePermission()
const canRead = permission.can('demo:read')
const canEdit = computed(() => permission.hasPermission('demo:write'))
const canUse = computed(() => permission.hasAny(['demo:read', 'demo:write']))
const canManage = computed(() => permission.hasAll(['demo:read', 'demo:write']))
<template>
<el-button v-if="canRead">有权限时才创建</el-button>
<el-button v-if="canManage">同时拥有读取和写入权限</el-button>
<el-button :disabled="!canEdit">保留展示,无权限时禁用</el-button>
</template>
框架无关逻辑首选从 @axewo/fin-core/permission 导入 hasPermission(session, name)、hasAny(session, names)、hasAll(session, names);/sdk 同名函数保持兼容并调用 core。Vue 权限变更/退出立即更新计算值;普通函数在 computed/模板内调用才追踪依赖,不要把单次布尔结果当作响应式状态。按钮显隐仅辅助体验,核心 canOpen 和服务端仍须独立鉴权。
locales / router / stores 接线
两类生成项目均包含 locales/modules/app_zh-CN.ts、locales/modules/app_en.ts 与各自的真实路由。业务词条按 模块名_语言.ts/json 命名,例如 User_zh-CN.ts 导出 { name: '姓名' },对应 t('User.name')。locales/index.ts 自动收集并按语言和模块命名空间合并,调用 installFinI18n(app, { messages }) 注入公共与业务词条,默认导出 setupI18n(app) 并返回当前应用的 i18n;页面使用 useFinLocale 切换语言。语言入口从 FConfigProvider 的 config.langs 读取选项,AppProviders 透传该配置,未配置时默认中英文;扩展语种支持选择、保存和宿主同步,缺失文案默认回退中文。宿主和独立 Vue 应用在首次渲染前通过 connectFinLocaleStorage 恢复语言,切换后立即保存,卸载释放观察。存储键分别为 fin-micro:locale:host:<项目名> 和 fin-micro:locale:app:<appId>,避免互相覆盖;存储被禁用时保留内存切换。嵌入子应用只通过 connectMicroLocale 跟随宿主偏好,不读写独立语言存储,也不改变认证版本。已有项目需要升级配套包并迁移 bootstrap 接线,每轮挂载创建独立 Pinia,已移除未使用的计数 store、router/demo.ts 和 /demo 入口。
- vue 独立运行:启动后先在
/#/login登录,再从主页菜单进入/#/list(默认端口 7101);列表/详情与缓存接线保留。 - vue 嵌入基座:后台
/api/menus须为当前已授权应用返回列表入口,例如{ menuId: 'records', name: '示例记录', target: { tabId: 'business:list', route: '/list' } }(替换实际 appId 前缀),再从基座菜单打开;未授权深链仍被拒绝。 - host 本地扩展:在 host 的
router/index.ts添加真实路由记录及认证元信息,并在router/targets.ts补充固定路由到 core 页签的映射;工作区页面还需补充localPages.ts的精确白名单及HostWorkspace.vue的显式 SFC 映射。本地路由不能代替平台授权。
业务添加 store 后,组件外显式传所属 Pinia 实例,组件内由已安装的 Pinia 注入。多页签属于同一子应用时共享该应用的 store;需要按页签隔离的业务状态应显式按页签标识管理。
包入口
| 入口 | 用途 |
|---|---|
/sdk | 框架无关类型、桥获取、调用/导航契约 |
/core | 应用登记、宿主状态、导航事务与能力白名单 |
/runtime | Wujie 单 appId 单实例挂载和清理 |
/vue | Vue 容器、路由连接、页签缓存与页面 SDK |
/browser | 基座 URL 和公开导航元信息恢复 |
/iframe | 显式窗口来源校验的独立 RPC |
非 Vue 应用使用独立子入口;根入口包含 Vue 适配。
Vue 子应用在本地维护正常 Vue Router 路由表,基座只传递 appId 和应用内 route,不传组件文件路径。缓存内容直接使用 MicroRouteView,不必复制路由解析器:
<MicroTabCache :tabs="tabs" :active-key="activeKey">
<MicroRouteView />
</MicroTabCache>
MicroRouteView 需要应用安装 Vue Router ^4.5.0 并调用 app.use(router);提供固定页面路由上下文、懒加载、路由记录 redirect、可见错误及重试。它不执行全局导航守卫、不修改宿主页签;嵌入模式不要同时对每个页签调用共享 router.replace,跳转和离页确认仍使用 PageSDK。
使用前必须知道
- 同 appId 只运行一个实例,应用内通过不同 tabId 打开多个路由页;key 代表具体页面生命周期。
openTab/operate保持应用隔离;跨应用打开使用page.navigateTo,由宿主canNavigate显式授权并继续检查canOpen。- 功能页关闭使用
sdk.back(target?):传完整 OpenTab 时优先去指定目标,不传则返回来源;跨应用来源返回须宿主crossAppBack: true(模板已开启)。中间来源关闭后跳过至存活祖先,页签栏关闭规则保持现状。显式跨应用目标检查 canNavigate/canOpen,来源返回只复核 canOpen;拒绝时保留本页。 - 参数迁移: 旧版
sdk.back(input)的 input 是 fallback,本版改为显式优先目的地。需要旧行为时使用sdk.operate({ type: 'back', fallback: input })。使用示例、结果处理、协议能力检查与生命周期边界见功能页面关闭。 - 导航 committed 不代表资源加载完成;运行时错误与重试另行处理。
- 公开会话不带 Token,宿主能力使用显式白名单;同窗口桥不是恶意代码安全沙箱。
- 超时/取消不回滚业务副作用;缓存和 sessionStorage 导航恢复不代替草稿持久化。
- iframe RPC 不是完整 AppBridge、守卫或缓存的透明代理。
生产构建与接入检查
pnpm check:production
pnpm --filter @axewo/fin-micro typecheck
pnpm --filter @axewo/fin-micro build
pnpm --filter @axewo/fin-micro check:package
测试用例及临时验收工程已移除。类型、构建、公开入口、模板运行能力和发布清单检查继续在 prepack 与 CI 中执行;静态检查不能替代真实后台和浏览器业务验收。
模板版本为 3,使用纯路径路由,生成项目固定使用当前配套 UI 版本;源码生成读取 core/locale 的实际 workspace 版本,打包后使用 pnpm 改写的依赖版本。已有工程仍需按文档同步源码,再执行 fin-micro doctor 和生成项目内的 check:runtime。
生产部署的 HTTPS、路由回退、CORS/CSP、认证及后台权限按项目环境验收。