@sl-theia/theia-socket-vue3
v0.1.2
Published
Vue3 adapter for Theia Socket
Downloads
310
Readme
@sl-theia/theia-socket-vue3
Vue3 版本的 Theia Socket 客户端封装。它基于 @sl-theia/socket-api-core,提供和 React 版本 @sl-theia/theia-socket-io-client 对齐的 socket 能力,并用 Vue3 的 provide/inject 与组合式 API 封装常用接入方式。
安装
npm install @sl-theia/theia-socket-vue3或使用 pnpm:
pnpm add @sl-theia/theia-socket-vue3本包要求项目中已安装 Vue3:
pnpm add vue快速开始
1. 在应用入口挂载 Provider
TheiaSocketProvider 会创建 TheiaSocketClient 实例,并通过 Vue 的依赖注入提供给子组件。所有使用 useSocket、useTheiaSocket、injectSocket 的组件都必须放在 Provider 子树中。
<template>
<TheiaSocketProvider :config="socketConfig">
<RouterView />
</TheiaSocketProvider>
</template>
<script setup lang="ts">
import {
TheiaSocketProvider,
type theiaSocketClientCfg,
} from '@sl-theia/theia-socket-vue3';
const socketConfig: theiaSocketClientCfg = {
userRole: 'WebController',
userGroup: 'default',
hostname: window.location.hostname,
port: '8070',
namespace: '/TheiaVis',
devTool: true,
webApiJson: {},
};
</script>2. 在页面中使用 useSocket
useSocket 是推荐用法。它会根据 name 创建当前页面或组件对应的实体 facade,返回的对象只暴露页面常用 socket 方法。
<template>
<button type="button" @click="queryApis">查询 API</button>
<button type="button" @click="emitNativeApi">调用 NativeAPI</button>
</template>
<script setup lang="ts">
import { onBeforeUnmount } from 'vue';
import { useSocket } from '@sl-theia/theia-socket-vue3';
const socket = useSocket({ name: 'DashboardPage' });
const offConnect = socket.onConnect((msg) => {
console.log('socket connected:', msg);
});
const offQueryResponse = socket.onQueryResponse((msg) => {
console.log('query response:', msg);
});
function queryApis() {
socket.query();
}
function emitNativeApi() {
socket.theiaEmit({
Entity: 'BP_PointManager_2',
NativeAPI: {
API_ShowPoint: {
Description: 'Show point',
Parms: {
show: true,
type: '',
},
},
},
});
}
onBeforeUnmount(() => {
offConnect();
offQueryResponse();
});
</script>3. 注册 WebAPI
WebAPI 是 Web 侧暴露给 Theia/Native 侧调用的 API。注册时建议在组件卸载时注销,避免页面重新进入后重复注册。
<script setup lang="ts">
import { onBeforeUnmount, ref } from 'vue';
import { useSocket } from '@sl-theia/theia-socket-vue3';
type SetCountParams = {
count?: number;
};
const count = ref(0);
const socket = useSocket({ name: 'CounterPage' });
function API_SET_COUNT(params: SetCountParams = {}) {
count.value += Number(params.count || 0);
}
socket.registerAPI('API_SET_COUNT', API_SET_COUNT);
onBeforeUnmount(() => {
socket.unregisterAPI('API_SET_COUNT');
});
</script>调用 WebAPI 时,Entity 要和注册 API 时的实体名一致:
socket.theiaEmit({
Entity: 'CounterPage',
WebAPI: {
API_SET_COUNT: {
Description: 'Update counter',
Parms: {
count: 1,
},
},
},
});在 vis/umi Vue3 项目中使用
如果项目通过 @sl-theia/vis 和 @umijs/preset-vue 接入,可以直接在 .umirc.ts 中开启 theiaSocket。插件会识别 Vue3 项目,并自动选择 @sl-theia/theia-socket-vue3。
import { defineConfig } from '@sl-theia/vis';
export default defineConfig({
presets: ['@umijs/preset-vue'],
vue: {},
theiaSocket: {
userRole: 'webUI',
userGroup: 'default',
hostname: '127.0.0.1',
port: '8070',
namespace: '/TheiaVis',
devTool: true,
autoRegister: {},
},
});开启插件后,可以从 umi 导入运行时生成的 socket 工具:
<script setup lang="ts">
import { onBeforeUnmount } from 'vue';
// 由 theiaSocket 运行时插件生成。
import { socketEmiter, useSocket } from 'umi';
const socket = useSocket({ name: 'VueSocketPage' });
function API_SET_COUNT(params: { count?: number } = {}) {
console.log('receive count:', params.count);
}
socket.registerAPI('API_SET_COUNT', API_SET_COUNT);
function emitApiSetCount() {
socketEmiter.theiaEmit({
Entity: 'VueSocketPage',
WebAPI: {
API_SET_COUNT: {
Parms: {
count: 1,
},
},
},
});
}
onBeforeUnmount(() => {
socket.unregisterAPI('API_SET_COUNT');
});
</script>API
TheiaSocketProvider
Provider 组件,用于创建并注入 socket 实例。
| 属性 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| config | theiaSocketClientCfg | 是 | socket 连接配置 |
config 常用字段:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| hostname | string | 否 | window.location.hostname 或 127.0.0.1 | socket 服务地址 |
| port | string | 否 | 8070 | socket 服务端口 |
| namespace | string | 否 | /TheiaVis | socket 命名空间 |
| userRole | string | 是 | - | 当前 Web 客户端注册角色 |
| userGroup | string | 否 | - | 当前 Web 客户端分组 |
| devTool | boolean | 否 | false | 是否开启调试工具 |
| webApiJson | object | 否 | {} | WebAPI 注册信息,通常由 vis 插件生成 |
useSocket
function useSocket(config?: { name?: string }): SocketFacade;推荐在业务页面和组件中使用。name 会作为当前实体名参与 WebAPI 注册和消息发送。
const socket = useSocket({ name: 'HomePage' });如果不传 name,运行时会输出错误日志,匿名函数场景下建议显式传入。
useTheiaSocket
function useTheiaSocket(): TheiaSocketClient;返回完整的 TheiaSocketClient 实例,适合需要访问底层 client、entities 或 socket 实例的高级场景。
const client = useTheiaSocket();
client.query();injectSocket
function injectSocket(config?: { name?: string }): (WrappedComponent: Component) => Component;injectSocket 会把 socket 注入到被包装组件的 props 中,主要用于需要沿用 React 版本高阶组件风格的场景。
import { defineComponent, type PropType } from 'vue';
import {
injectSocket,
type SocketFacade,
} from '@sl-theia/theia-socket-vue3';
const RawPanel = defineComponent({
name: 'RawPanel',
props: {
socket: {
type: Object as PropType<SocketFacade>,
required: true,
},
},
setup(props) {
props.socket.query();
return () => null;
},
});
export default injectSocket({ name: 'RawPanel' })(RawPanel);createTheiaSocket
function createTheiaSocket(config: theiaSocketClientCfg): TheiaSocketClient;手动创建 socket client。一般情况下优先使用 TheiaSocketProvider,只有在运行时工具、测试或非组件环境中才需要直接创建。
import { createTheiaSocket } from '@sl-theia/theia-socket-vue3';
const socket = createTheiaSocket({
userRole: 'manual-client',
webApiJson: {},
});provideTheiaSocket
function provideTheiaSocket(config: theiaSocketClientCfg): TheiaSocketClient;在自定义 Provider 中创建并注入 socket。
import { defineComponent, h } from 'vue';
import { provideTheiaSocket } from '@sl-theia/theia-socket-vue3';
export default defineComponent({
setup(_, { slots }) {
const socket = provideTheiaSocket({
userRole: 'custom-provider',
webApiJson: {},
});
return () => slots.default?.();
},
});SocketFacade 方法
useSocket 和 injectSocket 返回的 socket 都是 SocketFacade。
| 方法 | 说明 | 返回值 |
| --- | --- | --- |
| registerAPI(apiName, callback) | 注册当前实体的 WebAPI | void |
| unregisterAPI(apiName) | 注销当前实体的 WebAPI,支持字符串或字符串数组 | void |
| query(entityName?) | 查询已注册的实体和 API 信息 | void |
| theiaEmit(msg) | 发送 Msg 消息,可调用 NativeAPI 或 WebAPI | void |
| theiaOn(callback) | 监听 Msg 消息 | () => void |
| theiaOnce(callback) | 只监听一次 Msg 消息 | void |
| onConnect(callback) | 监听客户端连接广播 | () => void |
| onDisconnect(callback) | 监听客户端断开广播 | () => void |
| onQueryResponse(callback) | 监听 query 的响应 | () => void |
| onNativeAPIResponse(callback) | 监听 NativeAPI 调用响应 | () => void |
| onNativeAPIResponseAsync(callback) | 监听 NativeAPI 异步响应 | () => void |
| onWebAPIResponse(callback) | 监听 WebAPI 调用响应 | () => void |
| on(eventName, callback) | 监听 socket 原生事件 | () => void |
事件监听方法通常会返回取消监听函数,建议在 onBeforeUnmount 中执行。
const offMsg = socket.theiaOn((msg) => {
console.log('Msg:', msg);
});
onBeforeUnmount(() => {
offMsg();
});消息格式示例
调用 NativeAPI
socket.theiaEmit({
Entity: 'BP_PointManager_2',
NativeAPI: {
API_ShowPoint: {
Description: 'Show point',
Parms: {
show: true,
type: '',
},
},
},
});调用 WebAPI
socket.theiaEmit({
Entity: 'CounterPage',
WebAPI: {
API_SET_COUNT: {
Description: 'Set count',
Parms: {
count: 10,
},
},
},
});监听调用结果
const offNativeResponse = socket.onNativeAPIResponse((msg) => {
console.log('NativeAPI response:', msg);
});
const offWebResponse = socket.onWebAPIResponse((msg) => {
console.log('WebAPI response:', msg);
});
onBeforeUnmount(() => {
offNativeResponse();
offWebResponse();
});导出内容
export {
Entity,
Provider,
SocketContext,
TheiaSocketClient,
TheiaSocketProvider,
createSocketFacade,
createTheiaSocket,
injectSocket,
provideTheiaSocket,
socketKey,
useSocket,
useTheiaSocket,
};
export type {
EntityConfig,
InjectSocketProps,
SocketFacade,
injectSocketProps,
theiaSocketClientCfg,
};Provider 是 TheiaSocketProvider 的别名,SocketContext 是 socketKey 的别名,用于对齐 React 版本 API 命名。
打包产物
包内同时提供 CJS、ESM 和独立类型声明:
{
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/types/index.d.ts"
}发布文件只包含运行时 JS、类型声明,以及用于导出边界和模块类型声明的 package.json 文件,不会发布 .map 文件。
常见问题
useSocket 报错 TheiaSocketClient has not been provided.
说明当前组件没有被 TheiaSocketProvider 包裹。请把 Provider 放在应用入口或当前页面父级。
页面重复进入后 WebAPI 被重复调用.
通常是注册后没有注销。请在 onBeforeUnmount 中调用 unregisterAPI,并清理事件监听返回的 off 函数。
Umi/vis 项目里应该从哪里导入 useSocket.
开启 theiaSocket 插件后,业务页面推荐从 umi 导入:
import { socketEmiter, useSocket } from 'umi';独立 Vue3 项目或非 Umi 项目从本包导入:
import { TheiaSocketProvider, useSocket } from '@sl-theia/theia-socket-vue3';