web-extend-plugin-vue2 0.2.2 → 0.2.3

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,67 +1,25 @@
1
1
  # web-extend-plugin-vue2
2
2
 
3
- 面向 **Vue 2.6+** / **Vue Router 3.x** 宿主的 **Web 前端扩展插件**运行时。在浏览器中拉取插件清单、加载入口脚本、注入 **`hostApi`**(路由 / 菜单 / 扩展点 / 受控请求桥等),并提供 **`ExtensionPoint`** 在布局中挂载插件视图。与后端清单服务、静态资源目录约定配套使用(如 `extend-plugin-framework` 中的 `plugin-web-starter`)。
3
+ 面向 **Vue 2.6+** **Vue Router 3** Web 插件运行时:浏览器中拉取**插件清单**、加载入口脚本、执行 `activator(hostApi)`,并提供 **`ExtensionPoint`**、菜单/路由注册表与受控 **`getBridge()`**。发布物为预构建的 **`dist/`**(CJS/ESM),类型见根目录 **`index.d.ts`**。
4
4
 
5
- ## 包形态与兼容性
5
+ **Peer:`vue` ^2.6.14 \<3,`vue-router` ^3.2 \<4。**
6
6
 
7
- - **发布入口为预构建的 `dist/`(CJS + ESM)**,不含 `.vue` 源码、**运行时无 `import.meta` 语法**,避免 Vue CLI / Webpack 4 宿主再配 `transpileDependencies`、Babel `import.meta` 补丁等与版本强耦合的改动。包内存在模块顶层初始化(如 `registries` 的 `Vue.observable`),**不**声明 `sideEffects: false`,以免宿主打包器误裁剪。
8
- - **Webpack 4 / Vue CLI 4**:`package.json` **不**再声明 `module` 字段,默认解析 **`main` → `dist/index.cjs`**,由 Webpack 正常注入 `require`,避免误选 `index.mjs` 后在浏览器中出现 `require is not defined`。支持 `package.json` **`exports`** 的 Webpack 5、Vite、Rollup 等仍通过 **`import` 条件**使用 `dist/index.mjs`。
9
- - **peer**:`vue` `>=2.6.14 <3`,`vue-router` `>=3.2.0 <4`(与 2.6 / 2.7 主流栈对齐,减轻版本地狱)。
10
- - **Vite 宿主**:通过 `env: import.meta.env` 或 `setWebExtendPluginEnv(import.meta.env)` 注入环境,即可读取文档中的 `VITE_*` 键。
11
- - **TypeScript**:根目录 `index.d.ts`,`package.json` 的 `types` 与 `exports.types` 已配置;宿主可结合 `WebExtendPluginVue2` 做补全。
7
+ ---
12
8
 
13
- ## 安装
9
+ ## 如何使用
14
10
 
15
- ```bash
16
- npm add web-extend-plugin-vue2 vue@^2.7 vue-router@^3.6
17
- ```
18
-
19
- (Vue 2.6 项目请将 `vue` / `vue-template-compiler` 与 `vue-router` 保持与现有工程一致即可。)
20
-
21
- ## 稳定对外 API(推荐先读)
22
-
23
- 本包在语义化版本内保证以下入口稳定:
24
-
25
- | 方式 | 说明 |
26
- |------|------|
27
- | **`WebExtendPluginVue2`** | 根命名空间对象(`Object.freeze`),按领域分组:`install`、`runtime`、`host`、`config`、`constants`、`components`、`presets`。适合在 IDE 里点选浏览能力边界。 |
28
- | **具名导出** | 与命名空间内函数同一引用,便于 tree-shaking 与按需 `import { x } from '...'`。 |
29
- | **`index.d.ts`** | TypeScript / JSDoc 补全;`package.json` 的 `types` / `exports.types` 已指向根目录 `index.d.ts`。 |
30
-
31
- **`WebExtendPluginVue2.presets`**:各预设为带 `id` / `description` 的聚合对象(当前含 **`vueCliAxios`**),方法名见下表:
32
-
33
- | 预设 | 主要方法 | 作用 |
34
- |------|----------|------|
35
- | `presets.vueCliAxios` | `createInstallOptions({ request }, extra?)` | 生成 `install` 所需 options(清单走宿主 axios) |
36
- | 同上 | `manifestPathForApiBase` / `unwrapManifestBody` | 自定义 `fetchManifest` 时可复用 |
37
- | `runtime` | `wrapManifestFetchWithCache` 等 | 清单拉取缓存与中间件组合(见「清单拉取扩展」) |
38
-
39
- 源码中 **`src/public.js`** 为对外清单的唯一聚合点;新增稳定 API 时应同步更新该文件、`index.d.ts` 与本节。
40
-
41
- ## 推荐:一键接入
11
+ **一键接入**(注册全局 `ExtensionPoint` 并异步拉清单):
42
12
 
