create-ax-trusted-plugin 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # create-ax-trusted-plugin
2
2
 
3
3
  可信(internal)插件**脚手架**:一条命令生成一个基于 `@ax-npm/host-trusted-sdk-v4` 的可信插件骨架
4
- (默认「形态一」:ESM 直出 `activate` + 自带 Vue + 自定义元素面板 + 调 `map.flyTo` + 遥测订阅;
4
+ (ESM 直出 `activate` + 自带 Vue + 自定义元素面板 + 调 `map.flyTo` + 遥测订阅;
5
5
  dev 走裸 `vite`,原生 sourcemap、无构建步)。
6
6
 
7
7
  > 脚手架本身已发**公网 npm**,生成这步**零配置**;生成出的工程才走私有源(`192.168.1.209` GitLab)拉
@@ -38,7 +38,7 @@ npm run dev
38
38
 
39
39
  ## 生成内容
40
40
  `template/` 经占位替换(`__ID__`/`__TITLE__`/`__ANCHOR__`)后落地:`src/{index.ts,Panel.vue,state.ts}`、
41
- `manifest.json`(trust:internal、entry:main.js)、`vite.config.ts`(形态一 lib 构建 + dev 市场源桥)、
41
+ `manifest.json`(trust:internal、entry:main.js)、`vite.config.ts`(一行调 `trustedPluginConfig` 预设)、
42
42
  `package.json`、`tsconfig.json`、`.npmrc`、`.gitignore`、`README.md`。
43
43
 
44
44
  ## 发布(维护者)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-ax-trusted-plugin",
3
- "version": "1.0.10",
4
- "description": "可信(internal)插件脚手架:一条命令生成一个基于 @ax-npm/host-trusted-sdk-v4 的可信插件骨架(默认形态一:ESM 直出 activate + 自带 Vue,dev 裸 vite 原生 sourcemap)。用法:npm create ax-trusted-plugin <id>。生成器本身无机密,公网可装;生成出的工程仍走私有源拉 @ax-npm/* 依赖。",
3
+ "version": "1.0.12",
4
+ "description": "可信(internal)插件脚手架:一条命令生成一个基于 @ax-npm/host-trusted-sdk-v4 的可信插件骨架(ESM 直出 activate + 自带 Vue,dev 裸 vite 原生 sourcemap)。用法:npm create ax-trusted-plugin <id>。生成器本身无机密,公网可装;生成出的工程仍走私有源拉 @ax-npm/* 依赖。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -1,7 +1,7 @@
1
1
  # __ID__
2
2
 
3
- 可信(internal)插件「形态一」:模块直接 `export activate`,壳 `import` 即用;进程内拿完整 `ctx`。
4
- Vue 打进本插件 bundle(与宿主/其它插件隔离)。由 `create-ax-trusted-plugin` 脚手架生成。
3
+ 可信(internal)插件:模块直接 `export activate`(ESM 直出),壳 `import` 即用;进程内拿完整 `ctx`。
4
+ Vue 打进本插件 bundle(经 Shadow DOM 自包含、与宿主/其它插件隔离)。由 `create-ax-trusted-plugin` 脚手架生成。
5
5
 
6
6
  ## 开发
7
7
  ```bash
@@ -13,8 +13,8 @@ npm run dev # concurrently: vite(:5174,市场源) + host-dev 真宿主(:5173)
13
13
  ```
14
14
  浏览器打开 `http://localhost:5173`,锚点出现「__TITLE__」面板。**改代码 → 刷新浏览器即生效**(原生 sourcemap)。
15
15
 
16
- > dev 走裸 `vite`:`vite.config.ts` `hostSourceBridge` 把单插件服务伪装成市场源,
17
- > `/<id>/main.js` 实时转译 `src/index.ts`。多插件并行各自 `vite --port 5175/5176/…`。
16
+ > dev 走裸 `vite`:`vite.config.ts` 一行调 `trustedPluginConfig` 预设,内含的市场源桥把单插件服务伪装成市场源,
17
+ > `/<id>/main.js` 实时转译 `src/index.ts`。多插件并行用 `trustedPluginConfig({ port: 5175 })`。
18
18
 
19
19
  ## 构建 / 上架
20
20
  ```bash
@@ -24,10 +24,7 @@ npm run build # → dist/main.js(+ main.js.map)
24
24
 
25
25
  ## 关键约定
26
26
  - 入口 `src/index.ts` 必须 `export function activate(ctx)`(可选 `elementTag`/`deactivate`);`manifest.entry`=`main.js`。
27
- - `vue({customElement:true})` 把样式注入 shadow root;Vue 自带打包,不与宿主共享。
27
+ - 预设的 `vue({customElement:true})` 把样式注入 shadow root;Vue 自带打包,不与宿主共享。
28
+ - 静态资源:直接 `import x from './x.png'`(无需 `?inline`),预设保证 dev/build 都内联成 data URI(可信插件跑在宿主 origin,普通 URL 会裂图);大图用 `new URL('./big.png', import.meta.url).href`。
28
29
  - 提供能力须命名空间化(`__ID__/...`)且在 `contributes.capabilities` 声明;消费(含**调自己提供的能力**)须在 `uses.capabilities` 声明——contributes 与 uses 是两道独立门,`execute` 一律过 uses 闸。
29
30
  - 插件间不互相 import,只走 `ctx.commands` / `ctx.events`。
30
-
31
- > 需要多个可信插件**共享单例** Vue / 跨边界共享响应式 store,或要省 Vue 体积时,才回退「形态二」
32
- > (Module Federation):`vite.config` 改用 `@originjs/vite-plugin-federation`、`manifest` 加 `mfExpose`、
33
- > dev 走 `vite build --watch` + 静态托管。详见 `@ax-npm/host-trusted-sdk-v4` 的 README 与《三角色开发方法.md》。
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
- "description": "可信(internal)插件「形态一」:ESM 直出 activate,壳 import 即用、Vue 自带打包(隔离)、拿完整 ctx。dev 走裸 vite(原生 sourcemap、无构建步)。只依赖 @ax-npm/host-trusted-sdk-v4。",
6
+ "description": "可信(internal)插件",
7
7
  "scripts": {
8
8
  "build": "vue-tsc --noEmit && vite build",
9
9
  "serve": "vite",
@@ -12,11 +12,14 @@
12
12
  "typecheck": "vue-tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@ax-npm/host-trusted-sdk-v4": "^1.0.5",
16
- "vue": "^3.4.0"
15
+ "@ax-npm/host-trusted-sdk-v4": "^1.0.12",
16
+ "@ax-npm/common-v4": "^1.0.0",
17
+ "@ax-npm/capability-kit-v4": "^1.0.9",
18
+ "vue": "^3.5.0",
19
+ "vue-i18n": "^11"
17
20
  },
18
21
  "devDependencies": {
19
- "@ax-npm/host-dev-v4": "^1.0.7",
22
+ "@ax-npm/host-dev-v4": "^1.0.15",
20
23
  "@vitejs/plugin-vue": "^5.0.0",
21
24
  "concurrently": "^9.0.0",
22
25
  "electron": "^39.0.0",
@@ -3,12 +3,6 @@
3
3
  // 能力接线在 activate(ctx) 里完成,经 window 事件桥回(自定义元素拿不到 ctx)。
4
4
  import { state } from './state';
5
5
 
6
- function ping() {
7
- window.dispatchEvent(new CustomEvent('__ID__:ping'));
8
- }
9
- function flyTo() {
10
- window.dispatchEvent(new CustomEvent('__ID__:flyto'));
11
- }
12
6
  </script>
13
7
 
14
8
  <template>
@@ -16,22 +10,12 @@ function flyTo() {
16
10
  <div class="title">__TITLE__</div>
17
11
  <p class="hint">可信插件</p>
18
12
 
19
- <div class="row">
20
- <button @click="ping">调用自有能力 ping</button>
21
- <span class="val">{{ state.lastPing || '—' }}</span>
22
- </div>
23
-
24
- <div class="row">
25
- <button @click="flyTo">map.flyTo 北京</button>
26
- <span class="val">{{ state.flyToNote || '—' }}</span>
27
- </div>
28
-
29
13
  <div class="tele">
30
- <div class="tele-h">遥测 telemetry:fcs.basic</div>
14
+ <div class="tele-h">遥测</div>
31
15
  <div v-if="state.telemetry" class="tele-b">
32
- lon {{ state.telemetry.lng ?? '—' }} ·
33
- lat {{ state.telemetry.lat ?? '—' }} ·
34
- alt {{ state.telemetry.alt ?? '—' }}
16
+ lon {{ state.tele.pos_lon ?? '—' }} ·
17
+ lat {{ state.tele.pos_lat ?? '—' }} ·
18
+ alt {{ state.tele.pos_alt ?? '—' }}
35
19
  </div>
36
20
  <div v-else class="tele-b muted">等待遥测…</div>
37
21
  </div>
@@ -0,0 +1,19 @@
1
+ import { createI18n } from 'vue-i18n';
2
+ import zhCN from './locales/zh-CN';
3
+ import enUS from './locales/en-US';
4
+
5
+ export const i18n = createI18n({
6
+ legacy: false,
7
+ locale: 'zh-CN',
8
+ fallbackLocale: 'zh-CN',
9
+ missingWarn: false,
10
+ fallbackWarn: false,
11
+ messages: {
12
+ 'zh-CN': zhCN,
13
+ 'en-US': enUS,
14
+ },
15
+ })
16
+
17
+ export function setLocale(lang: string) {
18
+ i18n.global.locale.value = lang as typeof i18n.global.locale.value
19
+ }
@@ -1,36 +1,41 @@
1
- // 可信插件入口「形态一」:本模块直接导出 activate/elementTag(manifest.entry → main.js)。
2
- // 宿主 loader `import(url)` 命中「直出 activate」分支,调 activate(ctx),据 elementTag +
3
- // manifest.component 挂自定义元素。(业务代码与形态二一致,只差打包/加载方式。)
4
- import { definePluginElement, type PluginCtx } from '@ax-npm/host-trusted-sdk-v4';
1
+ // 可信插件入口:本模块直接导出 activate/elementTag(manifest.entry → main.js)。
2
+ // 宿主 loader `import(url)` activate(ctx),据 elementTag + manifest.component 挂自定义元素。
5
3
  import Panel from './Panel.vue';
6
- import { state, type FcsBasic } from './state';
4
+ import { state } from './state';
5
+ import { i18n, setLocale } from './i18n'
6
+ import * as fcs from '@ax-npm/common-v4/fcs';
7
+ import { FCS_EVENTS, STAGE_EVENTS } from '@ax-npm/capability-kit-v4';
8
+ import { definePluginElement, type PluginCtx } from '@ax-npm/host-trusted-sdk-v4';
7
9
 
8
- export const elementTag = definePluginElement(Panel, { tag: 'plugin-__ID__' });
10
+ export const elementTag = definePluginElement(
11
+ Panel,
12
+ {
13
+ tag: 'plugin-__ID__',
14
+ configureApp: (app) => app.use(i18n),
15
+ }
16
+ );
9
17
 
10
18
  export function activate(ctx: PluginCtx) {
11
- // ① 提供能力:id 须命名空间化 + 在 manifest.contributes.capabilities 声明。
12
- // 注意:contributes(提供)与 uses(调用)是两道独立门——execute 走 uses 闸,**调自己
13
- // register 的能力也要在 manifest.uses.capabilities 声明**(见下方 ③ 的 __ID__/ping)。
14
- ctx.commands.register('__ID__/ping', async () => 'pong @ ' + new Date().toLocaleTimeString());
15
19
 
16
- // ② 订阅宿主遥测(广播)。
17
- ctx.events.on('telemetry:fcs.basic', (p) => {
18
- state.telemetry = p as FcsBasic;
19
- });
20
+ // 多语言切换
21
+ ctx.events.on(STAGE_EVENTS.LOCALE_CHANGED, (p) => {
22
+ console.log(p.lang)
23
+ setLocale(p.lang)
24
+ })
25
+
26
+ // 订阅宿主遥测(广播)
27
+ ctx.events.on(FCS_EVENTS.BASIC, (p) => {
28
+ console.log(p)
29
+ state.tele = p;
30
+ });
31
+ // 订阅飞机属性信息
32
+ ctx.events.on(FCS_EVENTS.INFO, (p) => {
33
+ console.log(p)
34
+ state.aircraftInfo = p
35
+ })
20
36
 
21
- // ③ Panel 是自定义元素,拿不到 ctx;经 window 事件把用户动作桥回 activate 作用域。
22
- window.addEventListener('__ID__:ping', async () => {
23
- state.lastPing = String(await ctx.commands.execute('__ID__/ping'));
24
- });
25
- window.addEventListener('__ID__:flyto', async () => {
26
- try {
27
- // 调宿主地图能力(需在 manifest.uses.capabilities 声明 map.flyTo)。
28
- await ctx.commands.execute('map.flyTo', 116.397, 39.908);
29
- state.flyToNote = '已飞至北京';
30
- } catch (e) {
31
- state.flyToNote = '失败:' + (e instanceof Error ? e.message : String(e));
32
- }
33
- });
37
+ // 类似c++的头文件定义,从common-v4中导出
38
+ console.log(fcs.PT_FCS_MR);
34
39
 
35
40
  return {
36
41
  elementTag,
@@ -0,0 +1,5 @@
1
+ const messages: Record<string, string> = {
2
+ "TEST": "TEST"
3
+ };
4
+
5
+ export default messages;
@@ -0,0 +1,5 @@
1
+ const messages: Record<string, string> = {
2
+ "TEST": "测试"
3
+ };
4
+
5
+ export default messages;
@@ -1,16 +1,23 @@
1
- // activate(ctx) 与 Panel 自定义元素之间的共享响应式状态。
2
- // 二者 import 同一模块 → 同一宿主 vue reactive(MF 共享,单例),activate 更新即触发 Panel 重渲染。
3
- import { reactive } from 'vue';
4
-
5
- export interface FcsBasic {
6
- lng?: number;
7
- lat?: number;
8
- alt?: number;
9
- [k: string]: unknown;
10
- }
11
-
12
- export const state = reactive({
13
- lastPing: '',
14
- telemetry: null as FcsBasic | null,
15
- flyToNote: '',
16
- });
1
+ // activate(ctx) 与 Panel 自定义元素之间的共享响应式状态。
2
+ // 二者 import 同一模块 → 插件自带的同一份 vue reactive(单例),activate 更新即触发 Panel 重渲染。
3
+ import {
4
+ FcsBasicTelemetry,
5
+ FcsModeTelemetry,
6
+ FcsNavposTelemetry,
7
+ AircraftInfo
8
+ } from '@ax-npm/capability-kit-v4';
9
+ import { reactive } from 'vue';
10
+
11
+ export interface FcsBasic {
12
+ lng?: number;
13
+ lat?: number;
14
+ alt?: number;
15
+ [k: string]: unknown;
16
+ }
17
+
18
+ export const state = reactive({
19
+ tele: null as FcsBasicTelemetry | null,
20
+ mode: null as FcsModeTelemetry | null,
21
+ navPos: null as FcsNavposTelemetry | null,
22
+ aircraftInfo: null as AircraftInfo | null,
23
+ });
@@ -1,86 +1,7 @@
1
- import { defineConfig } from 'vite';
2
- import vue from '@vitejs/plugin-vue';
3
- import { fileURLToPath, URL } from 'node:url';
4
- import { readFileSync } from 'node:fs';
1
+ // 可信插件「形态一」(ESM 直出 activate)构建 —— 全套配置收口在 SDK 预设里:
2
+ // Vue 自定义元素编译、dev 市场源桥、dev 资源内联(使 asset 朴素 import dev/build 一致)、
3
+ // lib 单文件产物、process.env 替换。详见 @ax-npm/host-trusted-sdk-v4/vite。
4
+ // 多插件并行调试时:trustedPluginConfig({ port: 5175 })。
5
+ import { trustedPluginConfig } from '@ax-npm/host-trusted-sdk-v4/vite';
5
6
 
6
- // 可信插件「形态一」(ESM 直出 activate)构建。与「形态二」(Module Federation 容器)对比:
7
- // - 形态一:本模块 import(url) 后**直接导出 activate/elementTag**,壳 loader 命中直出分支。
8
- // Vue 打进 bundle(自带依赖,与宿主/其它插件隔离 —— 宿主升级 Vue 波及不到本插件)。
9
- // - 形态二:打成 federation remoteEntry,运行时与宿主**共享单例** Vue/Pinia。
10
- // 只经 ctx 交互的内部插件用形态一**功能零损失**,且换来:dev 走裸 `vite`(实时转译、原生
11
- // sourcemap、无构建步),build 产单文件 `main.js`。仅当需要跨边界共享响应式 store / 省体积
12
- // 到单份 Vue 时才回退形态二(见 README 与《三角色开发方法.md》)。
13
- //
14
- // vue({ customElement: true }):SFC 以自定义元素模式编译,样式自动注入 shadow root,
15
- // 故无独立 CSS 产物,单个 main.js 即完整插件。
16
-
17
- const MANIFEST = JSON.parse(
18
- readFileSync(fileURLToPath(new URL('./manifest.json', import.meta.url)), 'utf-8'),
19
- ) as { id: string };
20
- const PLUGIN_ID = MANIFEST.id;
21
-
22
- // —— dev 桥:让「单插件 vite 服务」对外长得像宿主的插件市场源 ——
23
- // 宿主(LocalRegistry)会请求 /plugins.json、/<id>/manifest.json、/<id>/<entry>。
24
- // 这里:① /plugins.json = [{ id }];② 把 /<id>/* 重写回 /*(插件本体在根目录);
25
- // ③ manifest.entry 是 `main.js`(生产构建产物),dev 无此产物 → 把对它的请求
26
- // 顶替为 `src/index.ts`,由 vite 实时转译(原生 sourcemap、无构建步)。
27
- // 这样单跑 `vite` 即可被 harness/host-dev 当市场源加载,改代码刷新即生效。
28
- function hostSourceBridge() {
29
- return {
30
- name: 'host-source-bridge',
31
- configureServer(server: {
32
- middlewares: { use: (fn: (req: any, res: any, next: () => void) => void) => void };
33
- }) {
34
- server.middlewares.use((req, res, next) => {
35
- const url = (req.url || '').split('?')[0];
36
- if (url === '/plugins.json') {
37
- res.setHeader('content-type', 'application/json');
38
- res.setHeader('access-control-allow-origin', '*');
39
- res.end(JSON.stringify([{ id: PLUGIN_ID }]));
40
- return;
41
- }
42
- // /<id>/xxx → /xxx(去掉宿主加的 id 前缀)
43
- if (req.url === `/${PLUGIN_ID}` || req.url === `/${PLUGIN_ID}/`) {
44
- req.url = '/';
45
- } else if (req.url && req.url.startsWith(`/${PLUGIN_ID}/`)) {
46
- req.url = req.url.slice(PLUGIN_ID.length + 1);
47
- }
48
- // 形态一 dev:把 main.js 入口请求顶替为可实时转译的源文件。
49
- if ((req.url || '').split('?')[0] === '/main.js') req.url = '/src/index.ts';
50
- next();
51
- });
52
- },
53
- };
54
- }
55
-
56
- export default defineConfig({
57
- // 形态一 build 产物在真宿主(无 Node process)运行:替换 Vue 的 process.env.NODE_ENV,
58
- // 否则运行时报 ReferenceError: process is not defined。dev 模式 vite 本就注入,加此无副作用。
59
- define: { 'process.env.NODE_ENV': JSON.stringify('production') },
60
- plugins: [vue({ customElement: true }), hostSourceBridge()],
61
- server: {
62
- // 活跃集多插件并行时用 `vite --port 5175/5176/…` 覆盖,一份多源 plugins.json 列各端口。
63
- port: 5174,
64
- strictPort: true,
65
- // 宿主(:5180 / app://)跨源拉清单/manifest/入口模块,需放开 CORS。
66
- cors: { origin: '*' },
67
- },
68
- build: {
69
- target: 'esnext',
70
- outDir: 'dist',
71
- emptyOutDir: true,
72
- // 源码级调试可信插件产物:留 sourcemap、不混淆。
73
- sourcemap: true,
74
- minify: false,
75
- // library 模式:入口导出(activate/elementTag/deactivate)即模块导出,壳 import(url) 直出。
76
- lib: {
77
- entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)),
78
- formats: ['es'],
79
- fileName: () => 'main.js',
80
- },
81
- rollupOptions: {
82
- // 保住入口导出签名,别被当可执行 chunk 摇掉 activate。
83
- preserveEntrySignatures: 'strict',
84
- },
85
- },
86
- });
7
+ export default trustedPluginConfig();