kl-boss-message-hub
v1.0.0
Published
跨域跨标签页纯前端消息与会话状态中间件
Maintainers
Readme
kl-boss-message-hub
纯前端跨域、跨标签页消息与会话状态中间件。通过可配置的静态 Hub 页(隐藏 iframe)+ SDK,在同一 hubUrl + namespace 下完成事件在线投递与会话内状态同步。不依赖业务后端、SSE、WebSocket。
从 boss-message-hub 迁移(BREAKING)
| 项目 | 旧 | 新 |
|------|----|----|
| npm 包名 | boss-message-hub | kl-boss-message-hub |
| CDN ESM | boss-message-hub.esm.js | kl-boss-message-hub.esm.js |
| CDN IIFE | boss-message-hub.global.js | kl-boss-message-hub.global.js |
| 全局对象 | BossMessageHub | 不变(仍为 BossMessageHub) |
pnpm remove boss-message-hub
pnpm add kl-boss-message-hub
# 并将源码中 import 路径改为 'kl-boss-message-hub'线协议通道名未改,已部署的 Hub 页与新旧 SDK 在协议层仍可互通。
安装与接入
1)<script> 引入(IIFE 全局)
部署 dist/kl-boss-message-hub.global.js 后:
<script src="https://your-cdn/kl-boss-message-hub.global.js"></script>
<script>
const hub = BossMessageHub.createHub({
hubUrl: 'https://your-hub-host/hub.html',
namespace: 'boss',
onError(err) {
console.error(err.code, err.message)
},
})
await hub.ready
hub.subscribe('ui:ping', (payload) => console.log(payload))
await hub.publish('ui:ping', { from: 'a' })
await hub.setState('tenant', { id: '1' })
console.log(await hub.getState('tenant'))
</script>2)<script type="module"> 引入(ESM)
部署 dist/kl-boss-message-hub.esm.js 后,可用原生 ES Module(相对路径或 CDN URL):
<script type="module">
import { createHub } from './kl-boss-message-hub.esm.js'
// 或:import { createHub } from 'https://your-cdn/kl-boss-message-hub.esm.js'
const hub = createHub({
hubUrl: 'https://your-hub-host/hub.html',
namespace: 'boss',
onError(err) {
console.error(err.code, err.message)
},
})
await hub.ready
hub.subscribe('ui:ping', (payload) => console.log(payload))
await hub.publish('ui:ping', { from: 'a' })
</script>3)npm / 打包器 ESM
pnpm add kl-boss-message-hubimport { createHub } from 'kl-boss-message-hub'
const hub = createHub({
hubUrl: 'https://your-hub-host/hub.html',
namespace: 'boss',
})4)在 Vue 3 中使用
pnpm add kl-boss-message-hub<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import { createHub } from 'kl-boss-message-hub'
const tenant = ref(null)
const lastPing = ref(null)
let hub
let unsubPing
let unwatchTenant
onMounted(async () => {
hub = createHub({
hubUrl: 'https://your-hub-host/hub.html',
namespace: 'boss',
onError(err) {
console.error(err.code, err.message)
},
})
await hub.ready
unsubPing = hub.subscribe('ui:ping', (payload) => {
lastPing.value = payload
})
unwatchTenant = hub.watchState('tenant', (value) => {
tenant.value = value
})
})
async function sendPing() {
await hub?.publish('ui:ping', { from: 'vue3' })
}
async function saveTenant() {
await hub?.setState('tenant', { id: '1' })
}
onUnmounted(() => {
unsubPing?.()
unwatchTenant?.()
hub?.destroy()
})
</script>
<template>
<div>
<p>tenant: {{ tenant }}</p>
<p>lastPing: {{ lastPing }}</p>
<button type="button" @click="sendPing">publish</button>
<button type="button" @click="saveTenant">setState</button>
</div>
</template>5)在 Vue 2 中使用
npm install kl-boss-message-hub
# 或 yarn add kl-boss-message-hubVue 2 + webpack/vue-cli 一般可直接 ESM 引入;若构建报错,确认 babel 能转译 node_modules/kl-boss-message-hub(按需加入 transpileDependencies)。
<template>
<div>
<p>tenant: {{ tenant }}</p>
<p>lastPing: {{ lastPing }}</p>
<button type="button" @click="sendPing">publish</button>
<button type="button" @click="saveTenant">setState</button>
</div>
</template>
<script>
import { createHub } from 'kl-boss-message-hub'
export default {
name: 'HubDemo',
data() {
return {
tenant: null,
lastPing: null,
hub: null,
unsubPing: null,
unwatchTenant: null,
}
},
async created() {
this.hub = createHub({
hubUrl: 'https://your-hub-host/hub.html',
namespace: 'boss',
onError(err) {
console.error(err.code, err.message)
},
})
await this.hub.ready
this.unsubPing = this.hub.subscribe('ui:ping', (payload) => {
this.lastPing = payload
})
this.unwatchTenant = this.hub.watchState('tenant', (value) => {
this.tenant = value
})
},
methods: {
async sendPing() {
await this.hub.publish('ui:ping', { from: 'vue2' })
},
async saveTenant() {
await this.hub.setState('tenant', { id: '1' })
},
},
beforeDestroy() {
if (this.unsubPing) this.unsubPing()
if (this.unwatchTenant) this.unwatchTenant()
if (this.hub) this.hub.destroy()
},
}
</script>Vue 2.7 若用 Composition API,写法可对齐 Vue 3;销毁钩子用 onBeforeUnmount(不要用已废弃的 beforeDestroy 选项混用同一实例)。
部署 Hub
pnpm build 后 dist/ 产物分工如下:
| 文件 | 用途 | 是否进 npm |
|------|------|------------|
| index.js + index.d.ts | npm / 打包器 import { createHub } from 'kl-boss-message-hub' | 是 |
| kl-boss-message-hub.esm.js | <script type="module"> / CDN 直链 | 否(静态资源) |
| kl-boss-message-hub.global.js | <script> 全局 BossMessageHub | 否(静态资源) |
| hub.html + hub.js | Hub 中继页(hubUrl 指向 hub.html) | 否(运维部署) |
pnpm build
# npm 发布:见下方「发布到 npm」
# Hub / CDN:把对应 dist 文件拷到静态服务器或对象存储要点:
hubUrl、namespace均必填,无默认值- 要互通的子系统必须配置完全相同的
hubUrl+namespace - Hub 部署域不写死;换环境换
hubUrl即可隔离
发布到 npm
一键脚本会校验包名、Git 干净工作区、npm 登录,再执行 build / test / pack 内容检查,通过后才 pnpm publish。npm 包仅含 SDK(dist/index.js + dist/index.d.ts);hub.html / hub.js 与 CDN 文件不会进包,需按上一节单独部署。
发版前请先手动改好 package.json 的 version(脚本不自动 bump)。
# 建议先 dry-run(构建 + 校验,不上传)
pnpm release -- --dry-run
# 交互确认后发布
pnpm release
# 跳过确认(CI / 明确发版时)
pnpm release -- --yes常用参数:
| 参数 | 含义 |
|------|------|
| --dry-run | 跑完检查与 pack 校验,不上传 |
| --yes | 跳过「确认发布」提示 |
| --skip-tests | 跳过 pnpm test(不推荐) |
| --allow-dirty | 允许未提交变更时发布(不推荐) |
常见失败:未 npm login、工作区有未提交改动、目标 version 已在 registry 存在。
API 概要
| API | 说明 |
|-----|------|
| publish / subscribe | 事件通道:在线投递,不持久、不重放 |
| setState / getState / watchState / deleteState | 状态通道:逻辑会话内持久;watchState 含首包快照 |
| probe() | 连通探测(加载 / 握手 / 跨 Tab) |
| destroy() | 销毁 iframe 与监听 |
状态仅在逻辑会话内有效(有存活参与者)。全部 Tab 离开或冷启动发现无存活 peer 时会清空该 namespace 会话态。
默认可信 Origin
默认信任:
*.kailinjt.com*.kailinesb.comlocalhost/127.0.0.1/[::1](任意端口,http/https)
trustedOrigins 追加到默认列表,不替换。hubUrl 自身 Origin 始终可信。
错误码(节选)
INVALID_CONFIG、HUB_LOAD_TIMEOUT、HUB_HANDSHAKE_FAILED、ORIGIN_REJECTED、CROSS_TAB_UNREACHABLE、STORAGE_PARTITIONED、PAYLOAD_NOT_SERIALIZABLE、STORAGE_QUOTA_EXCEEDED、HUB_VERSION_MISMATCH
通过 onError 与 Promise 拒绝暴露,避免静默失败。
安全注意
- 白名单内脚本均可读写总线,视为半公开通道,不要传递长期凭证
- Payload 须 JSON 可序列化;不设单条字节上限,但存储配额耗尽会报错
- 跨站嵌入 Hub 可能受浏览器存储分区影响,请用
probe()确认跨 Tab 可用;建议 Hub 与多数业务同站部署
非目标
跨设备同步、跨会话永久状态、业务后端通道、双 hubUrl 自动桥接、首版 RPC。
开发与验证
要求 Node.js ^24。
pnpm install
pnpm test # 纯函数单测 + 协议集成测(happy-dom)
pnpm build
pnpm dev # 双 port 真跨 Origin Playground
pnpm test:e2e # 本地 Playwright(不接 CI)Playground 端口(真跨 Origin)
| 地址 | 角色 | |------|------| | http://127.0.0.1:5173/?app=a | 子系统 A | | http://127.0.0.1:5174/?app=b | 子系统 B(不同 port → 不同 Origin,同主机 → 同站) | | http://127.0.0.1:5175/hub.html | Hub(默认 hubUrl) |
说明:若用 localhost 与 127.0.0.1 混搭,Hub 对其中一方是跨站第三方,易触发存储分区导致跨 Tab 不通;Playground 故意用同主机双 port 验证「真跨 Origin」且通道可用。
面板支持连接 / 事件 / 状态 / probe / destroy,以及故障注入(错误 hubUrl、不可序列化载荷、destroy 后调用)。
E2E
首次安装浏览器(走 npmmirror,仅 chromium,比官方源快):
pnpm playwright:install
# 等价于:
# PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries/playwright pnpm exec playwright install chromium
pnpm test:e2etest:e2e 会通过 Playwright webServer 拉起 pnpm dev(若端口已被占用且非 CI,可复用已有服务)。本仓库不将 E2E 作为 CI 门禁。
若镜像仍慢,可自设镜像:
PLAYWRIGHT_DOWNLOAD_HOST=https://your-mirror pnpm playwright:install