43
13
  ```js
44
- import Vue from 'vue'
45
- import router from './router'
46
14
  import { installWebExtendPluginVue2 } from 'web-extend-plugin-vue2'
47
15
 
48
- // Vue CLI:manifestBase 常与 VUE_APP_* 接口前缀一致
49
16
  installWebExtendPluginVue2(Vue, router, {
50
- manifestBase: process.env.VUE_APP_BASE_API
17
+ manifestBase: '/fp-api', // 或与网关一致的前缀
18
+ env: import.meta.env // Vite:可选,便于读取 VITE_*
51
19
  }).catch(console.warn)
52
-
53
- // Vite:传入 env 以支持 VITE_* 环境变量
54
- // installWebExtendPluginVue2(Vue, router, {
55
- // env: import.meta.env,
56
- // manifestBase: import.meta.env.VITE_FRONTEND_PLUGIN_BASE
57
- // }).catch(console.warn)
58
20
  ```
59
21
 
60
- ### Vue CLI + 统一 `request`(如若依,推荐)
61
-
62
- 无需在宿主项目里再建 `webExtendPlugin.js`:把清单请求交给与业务相同的 axios 实例即可。
63
-
64
- **具名导入:**
22
+ **Vue CLI + 已有 axios `request`**(清单走宿主登录态):
65
23
 
66
24
  ```js
67
25
  import { installWebExtendPluginVue2, createVueCliAxiosInstallOptions } from 'web-extend-plugin-vue2'
@@ -70,27 +28,9 @@ import request from '@/utils/request'
70
28
  installWebExtendPluginVue2(Vue, router, createVueCliAxiosInstallOptions({ request })).catch(console.warn)
71
29
  ```
72
30
 
73
- **命名空间(与上等价,对外边界更清晰):**
31
+ **按需组合**(自行注册 `ExtensionPoint`、控制引导时机):
74
32
 
75
33
  ```js
76
- import { WebExtendPluginVue2 } from 'web-extend-plugin-vue2'
77
- import request from '@/utils/request'
78
-
79
- WebExtendPluginVue2.install(
80
- Vue,
81
- router,
82
- WebExtendPluginVue2.presets.vueCliAxios.createInstallOptions({ request })
83
- ).catch(console.warn)
84
- ```
85
-
86
- 会默认使用 `process.env.VUE_APP_BASE_API` 作为 `manifestBase`,`fetchManifest` 走 `request`,并兼容 `{ code, data: { plugins } }` 式响应。可选环境变量 `VUE_APP_WEB_PLUGIN_MANIFEST_PATH` 覆盖清单路径段。需要额外字段时传入第二参数合并,例如 `createInstallOptions({ request }, { manifestListPath: '/api/my-list' })`。
87
-
88
- 布局中使用:`<ExtensionPoint point-id="..." />`(已由 `installWebExtendPluginVue2` 全局注册)。
89
-
90
- ## 进阶:按需组合
91
-
92
- ```js
93
- import Vue from 'vue'
94
34
  import {
95
35
  bootstrapPlugins,
96
36
  createHostApi,
@@ -99,154 +39,67 @@ import {
99
39
  } from 'web-extend-plugin-vue2'
100
40
 
101
41
  Vue.component('ExtensionPoint', ExtensionPoint)
102
-
103
- const runtime = resolveRuntimeOptions({
104
- // 按需覆盖,见 defaultWebExtendPluginRuntime
105
- })
106
-
42
+ const runtime = resolveRuntimeOptions({ manifestBase: '/fp-api' })
107
43
  bootstrapPlugins(router, (id, r, kit) => createHostApi(id, r, kit), runtime).catch(console.warn)
108
44
  ```
109
45
 
110
- 清单请求 URL 为 **`manifestBase` + `manifestListPath`**(默认 `/fp-api` + `/api/frontend-plugins`)。工厂请使用 **`(id, r, kit) => createHostApi(id, r, kit)`**,以便 bridge 白名单等配置生效。
111
-
112
- ## 配置与默认值
113
-
114
- **优先级(后者覆盖前者)**:`resolveRuntimeOptions` 传入对象中的显式字段 → **注入环境**(`setWebExtendPluginEnv` / `globalThis.__WEP_ENV__` / `install` 的 `env`)→ `process.env`(Webpack `DefinePlugin` 等)→ **`defaultWebExtendPluginRuntime`**。
46
+ 清单请求地址:**`manifestBase` + `manifestListPath`**(默认路径段为 `/api/frontend-plugins`)。工厂请使用 **`(id, r, kit) => createHostApi(id, r, kit)`**,以便 `bridgeAllowedPathPrefixes` 等传入 `hostApi`。
115
47
 
116
- **环境变量命名**:文档以 **`VITE_*`** 为准;每个键都有等价的 **`PLUGIN_*`**(把前缀 `VITE_` 换成 `PLUGIN_`)。在 **Webpack** 中可将同名键通过 `DefinePlugin` 挂到 `process.env`;在 **Vite** 中请使用 `installWebExtendPluginVue2(..., { env: import.meta.env })` 或先调用 `setWebExtendPluginEnv(import.meta.env)`,并在 `defineConfig` 中配置 `envPrefix`(如含 `PLUGIN_`)以便变量进入 `import.meta.env`。
48
+ ---
117
49
 
118
- **`isDev`**:未在对象里写 `isDev` 时,先判断注入环境中的 `DEV === true`,否则使用 `process.env.NODE_ENV === 'development'`。
50
+ ## 主要配置(`resolveRuntimeOptions` / `install` 同源字段)
119
51
 
120
- ### `resolveRuntimeOptions` / `defaultWebExtendPluginRuntime` 字段
121
-
122
- | 字段 | 类型 | 默认值 | 作用 |
123
- |------|------|--------|------|
124
- | `manifestBase` | `string` | `/fp-api` | 清单与代理前缀(不含尾部 `/`),与后端 context-path 对齐 |
125
- | `manifestListPath` | `string` | `/api/frontend-plugins` | 清单接口路径(以 `/` 开头),完整请求 URL = `manifestBase` + `manifestListPath` |
126
- | `manifestFetchCredentials` | `string` | `include` | 拉清单时 `fetch` 的 `credentials`:`include` / `same-origin` / `omit` |
127
- | `isDev` | `boolean` | 见上 | 是否开发模式;影响隐式 dev 映射、SSE 等 |
128
- | `webPluginDevOrigin` | `string` | `''` | 插件 dev 服务 origin,如 `http://localhost:5188`;空则不做隐式 dev ping |
129
- | `webPluginDevIds` | `string` | `''` | 逗号分隔插件 id;有值且 ping 成功时生成隐式 dev 入口映射 |
130
- | `webPluginDevMapJson` | `string` | `''` | JSON 字符串:`{ "插件id": "完整入口URL" }`,与隐式映射合并,**显式覆盖同 id** |
131
- | `webPluginDevEntryPath` | `string` | `/src/plugin-entry.js` | 隐式映射里各 id 对应的入口路径(相对 `webPluginDevOrigin`);Webpack dev 可改为 `/dist/main.js` 等 |
132
- | `devPingPath` | `string` | `/__web_plugin_dev_ping` | 拼在 `webPluginDevOrigin` 后的存活探测路径 |
133
- | `devReloadSsePath` | `string` | `/__web_plugin_reload_stream` | 插件 dev 热更新 SSE 路径(相对各 dev 入口的 origin) |
134
- | `devPingTimeoutMs` | `number` | `500` | dev ping 超时(毫秒) |
135
- | `defaultImplicitDevPluginIds` | `string[]` | `[]` | 未配置 `webPluginDevIds` 且未设对应 env 时,隐式 dev 使用的 id 列表 |
136
- | `allowedScriptHosts` | `string[]` | `localhost`、`127.0.0.1`、`::1` | 允许加载插件脚本(`<script>` / 动态 `import`)的主机名 |
137
- | `bridgeAllowedPathPrefixes` | `string[]` | `['/api/']` | `hostApi.getBridge().request(path)` 允许的 URL 前缀(须以 `/` 开头) |
138
- | `bootstrapSummary` | `boolean` \| `undefined` | `undefined` | 是否打印 bootstrap 结束摘要;`undefined` 时由 `VITE_PLUGINS_BOOTSTRAP_SUMMARY` 或开发模式决定 |
139
- | `fetchManifest` | `function` \| `undefined` | `undefined` | 宿主自定义清单请求。签名:`(ctx) => Promise<{ ok, data?, status?, error? }>`,其中 `ctx` 为 `{ manifestUrl, credentials }`。未传时内部使用 `fetch(manifestUrl, { credentials })`。适合与 **axios / 统一 request**、Token、RuoYi 式 `{ code, data }` 包装等对齐。 |
140
-
141
- ### 宿主接管清单请求(推荐与后端封装对齐)
52
+ | 字段 | 作用 |
53
+ |------|------|
54
+ | `manifestBase` | 清单服务 URL 前缀(无尾 `/`),默认 `/fp-api` |
55
+ | `manifestListPath` | 清单路径段(以 `/` 开头),拼在 `manifestBase` 后 |
56
+ | `manifestFetchCredentials` | 拉清单时 `fetch` `credentials`,默认 `include` |
57
+ | `fetchManifest` | 自定义清单请求 `(ctx) => Promise<{ ok, data?, error? }>` |
58
+ | `bridgeAllowedPathPrefixes` | `hostApi.getBridge().request(path)` 允许的 path 前缀 |
59
+ | `allowedScriptHosts` | 允许加载插件脚本的主机名白名单 |
60
+ | `isDev` / `webPluginDevOrigin` | 开发态隐式 dev 入口与 SSE,见类型定义 |
61
+ | `pluginRoutesParentName` | 插件子路由挂到的**已有**命名父路由 |
62
+ | `adaptRouteDeclarations` / `transformRoutes` / `interceptRegisterRoutes` | 路由 PRD 适配与宿主扩展流水线 |
142
63
 
143
- 默认由运行时直接 `fetch` 拼好的 `manifestUrl`。若清单接口已与宿主登录态、拦截器、错误码封装在一起,建议传入 **`fetchManifest`**,在函数内调用宿主的 `request` / `axios`,并自行把响应 **解包** 为与清单服务一致的 JSON 形态(含 `plugins` 数组,可选 `hostPluginApiVersion`)。
64
+ 环境:Vite 可在入口调用 **`setWebExtendPluginEnv(import.meta.env)`**,或在 options 里传 **`env`**。键名支持 **`VITE_*`** 与等价 **`PLUGIN_*`**(实现内会解析)。
144
65
 
145
- 需要「先走宿主 HTTP 栈再回退到裸 `fetch`」时,可引入导出的 **`defaultFetchWebPluginManifest`** 做委托。
66
+ ---
146
67
 
147
- ### 清单拉取扩展(缓存 / 埋点,第三方规范用法)
68
+ ## 功能示例)
148
69
 
149
- **契约**:`fetchManifest(ctx)` `Promise<{ ok, data?, status?, error? }>`。任何扩展都应**包装**该函数后再传入 `install` / `resolveRuntimeOptions`,**不修改**包内 `bootstrapPlugins` 源码。
70
+ **布局里开槽**(插件通过 `hostApi.registerSlotComponents('your.point.id', [...])` 注入组件):
150
71
 
151
- 1. **缓存(内置、零额外依赖)**
152
- - **`wrapManifestFetchWithCache(inner, { ttlMs, storage?, ... })`**:常用快捷方式。
153
- - **`manifestFetchCacheMiddleware(options)`** + **`composeManifestFetch(inner, ...middlewares)`**:与自定义中间件组合。
72
+ ```vue
73
+ <ExtensionPoint point-id="app.toolbar.demo" />
74
+ ```
154
75
 
155
- 2. **示例:在预设 `fetchManifest` 外包一层内存缓存(5 分钟)**
76
+ **读全局菜单**(插件 `registerMenuItems` 写入响应式表):
156
77
 
157
78
  ```js
158
- import { WebExtendPluginVue2 } from 'web-extend-plugin-vue2'
159
- import request from '@/utils/request'
160
-
161
- const base = WebExtendPluginVue2.presets.vueCliAxios.createInstallOptions({ request })
162
-
163
- WebExtendPluginVue2.install(Vue, router, {
164
- ...base,
165
- fetchManifest: WebExtendPluginVue2.runtime.wrapManifestFetchWithCache(base.fetchManifest, {
166
- ttlMs: 5 * 60 * 1000,
167
- storage: 'memory',
168
- maxEntries: 20
169
- })
170
- }).catch(console.warn)
79
+ import { registries } from 'web-extend-plugin-vue2'
80
+ // computed: { menus() { return registries.menus } }
171
81
  ```
172
82
 
173
- 3. **`storage: 'session' | 'local'`** 时使用 `JSON.stringify` 落盘,请确保 `data` 可序列化;键前缀默认 `wep.manifestFetch.v1`,可通过 `storageKeyPrefix` 覆盖。
174
-
175
- 4. **自定义中间件**(如埋点、重试):实现 `(next) => async (ctx) => { /* 前 */ const r = await next(ctx); /* 后 */ return r }`,再用 **`composeManifestFetch(inner, mw1, mw2)`** 从外到内包裹(最外层先执行)。
176
-
177
- 对应 API 挂在 **`WebExtendPluginVue2.runtime`**,与具名导出 **`wrapManifestFetchWithCache` / `manifestFetchCacheMiddleware` / `composeManifestFetch`** 为同一实现。
178
-
179
- ### 环境变量一览(`PLUGIN_*` 同名等价)
180
-
181
- | 环境变量(`PLUGIN_…` 同理) | 作用 |
182
- |-----------------------------|------|
183
- | `VITE_FRONTEND_PLUGIN_BASE` | `manifestBase` |
184
- | `VITE_WEB_PLUGIN_MANIFEST_PATH` | `manifestListPath` |
185
- | `VITE_WEB_PLUGIN_MANIFEST_CREDENTIALS` | `manifestFetchCredentials`(仅上述三取值) |
186
- | `VITE_WEB_PLUGIN_DEV_ORIGIN` | `webPluginDevOrigin` |
187
- | `VITE_WEB_PLUGIN_DEV_IDS` | `webPluginDevIds`(逗号分隔) |
188
- | `VITE_WEB_PLUGIN_DEV_MAP` | `webPluginDevMapJson` |
189
- | `VITE_WEB_PLUGIN_DEV_ENTRY` | `webPluginDevEntryPath` |
190
- | `VITE_WEB_PLUGIN_DEV_PING_PATH` | `devPingPath` |
191
- | `VITE_WEB_PLUGIN_DEV_SSE_PATH` | `devReloadSsePath` |
192
- | `VITE_WEB_PLUGIN_DEV_PING_TIMEOUT_MS` | `devPingTimeoutMs`(正整数) |
193
- | `VITE_WEB_PLUGIN_IMPLICIT_DEV_IDS` | 逗号分隔 → `defaultImplicitDevPluginIds`(仅当未在对象里传数组时) |
194
- | `VITE_WEB_PLUGIN_ALLOWED_SCRIPT_HOSTS` | 逗号分隔主机名 → `allowedScriptHosts` |
195
- | `VITE_WEB_PLUGIN_BRIDGE_PREFIXES` | 逗号分隔路径前缀 → `bridgeAllowedPathPrefixes` |
196
- | `VITE_PLUGINS_BOOTSTRAP_SUMMARY` | `0`/`false` 关闭摘要;`1`/`true` 强制开启;未设时在开发模式默认开启 |
197
-
198
- ### 其它导出
83
+ **路由扩展(宿主)**:在 `resolveRuntimeOptions` 里提供 `transformRoutes` `adaptRouteDeclarations`,插件在 `activator` 第二个参数中取冻结的 **`pluginRecord`**(可含清单里的 `routeDeclarations`)。
199
84
 
200
- 完整列表见 **`WebExtendPluginVue2`** 各分组与 **`src/public.js`**。常见补充说明:
201
-
202
- - **`setWebExtendPluginEnv(env)`**:Vite 入口显式注入与 `import.meta.env` 同形态对象。
203
- - **`HOST_PLUGIN_API_VERSION`**:宿主与插件约定的 API 版本字符串(与后端清单字段对齐),非 `resolveRuntimeOptions` 配置项。
204
- - **`defaultFetchWebPluginManifest(ctx)`**:内置清单 `fetch` 实现,供宿主在自定义 `fetchManifest` 中按需包装或回退。
205
- - **`presetVueCliAxios`**:Vue CLI + axios 预设聚合(`createInstallOptions` 等与具名导出等价)。
206
-
207
- ## 发布与本地开发
208
-
209
- - **npm 发布的包**:`prepublishOnly` 会执行 `npm run build && npm test`,打包容器内已含 **`dist/`**;宿主安装时**不会**再跑构建,也**不需要**本包的 Rollup(避免依赖安装阶段因缺少 devDependencies 而失败)。
210
- - **从仓库 / `file:` 路径引用**:请先在包目录执行 **`npm install && npm run build`**,保证存在 `dist/`,或将 **`dist/` 纳入版本库**后再被其它项目引用。
211
-
212
- ## 卸载
85
+ **卸载插件**:
213
86
 
214
87
  ```js
215
88
  import { disposeWebPlugin } from 'web-extend-plugin-vue2'
216
-
217
- disposeWebPlugin('your.plugin.id')
89
+ disposeWebPlugin('com.your.plugin.id')
218
90
  ```
219
91
 
220
- Vue Router 3 无公开 `removeRoute`,动态路由卸载后可能需整页刷新。
221
-
222
- ## 版本纪要
223
-
224
- ### 0.2.2
225
-
226
- - **`composeManifestFetch`** / **`manifestFetchCacheMiddleware`** / **`wrapManifestFetchWithCache`**:清单 `fetchManifest` 的中间件组合与可选缓存(memory / sessionStorage / localStorage),无额外 npm 依赖。
227
-
228
- ### 0.2.4
229
-
230
- - **`WebExtendPluginVue2`**:根命名空间对象,对外能力按 `install` / `runtime` / `host` / `config` / `constants` / `components` / `presets` 分组。
231
- - **`presetVueCliAxios`**:预设聚合对象(`id`、`description`、与具名函数等价的方法),源码位于 `src/presets/vue-cli-axios.js`。
232
- - **`src/public.js`**:稳定具名导出的唯一聚合点;根目录 **`index.d.ts`** 与 `package.json` 的 `types` / `exports.types` 供 TS 补全。
233
-
234
- ### 0.2.3
235
-
236
- - **`createVueCliAxiosInstallOptions`**:Vue CLI + 宿主 `request` 一键选项,避免宿主再维护大段清单/bridge 封装代码。
92
+ ---
237
93
 
238
- ### 0.2.2
94
+ ## API 浏览
239
95
 
240
- - **`fetchManifest`**:`resolveRuntimeOptions` / `installWebExtendPluginVue2` 支持宿主注入清单拉取函数,便于与 axios、统一 request、鉴权及业务响应包装对齐。
241
- - **`defaultFetchWebPluginManifest`**:导出内置 `fetch` 实现,便于宿主组合或回退。
96
+ - **具名导出**:与下述命名空间指向同一实现,便于 tree-shaking。
97
+ - **`WebExtendPluginVue2`**:`install`、`runtime`(含 `bootstrapPlugins`、`resolveRuntimeOptions`、`wrapManifestFetchWithCache` 等)、`host`、`config`、`constants`、`components`、`presets`(`vueCliAxios`)。
242
98
 
243
- ### 0.2.1
99
+ 更细的签名与说明以 **`index.d.ts`** 为准。
244
100
 
245
- - **Webpack 4 / Vue CLI**:去掉 `package.json` 的 `module` 字段,默认走 **`main`(CJS)**,避免误解析 `index.mjs` 导致浏览器端 `require is not defined`。
246
- - **`exports`**:补充 `default` 指向 CJS,便于仅部分实现 `exports` 条件的工具链兜底。
247
- - **语法兼容**:源码避免 `??` 等 Webpack 4 解析 `node_modules` 内 CJS 时可能不支持的语法,便于无 `transpileDependencies` 开箱接入。
101
+ ---
248
102
 
249
- ## 仓库与协议
103
+ ## 仓库
250
104
 
251
- - 源码:[extend-plugin-framework / web-extend-plugin-vue2](https://github.com/xtemplus/extend-plugin-framework/tree/master/web-extend-plugin-vue2)
252
- - 许可证:Apache-2.0
105
+ <https://github.com/xtemplus/extend-plugin-framework/tree/master/web-extend-plugin-vue2> · Apache-2.0