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 +45 -192
- package/dist/index.cjs +477 -547
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +475 -546
- package/dist/index.mjs.map +1 -1
- package/index.d.ts +136 -16
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,107 +1,62 @@
|
|
|
1
1
|
import Vue from 'vue';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* 使用方式:`resolveRuntimeOptions({ ...defaultWebExtendPluginRuntime, manifestListPath: '/api/my-plugins' })`
|
|
6
|
-
* 或只传需要改动的字段:`resolveRuntimeOptions({ manifestListPath: '/api/my-plugins' })`。
|
|
7
|
-
*
|
|
8
|
-
* @module default-runtime-config
|
|
4
|
+
* `resolveRuntimeOptions` 的默认值来源;宿主可只覆盖部分字段。
|
|
9
5
|
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {typeof defaultWebExtendPluginRuntime} WebExtendPluginDefaultRuntime
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
6
|
const defaultWebExtendPluginRuntime = {
|
|
16
|
-
/** 清单 HTTP 服务前缀(与后端 context-path 对齐),不含尾部 `/` */
|
|
17
7
|
manifestBase: '/fp-api',
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 拉取插件清单的 **路径段**(以 `/` 开头),拼在 `manifestBase` 之后。
|
|
21
|
-
* 完整 URL:`{manifestBase}{manifestListPath}` → 默认 `/fp-api/api/frontend-plugins`
|
|
22
|
-
*/
|
|
23
8
|
manifestListPath: '/api/frontend-plugins',
|
|
24
|
-
|
|
25
|
-
/** 清单 `fetch` 的 `credentials`,需 Cookie 会话时用 `include` */
|
|
26
9
|
manifestFetchCredentials: 'include',
|
|
27
|
-
|
|
28
|
-
/** 插件 dev 服务存活探测路径(拼在 `webPluginDevOrigin` 后) */
|
|
29
10
|
devPingPath: '/__web_plugin_dev_ping',
|
|
30
|
-
|
|
31
|
-
/** 插件 dev 热更新 SSE 路径(拼在插件 dev 的 origin 后) */
|
|
32
11
|
devReloadSsePath: '/__web_plugin_reload_stream',
|
|
33
|
-
|
|
34
|
-
/** 隐式 dev 映射里,每个 id 对应的入口路径(相对插件 dev origin) */
|
|
35
12
|
webPluginDevEntryPath: '/src/plugin-entry.js',
|
|
36
|
-
|
|
37
|
-
/** `fetch(devPingUrl)` 超时毫秒数 */
|
|
38
13
|
devPingTimeoutMs: 500,
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* **隐式 dev 映射**(可选):开发模式下若 `webPluginDevOrigin` 上 ping 成功,运行时会为若干插件 id 自动生成
|
|
42
|
-
* `{ id → origin + webPluginDevEntryPath }`,从而用 dev 服务入口替代清单里的 dist,便于热更新联调。
|
|
43
|
-
*
|
|
44
|
-
* 插件 id 来源优先级:`webPluginDevIds`(或 `VITE_WEB_PLUGIN_DEV_IDS`)→ 本字段。**默认 `[]`**,
|
|
45
|
-
* 避免把仓库示例 id 写进通用宿主;联调时在 `.env` 里设 `VITE_WEB_PLUGIN_DEV_IDS=com.xxx,com.yyy`,
|
|
46
|
-
* 或 `resolveRuntimeOptions({ defaultImplicitDevPluginIds: ['com.xxx'] })` 即可。
|
|
47
|
-
*/
|
|
48
14
|
defaultImplicitDevPluginIds: [],
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 允许通过 `<script>` / 动态 `import()` 加载的插件脚本所在主机名(小写),防误配公网 URL。
|
|
52
|
-
*/
|
|
53
15
|
allowedScriptHosts: ['localhost', '127.0.0.1', '::1'],
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* `hostApi.getBridge().request(path)` 允许的 path 前缀;须以 `/` 开头。
|
|
57
|
-
* 需与后端实际 API 前缀一致。
|
|
58
|
-
*/
|
|
59
16
|
bridgeAllowedPathPrefixes: ['/api/']
|
|
60
17
|
};
|
|
61
18
|
|
|
62
19
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* - Vite:在入口调用 `setWebExtendPluginEnv(import.meta.env)`,或 `installWebExtendPluginVue2(..., { env: import.meta.env })`。
|
|
66
|
-
* - 也可在入口前设置 `globalThis.__WEP_ENV__ = import.meta.env`(与 setWebExtendPluginEnv 二选一即可)。
|
|
67
|
-
*
|
|
68
|
-
* @module bundled-env
|
|
20
|
+
* 与具体打包器解耦的运行时环境读取:优先显式注入,其次 `globalThis.__WEP_ENV__`,再读 `process.env`。
|
|
21
|
+
* Vite 宿主建议在入口调用 `setWebExtendPluginEnv(import.meta.env)`。
|
|
69
22
|
*/
|
|
70
23
|
|
|
71
24
|
/** @type {Record<string, unknown> | null} */
|
|
72
|
-
let
|
|
25
|
+
let _injected = null;
|
|
73
26
|
|
|
74
27
|
/**
|
|
75
|
-
*
|
|
28
|
+
* 注入与 `import.meta.env` 同形态的对象(键如 `VITE_*`、`DEV`)。
|
|
76
29
|
* @param {Record<string, unknown> | null | undefined} env
|
|
77
30
|
*/
|
|
78
31
|
function setWebExtendPluginEnv(env) {
|
|
79
|
-
|
|
32
|
+
_injected = env && typeof env === 'object' ? env : null;
|
|
80
33
|
}
|
|
81
34
|
|
|
82
35
|
/**
|
|
83
36
|
* @returns {Record<string, unknown> | null}
|
|
84
37
|
*/
|
|
85
|
-
function
|
|
86
|
-
if (
|
|
87
|
-
return
|
|
38
|
+
function getEnvObject() {
|
|
39
|
+
if (_injected) {
|
|
40
|
+
return _injected
|
|
88
41
|
}
|
|
89
42
|
try {
|
|
90
43
|
const g = typeof globalThis !== 'undefined' ? globalThis : undefined;
|
|
91
44
|
if (g && g.__WEP_ENV__ && typeof g.__WEP_ENV__ === 'object') {
|
|
92
45
|
return g.__WEP_ENV__
|
|
93
46
|
}
|
|
94
|
-
} catch (_) {
|
|
47
|
+
} catch (_) {
|
|
48
|
+
/* ignore */
|
|
49
|
+
}
|
|
95
50
|
return null
|
|
96
51
|
}
|
|
97
52
|
|
|
98
53
|
/**
|
|
99
|
-
*
|
|
54
|
+
* 读取注入环境中的字符串配置(`VITE_*` / `PLUGIN_*` 等价键由调用方传入)。
|
|
100
55
|
* @param {string} key
|
|
101
56
|
* @returns {string|undefined}
|
|
102
57
|
*/
|
|
103
58
|
function readInjectedEnvKey(key) {
|
|
104
|
-
const o =
|
|
59
|
+
const o = getEnvObject();
|
|
105
60
|
if (!o || !(key in o)) {
|
|
106
61
|
return undefined
|
|
107
62
|
}
|
|
@@ -112,17 +67,14 @@ function readInjectedEnvKey(key) {
|
|
|
112
67
|
return String(v)
|
|
113
68
|
}
|
|
114
69
|
|
|
115
|
-
/**
|
|
116
|
-
* @returns {boolean}
|
|
117
|
-
*/
|
|
70
|
+
/** @returns {boolean} */
|
|
118
71
|
function readInjectedEnvDev() {
|
|
119
|
-
const o =
|
|
72
|
+
const o = getEnvObject();
|
|
120
73
|
return !!(o && o.DEV === true)
|
|
121
74
|
}
|
|
122
75
|
|
|
123
76
|
/**
|
|
124
|
-
* 从注入环境与 `process.env` 解析 VITE_/PLUGIN_ 键。
|
|
125
|
-
* @module runtime/env-resolve
|
|
77
|
+
* 从注入环境与 `process.env` 解析 `VITE_*` / `PLUGIN_*` 键。
|
|
126
78
|
*/
|
|
127
79
|
|
|
128
80
|
/**
|
|
@@ -137,7 +89,9 @@ function readProcessEnv(key) {
|
|
|
137
89
|
return String(v)
|
|
138
90
|
}
|
|
139
91
|
}
|
|
140
|
-
} catch (_) {
|
|
92
|
+
} catch (_) {
|
|
93
|
+
/* ignore */
|
|
94
|
+
}
|
|
141
95
|
return undefined
|
|
142
96
|
}
|
|
143
97
|
|
|
@@ -168,20 +122,22 @@ function resolveBundledEnv(key, fallback = '') {
|
|
|
168
122
|
return first === undefined || first === null ? fallback : first
|
|
169
123
|
}
|
|
170
124
|
|
|
171
|
-
/**
|
|
172
|
-
* @returns {boolean}
|
|
173
|
-
*/
|
|
125
|
+
/** @returns {boolean} */
|
|
174
126
|
function resolveBundledIsDev() {
|
|
175
127
|
try {
|
|
176
128
|
if (readInjectedEnvDev()) {
|
|
177
129
|
return true
|
|
178
130
|
}
|
|
179
|
-
} catch (_) {
|
|
131
|
+
} catch (_) {
|
|
132
|
+
/* ignore */
|
|
133
|
+
}
|
|
180
134
|
try {
|
|
181
135
|
if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'development') {
|
|
182
136
|
return true
|
|
183
137
|
}
|
|
184
|
-
} catch (_) {
|
|
138
|
+
} catch (_) {
|
|
139
|
+
/* ignore */
|
|
140
|
+
}
|
|
185
141
|
return false
|
|
186
142
|
}
|
|
187
143
|
|
|
@@ -386,39 +342,24 @@ function resolveRuntimeOptions$1(user = {}) {
|
|
|
386
342
|
allowedScriptHosts,
|
|
387
343
|
bridgeAllowedPathPrefixes,
|
|
388
344
|
bootstrapSummary: user.bootstrapSummary,
|
|
389
|
-
|
|
345
|
+
pluginRoutesParentName:
|
|
346
|
+
user.pluginRoutesParentName !== undefined && String(user.pluginRoutesParentName).trim() !== ''
|
|
347
|
+
? String(user.pluginRoutesParentName).trim()
|
|
348
|
+
: '',
|
|
349
|
+
...(typeof user.fetchManifest === 'function' ? { fetchManifest: user.fetchManifest } : {}),
|
|
350
|
+
...(typeof user.transformRoutes === 'function' ? { transformRoutes: user.transformRoutes } : {}),
|
|
351
|
+
...(typeof user.interceptRegisterRoutes === 'function'
|
|
352
|
+
? { interceptRegisterRoutes: user.interceptRegisterRoutes }
|
|
353
|
+
: {}),
|
|
354
|
+
...(typeof user.adaptRouteDeclarations === 'function'
|
|
355
|
+
? { adaptRouteDeclarations: user.adaptRouteDeclarations }
|
|
356
|
+
: {})
|
|
390
357
|
}
|
|
391
358
|
}
|
|
392
359
|
|
|
393
360
|
/**
|
|
394
|
-
*
|
|
395
|
-
* @
|
|
396
|
-
*/
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* @typedef {object} FetchWebPluginManifestContext
|
|
400
|
-
* @property {string} manifestUrl
|
|
401
|
-
* @property {RequestCredentials} credentials
|
|
402
|
-
*/
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* @typedef {object} FetchWebPluginManifestResult
|
|
406
|
-
* @property {boolean} ok
|
|
407
|
-
* @property {number} [status]
|
|
408
|
-
* @property {{ hostPluginApiVersion?: string, plugins?: object[] }|null} [data]
|
|
409
|
-
* @property {unknown} [error]
|
|
410
|
-
*/
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* @callback FetchWebPluginManifestFn
|
|
414
|
-
* @param {FetchWebPluginManifestContext} ctx
|
|
415
|
-
* @returns {Promise<FetchWebPluginManifestResult>}
|
|
416
|
-
*/
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* 默认清单请求(未配置 `fetchManifest` 时)。
|
|
420
|
-
* @param {FetchWebPluginManifestContext} ctx
|
|
421
|
-
* @returns {Promise<FetchWebPluginManifestResult>}
|
|
361
|
+
* 未配置 `fetchManifest` 时使用的清单 `fetch` 实现。
|
|
362
|
+
* @param {{ manifestUrl: string, credentials: RequestCredentials }} ctx
|
|
422
363
|
*/
|
|
423
364
|
async function defaultFetchWebPluginManifest$1(ctx) {
|
|
424
365
|
const { manifestUrl, credentials } = ctx;
|
|
@@ -3159,11 +3100,11 @@ function requireSemver () {
|
|
|
3159
3100
|
var semverExports = requireSemver();
|
|
3160
3101
|
var semver = /*@__PURE__*/getDefaultExportFromCjs(semverExports);
|
|
3161
3102
|
|
|
3162
|
-
/**
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
*/
|
|
3166
|
-
const
|
|
3103
|
+
/** 与清单服务 `hostPluginApiVersion` 对齐,用于 `semver` 校验。 */
|
|
3104
|
+
const HOST_PLUGIN_API_VERSION = '1.0.0';
|
|
3105
|
+
|
|
3106
|
+
/** 控制台日志与横幅使用的短名称。 */
|
|
3107
|
+
const RUNTIME_CONSOLE_LABEL = 'web-extend-plugin-vue2';
|
|
3167
3108
|
|
|
3168
3109
|
/**
|
|
3169
3110
|
* 开发模式插件 URL 映射(显式 JSON + 隐式 dev 探测)。
|
|
@@ -3185,7 +3126,7 @@ function parseWebPluginDevMapExplicit(opts) {
|
|
|
3185
3126
|
const map = JSON.parse(String(raw));
|
|
3186
3127
|
return map && typeof map === 'object' ? map : null
|
|
3187
3128
|
} catch {
|
|
3188
|
-
console.warn('[
|
|
3129
|
+
console.warn('[wep] invalid webPluginDevMapJson / VITE_WEB_PLUGIN_DEV_MAP');
|
|
3189
3130
|
return null
|
|
3190
3131
|
}
|
|
3191
3132
|
}
|
|
@@ -3267,14 +3208,7 @@ async function buildImplicitWebPluginDevMap(opts, hostSet) {
|
|
|
3267
3208
|
map[id] = `${base}${pathPart}`;
|
|
3268
3209
|
}
|
|
3269
3210
|
if (ids.length) {
|
|
3270
|
-
console.info(
|
|
3271
|
-
'[plugins] 已检测到插件 dev 服务(',
|
|
3272
|
-
base,
|
|
3273
|
-
'),下列 id 将加载隐式 dev 入口(',
|
|
3274
|
-
pathPart,
|
|
3275
|
-
')而非清单 dist:',
|
|
3276
|
-
ids.join(', ')
|
|
3277
|
-
);
|
|
3211
|
+
console.info('[wep] plugin dev server', base, '→ implicit entries', pathPart, ids.join(', '));
|
|
3278
3212
|
}
|
|
3279
3213
|
return map
|
|
3280
3214
|
}
|
|
@@ -3342,10 +3276,10 @@ function startPluginDevReloadSse(origin, isDev, hostSet, ssePath) {
|
|
|
3342
3276
|
window.location.reload();
|
|
3343
3277
|
});
|
|
3344
3278
|
es.onopen = () => {
|
|
3345
|
-
console.info('[
|
|
3279
|
+
console.info('[wep] dev reload SSE', url);
|
|
3346
3280
|
};
|
|
3347
3281
|
} catch (e) {
|
|
3348
|
-
console.warn('[
|
|
3282
|
+
console.warn('[wep] EventSource failed', url, e);
|
|
3349
3283
|
}
|
|
3350
3284
|
}
|
|
3351
3285
|
|
|
@@ -3433,9 +3367,21 @@ function loadScript(src) {
|
|
|
3433
3367
|
return p
|
|
3434
3368
|
}
|
|
3435
3369
|
|
|
3370
|
+
let _printed = false;
|
|
3371
|
+
|
|
3372
|
+
/** 在首次引导插件时打印一行运行时标识(非大块 ASCII art)。 */
|
|
3373
|
+
function printRuntimeBannerOnce() {
|
|
3374
|
+
if (_printed) {
|
|
3375
|
+
return
|
|
3376
|
+
}
|
|
3377
|
+
_printed = true;
|
|
3378
|
+
if (typeof console !== 'undefined' && typeof console.info === 'function') {
|
|
3379
|
+
console.info(`[wep] ${RUNTIME_CONSOLE_LABEL} · host API ${HOST_PLUGIN_API_VERSION}`);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3436
3383
|
/**
|
|
3437
|
-
*
|
|
3438
|
-
* @module runtime/bootstrap-plugins
|
|
3384
|
+
* 拉取插件清单、加载入口脚本并调用各插件 `activator`。
|
|
3439
3385
|
*/
|
|
3440
3386
|
|
|
3441
3387
|
/**
|
|
@@ -3468,7 +3414,7 @@ async function loadPluginEntry(p, entryUrl, devMap, hostSet) {
|
|
|
3468
3414
|
const devEntry = devMap && typeof devMap[p.id] === 'string' ? devMap[p.id].trim() : '';
|
|
3469
3415
|
if (devEntry) {
|
|
3470
3416
|
if (!isScriptHostAllowed(devEntry, hostSet)) {
|
|
3471
|
-
console.warn('[
|
|
3417
|
+
console.warn('[wep] dev entry URL not allowed', p.id, devEntry);
|
|
3472
3418
|
return
|
|
3473
3419
|
}
|
|
3474
3420
|
try {
|
|
@@ -3478,7 +3424,7 @@ async function loadPluginEntry(p, entryUrl, devMap, hostSet) {
|
|
|
3478
3424
|
devEntry
|
|
3479
3425
|
);
|
|
3480
3426
|
} catch (e) {
|
|
3481
|
-
console.warn('[
|
|
3427
|
+
console.warn('[wep] dev import failed, trying manifest entryUrl', p.id, e);
|
|
3482
3428
|
if (entryUrl && isScriptHostAllowed(entryUrl, hostSet)) {
|
|
3483
3429
|
await loadScript(entryUrl);
|
|
3484
3430
|
}
|
|
@@ -3487,7 +3433,7 @@ async function loadPluginEntry(p, entryUrl, devMap, hostSet) {
|
|
|
3487
3433
|
return
|
|
3488
3434
|
}
|
|
3489
3435
|
if (!entryUrl || !isScriptHostAllowed(entryUrl, hostSet)) {
|
|
3490
|
-
console.warn('[
|
|
3436
|
+
console.warn('[wep] skip (entryUrl not allowed)', p.id, entryUrl);
|
|
3491
3437
|
return
|
|
3492
3438
|
}
|
|
3493
3439
|
await loadScript(entryUrl);
|
|
@@ -3495,14 +3441,15 @@ async function loadPluginEntry(p, entryUrl, devMap, hostSet) {
|
|
|
3495
3441
|
|
|
3496
3442
|
/**
|
|
3497
3443
|
* @param {import('vue-router').default} router
|
|
3498
|
-
* @param {(pluginId: string, router: import('vue-router').default, hostKit?:
|
|
3444
|
+
* @param {(pluginId: string, router: import('vue-router').default, hostKit?: object) => object} createHostApiFactory
|
|
3499
3445
|
* @param {import('./resolve-runtime-options.js').WebExtendPluginRuntimeOptions} [runtimeOptions]
|
|
3500
3446
|
*/
|
|
3501
3447
|
async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions) {
|
|
3502
3448
|
if (typeof window === 'undefined') {
|
|
3503
|
-
console.warn('[
|
|
3449
|
+
console.warn('[wep] bootstrapPlugins skipped (no window)');
|
|
3504
3450
|
return
|
|
3505
3451
|
}
|
|
3452
|
+
printRuntimeBannerOnce();
|
|
3506
3453
|
const opts = resolveRuntimeOptions$1(runtimeOptions || {});
|
|
3507
3454
|
const base = String(opts.manifestBase).replace(/\/$/, '');
|
|
3508
3455
|
const manifestUrl = `${base}${opts.manifestListPath}`;
|
|
@@ -3530,16 +3477,28 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3530
3477
|
const devMap = mergeDevMaps(implicit, explicit);
|
|
3531
3478
|
startPluginDevSseForMap(devMap, opts.isDev, hostSet, opts.devReloadSsePath);
|
|
3532
3479
|
|
|
3533
|
-
const hostKit = {
|
|
3480
|
+
const hostKit = {
|
|
3481
|
+
bridgeAllowedPathPrefixes: opts.bridgeAllowedPathPrefixes,
|
|
3482
|
+
...(opts.pluginRoutesParentName
|
|
3483
|
+
? { pluginRoutesParentName: opts.pluginRoutesParentName }
|
|
3484
|
+
: {}),
|
|
3485
|
+
...(typeof opts.transformRoutes === 'function' ? { transformRoutes: opts.transformRoutes } : {}),
|
|
3486
|
+
...(typeof opts.interceptRegisterRoutes === 'function'
|
|
3487
|
+
? { interceptRegisterRoutes: opts.interceptRegisterRoutes }
|
|
3488
|
+
: {}),
|
|
3489
|
+
...(typeof opts.adaptRouteDeclarations === 'function'
|
|
3490
|
+
? { adaptRouteDeclarations: opts.adaptRouteDeclarations }
|
|
3491
|
+
: {})
|
|
3492
|
+
};
|
|
3534
3493
|
|
|
3535
3494
|
if (!manifestResult.ok) {
|
|
3536
3495
|
if (manifestResult.error) {
|
|
3537
|
-
console.warn('[
|
|
3496
|
+
console.warn('[wep] fetch manifest failed', manifestResult.error);
|
|
3538
3497
|
} else {
|
|
3539
|
-
console.warn('[
|
|
3498
|
+
console.warn('[wep] manifest HTTP', manifestResult.status, manifestUrl);
|
|
3540
3499
|
}
|
|
3541
3500
|
if (shouldShowBootstrapSummary(opts)) {
|
|
3542
|
-
console.info('[
|
|
3501
|
+
console.info('[wep] bootstrap_summary', { ok: false, reason: 'manifest_fetch' });
|
|
3543
3502
|
}
|
|
3544
3503
|
return
|
|
3545
3504
|
}
|
|
@@ -3547,7 +3506,7 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3547
3506
|
const data = manifestResult.data;
|
|
3548
3507
|
if (!data) {
|
|
3549
3508
|
if (shouldShowBootstrapSummary(opts)) {
|
|
3550
|
-
console.info('[
|
|
3509
|
+
console.info('[wep] bootstrap_summary', { ok: false, reason: 'manifest_empty_body' });
|
|
3551
3510
|
}
|
|
3552
3511
|
return
|
|
3553
3512
|
}
|
|
@@ -3558,12 +3517,10 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3558
3517
|
const maj = coerced ? coerced.major : 0;
|
|
3559
3518
|
const range = `^${maj}.0.0`;
|
|
3560
3519
|
if (!semver.satisfies(HOST_PLUGIN_API_VERSION, range, { includePrerelease: true })) {
|
|
3561
|
-
console.warn(
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
apiVer
|
|
3566
|
-
);
|
|
3520
|
+
console.warn('[wep] host API version mismatch', {
|
|
3521
|
+
host: HOST_PLUGIN_API_VERSION,
|
|
3522
|
+
manifest: apiVer
|
|
3523
|
+
});
|
|
3567
3524
|
}
|
|
3568
3525
|
}
|
|
3569
3526
|
|
|
@@ -3571,11 +3528,7 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3571
3528
|
|
|
3572
3529
|
const plugins = data.plugins || [];
|
|
3573
3530
|
if (plugins.length === 0) {
|
|
3574
|
-
console.info(
|
|
3575
|
-
'[plugins] 清单为空。请检查:① 后端清单服务(plugin-web-starter)是否已接入;② web-plugin.web-plugins-dir 是否指向含各插件子目录及 manifest.json 的路径;③ 浏览器直接访问',
|
|
3576
|
-
manifestUrl,
|
|
3577
|
-
'是否返回 plugins 条目。'
|
|
3578
|
-
);
|
|
3531
|
+
console.info('[wep] empty plugin manifest — check backend and URL', manifestUrl);
|
|
3579
3532
|
}
|
|
3580
3533
|
|
|
3581
3534
|
const summary = {
|
|
@@ -3590,7 +3543,7 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3590
3543
|
for (const p of plugins) {
|
|
3591
3544
|
const range = p.engines && p.engines.host;
|
|
3592
3545
|
if (range && !semver.satisfies(HOST_PLUGIN_API_VERSION, range, { includePrerelease: true })) {
|
|
3593
|
-
console.warn('[
|
|
3546
|
+
console.warn('[wep] skip plugin (engines.host)', p.id, range);
|
|
3594
3547
|
summary.skipEngines++;
|
|
3595
3548
|
continue
|
|
3596
3549
|
}
|
|
@@ -3598,39 +3551,34 @@ async function bootstrapPlugins$1(router, createHostApiFactory, runtimeOptions)
|
|
|
3598
3551
|
try {
|
|
3599
3552
|
await loadPluginEntry(p, entryUrl, devMap, hostSet);
|
|
3600
3553
|
} catch (e) {
|
|
3601
|
-
console.warn('[
|
|
3554
|
+
console.warn('[wep] script load failed', p.id, e);
|
|
3602
3555
|
summary.skipLoad++;
|
|
3603
3556
|
continue
|
|
3604
3557
|
}
|
|
3605
3558
|
const activator = window.__PLUGIN_ACTIVATORS__[p.id];
|
|
3606
3559
|
if (typeof activator !== 'function') {
|
|
3607
|
-
console.warn('[
|
|
3560
|
+
console.warn('[wep] no activator for', p.id);
|
|
3608
3561
|
summary.skipNoActivator++;
|
|
3609
3562
|
continue
|
|
3610
3563
|
}
|
|
3611
3564
|
const hostApi = createHostApiFactory(p.id, router, hostKit);
|
|
3612
3565
|
try {
|
|
3613
|
-
|
|
3566
|
+
const pluginRecord = Object.freeze({ ...p });
|
|
3567
|
+
activator(hostApi, { pluginRecord });
|
|
3614
3568
|
summary.activated++;
|
|
3615
3569
|
} catch (e) {
|
|
3616
|
-
console.error('[
|
|
3570
|
+
console.error('[wep] activate failed', p.id, e);
|
|
3617
3571
|
summary.activateFail++;
|
|
3618
3572
|
}
|
|
3619
3573
|
}
|
|
3620
3574
|
|
|
3621
3575
|
if (shouldShowBootstrapSummary(opts)) {
|
|
3622
|
-
console.info('[
|
|
3576
|
+
console.info('[wep] bootstrap_summary', { ok: true, ...summary });
|
|
3623
3577
|
}
|
|
3624
3578
|
}
|
|
3625
3579
|
|
|
3626
3580
|
/**
|
|
3627
|
-
*
|
|
3628
|
-
* 实现已拆至 `src/runtime/` 下各模块;本文件保留模块说明与对外类型约定,并 re-export 稳定 API。
|
|
3629
|
-
*
|
|
3630
|
-
* **Webpack 宿主**:用 `DefinePlugin` 注入 `process.env.VITE_*` 或 **`PLUGIN_*`**(等价键),或 `resolveRuntimeOptions` 显式传参。
|
|
3631
|
-
* **Vite 宿主**:入口调用 `setWebExtendPluginEnv(import.meta.env)`,或 `installWebExtendPluginVue2(..., { env: import.meta.env })`。
|
|
3632
|
-
*
|
|
3633
|
-
* @module PluginRuntime
|
|
3581
|
+
* 运行时引导相关 API 的聚合导出(实现位于 `./runtime/`)。
|
|
3634
3582
|
*/
|
|
3635
3583
|
|
|
3636
3584
|
var pluginRuntime = /*#__PURE__*/Object.freeze({
|
|
@@ -3642,7 +3590,7 @@ var pluginRuntime = /*#__PURE__*/Object.freeze({
|
|
|
3642
3590
|
|
|
3643
3591
|
/**
|
|
3644
3592
|
* 清单拉取函数的组合工具:缓存、埋点等以**中间件**形式扩展,不侵入 `bootstrapPlugins` 核心逻辑,
|
|
3645
|
-
*
|
|
3593
|
+
* 可组合的 `fetchManifest` 包装;入参/出参与 `resolveRuntimeOptions({ fetchManifest })` 一致。
|
|
3646
3594
|
*
|
|
3647
3595
|
* @module runtime/manifest-fetch-composer
|
|
3648
3596
|
*/
|
|
@@ -3857,356 +3805,367 @@ var manifestComposer = /*#__PURE__*/Object.freeze({
|
|
|
3857
3805
|
wrapManifestFetchWithCache: wrapManifestFetchWithCache$1
|
|
3858
3806
|
});
|
|
3859
3807
|
|
|
3860
|
-
/**
|
|
3861
|
-
*
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
if (
|
|
3885
|
-
throw new Error('[bridge] path
|
|
3886
|
-
}
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
}
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
...init
|
|
3894
|
-
})
|
|
3895
|
-
}
|
|
3896
|
-
}
|
|
3808
|
+
/**
|
|
3809
|
+
* 插件访问后端的受控通道:`fetch` 仅允许落在配置的路径前缀下(默认 `/api/`),默认 `credentials: 'same-origin'`。
|
|
3810
|
+
*/
|
|
3811
|
+
|
|
3812
|
+
/**
|
|
3813
|
+
* @param {{ allowedPathPrefixes?: string[] }} [config]
|
|
3814
|
+
*/
|
|
3815
|
+
function createRequestBridge(config = {}) {
|
|
3816
|
+
const raw =
|
|
3817
|
+
Array.isArray(config.allowedPathPrefixes) && config.allowedPathPrefixes.length > 0
|
|
3818
|
+
? config.allowedPathPrefixes
|
|
3819
|
+
: defaultWebExtendPluginRuntime.bridgeAllowedPathPrefixes;
|
|
3820
|
+
const allowedPathPrefixes = raw.map((p) => ensureLeadingPath(p));
|
|
3821
|
+
|
|
3822
|
+
return {
|
|
3823
|
+
/**
|
|
3824
|
+
* @param {string} path 必须以 `/` 开头,且匹配某一白名单前缀
|
|
3825
|
+
* @param {RequestInit} [init]
|
|
3826
|
+
*/
|
|
3827
|
+
async request(path, init = {}) {
|
|
3828
|
+
if (typeof path !== 'string' || !path.startsWith('/')) {
|
|
3829
|
+
throw new Error('[wep:bridge] path must start with /')
|
|
3830
|
+
}
|
|
3831
|
+
const allowed = allowedPathPrefixes.some((p) => path.startsWith(p));
|
|
3832
|
+
if (!allowed) {
|
|
3833
|
+
throw new Error('[wep:bridge] path not allowed: ' + path)
|
|
3834
|
+
}
|
|
3835
|
+
return fetch(path, {
|
|
3836
|
+
credentials: 'same-origin',
|
|
3837
|
+
...init
|
|
3838
|
+
})
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3897
3841
|
}
|
|
3898
3842
|
|
|
3899
|
-
/**
|
|
3900
|
-
*
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
*
|
|
3907
|
-
*
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
slots: {},
|
|
3915
|
-
/**
|
|
3916
|
-
* 每次变更 slots 时递增,供 ExtensionPoint 计算属性显式依赖。
|
|
3917
|
-
* Vue 2 对「先访问不存在的 slots[key]、后 Vue.set 补 key」的依赖收集不可靠,会导致扩展点不刷新。
|
|
3918
|
-
*/
|
|
3919
|
-
slotRevision: 0
|
|
3843
|
+
/**
|
|
3844
|
+
* 宿主侧响应式注册表:插件菜单与扩展点槽位(供布局与 `ExtensionPoint` 消费)。
|
|
3845
|
+
*/
|
|
3846
|
+
|
|
3847
|
+
/**
|
|
3848
|
+
* @type {{
|
|
3849
|
+
* menus: object[],
|
|
3850
|
+
* slots: Record<string, Array<{ pluginId: string, component: import('vue').Component, priority: number, key: string }>>
|
|
3851
|
+
* }}
|
|
3852
|
+
*/
|
|
3853
|
+
const registries = Vue.observable({
|
|
3854
|
+
menus: [],
|
|
3855
|
+
slots: {},
|
|
3856
|
+
/** 槽位变更计数;缓解 Vue2 对动态 `Vue.set(slots, key)` 的依赖收集不完整。 */
|
|
3857
|
+
slotRevision: 0
|
|
3920
3858
|
});
|
|
3921
3859
|
|
|
3922
|
-
/**
|
|
3923
|
-
*
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
*/
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
byPlugin.set(pluginId, arr);
|
|
3944
|
-
}
|
|
3945
|
-
arr.push(fn);
|
|
3946
|
-
}
|
|
3947
|
-
|
|
3948
|
-
/**
|
|
3949
|
-
* 执行并清空该插件已登记的全部 teardown;调用后 Map 中不再保留该 id。
|
|
3950
|
-
* @param {string} pluginId
|
|
3951
|
-
*/
|
|
3952
|
-
function runPluginTeardowns(pluginId) {
|
|
3953
|
-
const arr = byPlugin.get(pluginId);
|
|
3954
|
-
if (!arr) {
|
|
3955
|
-
return
|
|
3956
|
-
}
|
|
3957
|
-
byPlugin.delete(pluginId);
|
|
3958
|
-
for (const fn of arr) {
|
|
3959
|
-
try {
|
|
3960
|
-
fn();
|
|
3961
|
-
} catch (e) {
|
|
3962
|
-
console.warn('[plugins] teardown failed', pluginId, e);
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3860
|
+
/**
|
|
3861
|
+
* 按插件 id 收集 `onTeardown` 回调,供 `disposeWebPlugin` 统一执行。
|
|
3862
|
+
*/
|
|
3863
|
+
|
|
3864
|
+
/** @type {Map<string, Array<() => void>>} */
|
|
3865
|
+
const _byPlugin = new Map();
|
|
3866
|
+
|
|
3867
|
+
/**
|
|
3868
|
+
* @param {string} pluginId
|
|
3869
|
+
* @param {() => void} fn
|
|
3870
|
+
*/
|
|
3871
|
+
function registerPluginTeardown(pluginId, fn) {
|
|
3872
|
+
if (typeof fn !== 'function') {
|
|
3873
|
+
return
|
|
3874
|
+
}
|
|
3875
|
+
let list = _byPlugin.get(pluginId);
|
|
3876
|
+
if (!list) {
|
|
3877
|
+
list = [];
|
|
3878
|
+
_byPlugin.set(pluginId, list);
|
|
3879
|
+
}
|
|
3880
|
+
list.push(fn);
|
|
3965
3881
|
}
|
|
3966
3882
|
|
|
3967
|
-
/**
|
|
3968
|
-
*
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
*/
|
|
3984
|
-
|
|
3985
|
-
/**
|
|
3986
|
-
* @typedef {object} HostApi
|
|
3987
|
-
* @property {string} hostPluginApiVersion 宿主实现的协议版本
|
|
3988
|
-
* @property {(routes: import('vue-router').RouteConfig[]) => void} registerRoutes 注册路由;无 `name` 时自动生成稳定合成名;优先 `router.addRoute`
|
|
3989
|
-
* @property {(items: object[]) => void} registerMenuItems 注册菜单并按 `order` 排序
|
|
3990
|
-
* @property {(pointId: string, components: RegisterSlotEntry[]) => void} registerSlotComponents 向扩展点挂载组件
|
|
3991
|
-
* @property {(urls?: string[]) => void} registerStylesheetUrls 注入 `link[rel=stylesheet]`,带 `data-plugin-asset`
|
|
3992
|
-
* @property {(urls?: string[]) => void} registerScriptUrls 顺序注入外链脚本
|
|
3993
|
-
* @property {() => void} registerSanitizedHtmlSnippet MVP 未实现,调用即抛错
|
|
3994
|
-
* @property {() => ReturnType<typeof createRequestBridge>} getBridge 受控 `fetch` 代理
|
|
3995
|
-
* @property {(pluginId: string, fn: () => void) => void} onTeardown 注册卸载回调;由 `disposeWebPlugin(pluginId)` 触发
|
|
3996
|
-
*/
|
|
3997
|
-
|
|
3998
|
-
/**
|
|
3999
|
-
* @typedef {object} HostKitOptions
|
|
4000
|
-
* @property {string[]} [bridgeAllowedPathPrefixes] 覆盖 `getBridge().request` 允许的 URL 前缀;默认见 `defaultWebExtendPluginRuntime.bridgeAllowedPathPrefixes`
|
|
4001
|
-
*/
|
|
4002
|
-
|
|
4003
|
-
/**
|
|
4004
|
-
* 创建单个插件在宿主侧的 API 句柄,传入插件 `activator(hostApi)`。
|
|
4005
|
-
*
|
|
4006
|
-
* `bootstrapPlugins` 始终以 `(pluginId, router, hostKitOptions)` 调用工厂;请使用 `(id, r, kit) => createHostApi(id, r, kit)` 传入 `bridgeAllowedPathPrefixes`。
|
|
4007
|
-
* 单参工厂 `(id) => createHostApi(id, router)` 仍可用(忽略后两个实参),此时 bridge 仅用包内默认前缀。
|
|
4008
|
-
*
|
|
4009
|
-
* @param {string} pluginId 与 manifest.id 一致
|
|
4010
|
-
* @param {import('vue-router').default} router 宿主 Vue Router 实例(vue-router@3)
|
|
4011
|
-
* @param {HostKitOptions} [hostKitOptions]
|
|
4012
|
-
* @returns {HostApi}
|
|
4013
|
-
*/
|
|
4014
|
-
function createHostApi(pluginId, router, hostKitOptions = {}) {
|
|
4015
|
-
const bridgePrefixes =
|
|
4016
|
-
Array.isArray(hostKitOptions.bridgeAllowedPathPrefixes) &&
|
|
4017
|
-
hostKitOptions.bridgeAllowedPathPrefixes.length > 0
|
|
4018
|
-
? hostKitOptions.bridgeAllowedPathPrefixes
|
|
4019
|
-
: defaultWebExtendPluginRuntime.bridgeAllowedPathPrefixes;
|
|
4020
|
-
const bridge = createRequestBridge({ allowedPathPrefixes: bridgePrefixes });
|
|
4021
|
-
|
|
4022
|
-
/**
|
|
4023
|
-
* 注入样式表;`disposeWebPlugin` 会按 `data-plugin-asset` 移除对应节点。
|
|
4024
|
-
* @param {string} href
|
|
4025
|
-
*/
|
|
4026
|
-
function injectStylesheet(href) {
|
|
4027
|
-
const link = document.createElement('link');
|
|
4028
|
-
link.rel = 'stylesheet';
|
|
4029
|
-
link.href = href;
|
|
4030
|
-
link.setAttribute('data-plugin-asset', pluginId);
|
|
4031
|
-
document.head.appendChild(link);
|
|
4032
|
-
}
|
|
4033
|
-
|
|
4034
|
-
/**
|
|
4035
|
-
* 注入外链脚本(用于插件额外资源,非清单主入口)。
|
|
4036
|
-
* @param {string} src
|
|
4037
|
-
* @returns {Promise<void>}
|
|
4038
|
-
*/
|
|
4039
|
-
function injectScript(src) {
|
|
4040
|
-
return new Promise((resolve, reject) => {
|
|
4041
|
-
const s = document.createElement('script');
|
|
4042
|
-
s.async = true;
|
|
4043
|
-
s.src = src;
|
|
4044
|
-
s.setAttribute('data-plugin-asset', pluginId);
|
|
4045
|
-
s.onload = () => resolve();
|
|
4046
|
-
s.onerror = () => reject(new Error('script failed: ' + src));
|
|
4047
|
-
document.head.appendChild(s);
|
|
4048
|
-
})
|
|
4049
|
-
}
|
|
4050
|
-
|
|
4051
|
-
return {
|
|
4052
|
-
hostPluginApiVersion: HOST_PLUGIN_API_VERSION,
|
|
4053
|
-
|
|
4054
|
-
/**
|
|
4055
|
-
* 动态注册路由。Vue Router 3.5+ 推荐 `addRoute`;若不存在则回退已弃用的 `addRoutes`。
|
|
4056
|
-
* @param {import('vue-router').RouteConfig[]} routes
|
|
4057
|
-
*/
|
|
4058
|
-
registerRoutes(routes) {
|
|
4059
|
-
const wrapped = routes.map((r) => ({
|
|
4060
|
-
...r,
|
|
4061
|
-
name: r.name || `__wep_${pluginId}_${routeSynthSeq++}`,
|
|
4062
|
-
meta: { ...(r.meta || {}), pluginId }
|
|
4063
|
-
}));
|
|
4064
|
-
if (typeof router.addRoute === 'function') {
|
|
4065
|
-
for (const r of wrapped) {
|
|
4066
|
-
router.addRoute(r);
|
|
4067
|
-
}
|
|
4068
|
-
} else {
|
|
4069
|
-
router.addRoutes(wrapped);
|
|
4070
|
-
}
|
|
4071
|
-
},
|
|
4072
|
-
|
|
4073
|
-
/**
|
|
4074
|
-
* 写入全局菜单注册表(响应式);按 `order` 升序排列。
|
|
4075
|
-
* @param {object[]} items
|
|
4076
|
-
*/
|
|
4077
|
-
registerMenuItems(items) {
|
|
4078
|
-
for (const item of items) {
|
|
4079
|
-
registries.menus.push({ ...item, pluginId });
|
|
4080
|
-
}
|
|
4081
|
-
registries.menus.sort(
|
|
4082
|
-
(a, b) => (a.order != null ? a.order : 0) - (b.order != null ? b.order : 0)
|
|
4083
|
-
);
|
|
4084
|
-
},
|
|
4085
|
-
|
|
4086
|
-
/**
|
|
4087
|
-
* 向指定扩展点 id 注册 Vue 组件;`ExtensionPoint` 按 `priority` 降序渲染。
|
|
4088
|
-
* @param {string} pointId
|
|
4089
|
-
* @param {RegisterSlotEntry[]} components
|
|
4090
|
-
*/
|
|
4091
|
-
registerSlotComponents(pointId, components) {
|
|
4092
|
-
if (!pointId) {
|
|
4093
|
-
return
|
|
4094
|
-
}
|
|
4095
|
-
if (!registries.slots[pointId]) {
|
|
4096
|
-
Vue.set(registries.slots, pointId, []);
|
|
4097
|
-
}
|
|
4098
|
-
const list = registries.slots[pointId];
|
|
4099
|
-
for (const c of components) {
|
|
4100
|
-
list.push({
|
|
4101
|
-
pluginId,
|
|
4102
|
-
component: c.component,
|
|
4103
|
-
priority: c.priority != null ? c.priority : 0,
|
|
4104
|
-
key: `${pluginId}-${pointId}-${++slotItemKeySeq}`
|
|
4105
|
-
});
|
|
4106
|
-
}
|
|
4107
|
-
list.sort((a, b) => b.priority - a.priority);
|
|
4108
|
-
registries.slotRevision++;
|
|
4109
|
-
},
|
|
4110
|
-
|
|
4111
|
-
/**
|
|
4112
|
-
* @param {string[]|undefined} urls
|
|
4113
|
-
*/
|
|
4114
|
-
registerStylesheetUrls(urls) {
|
|
4115
|
-
for (const u of urls || []) {
|
|
4116
|
-
if (typeof u === 'string' && u) {
|
|
4117
|
-
injectStylesheet(u);
|
|
4118
|
-
}
|
|
4119
|
-
}
|
|
4120
|
-
},
|
|
4121
|
-
|
|
4122
|
-
/**
|
|
4123
|
-
* 串行加载多个脚本,失败仅告警不中断宿主。
|
|
4124
|
-
* @param {string[]|undefined} urls
|
|
4125
|
-
*/
|
|
4126
|
-
registerScriptUrls(urls) {
|
|
4127
|
-
const chain = (urls || []).filter((u) => typeof u === 'string' && u).reduce(
|
|
4128
|
-
(p, u) => p.then(() => injectScript(u)),
|
|
4129
|
-
Promise.resolve()
|
|
4130
|
-
);
|
|
4131
|
-
chain.catch((e) => console.warn('[plugins] registerScriptUrls', pluginId, e));
|
|
4132
|
-
},
|
|
4133
|
-
|
|
4134
|
-
registerSanitizedHtmlSnippet() {
|
|
4135
|
-
throw new Error('registerSanitizedHtmlSnippet is not enabled in MVP')
|
|
4136
|
-
},
|
|
4137
|
-
|
|
4138
|
-
getBridge: () => bridge,
|
|
4139
|
-
|
|
4140
|
-
/**
|
|
4141
|
-
* 插件卸载前清理逻辑;第一个参数为预留与协议对齐,实际以创建 API 时的 `pluginId` 为准。
|
|
4142
|
-
* @param {string} _pluginId 预留,与 manifest.id 一致时可传入
|
|
4143
|
-
* @param {() => void} fn
|
|
4144
|
-
*/
|
|
4145
|
-
onTeardown(_pluginId, fn) {
|
|
4146
|
-
if (typeof fn === 'function') {
|
|
4147
|
-
registerPluginTeardown(pluginId, fn);
|
|
4148
|
-
}
|
|
4149
|
-
}
|
|
4150
|
-
}
|
|
3883
|
+
/**
|
|
3884
|
+
* @param {string} pluginId
|
|
3885
|
+
*/
|
|
3886
|
+
function runPluginTeardowns(pluginId) {
|
|
3887
|
+
const list = _byPlugin.get(pluginId);
|
|
3888
|
+
if (!list) {
|
|
3889
|
+
return
|
|
3890
|
+
}
|
|
3891
|
+
_byPlugin.delete(pluginId);
|
|
3892
|
+
for (const fn of list) {
|
|
3893
|
+
try {
|
|
3894
|
+
fn();
|
|
3895
|
+
} catch (e) {
|
|
3896
|
+
console.warn('[wep] teardown failed', pluginId, e);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
4151
3899
|
}
|
|
4152
3900
|
|
|
4153
|
-
/**
|
|
4154
|
-
*
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
*
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
if (
|
|
4175
|
-
|
|
4176
|
-
}
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
}
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
}
|
|
4191
|
-
}
|
|
4192
|
-
registries.slotRevision++;
|
|
4193
|
-
|
|
4194
|
-
if (typeof window !== 'undefined' && window.__PLUGIN_ACTIVATORS__) {
|
|
4195
|
-
delete window.__PLUGIN_ACTIVATORS__[pluginId];
|
|
4196
|
-
}
|
|
4197
|
-
|
|
4198
|
-
if (typeof document !== 'undefined') {
|
|
4199
|
-
document.querySelectorAll('[data-plugin-asset]').forEach((el) => {
|
|
4200
|
-
if (el.getAttribute('data-plugin-asset') === pluginId) {
|
|
4201
|
-
el.remove();
|
|
4202
|
-
}
|
|
4203
|
-
});
|
|
4204
|
-
}
|
|
3901
|
+
/**
|
|
3902
|
+
* 构造插件 `activator(hostApi)` 使用的宿主 API:路由、菜单、扩展点、资源与受控请求桥。
|
|
3903
|
+
*/
|
|
3904
|
+
|
|
3905
|
+
let slotItemKeySeq = 0;
|
|
3906
|
+
let routeSynthSeq = 0;
|
|
3907
|
+
|
|
3908
|
+
/**
|
|
3909
|
+
* @param {unknown[]} nodes
|
|
3910
|
+
*/
|
|
3911
|
+
function analyzeRouteInputTree(nodes) {
|
|
3912
|
+
let hasDecl = false;
|
|
3913
|
+
let hasCfg = false;
|
|
3914
|
+
/** @param {unknown} r */
|
|
3915
|
+
function walk(r) {
|
|
3916
|
+
if (!r || typeof r !== 'object') {
|
|
3917
|
+
return
|
|
3918
|
+
}
|
|
3919
|
+
const o = /** @type {Record<string, unknown>} */ (r);
|
|
3920
|
+
const cfg = o.component != null || o.components != null;
|
|
3921
|
+
const decl = typeof o.componentRef === 'string';
|
|
3922
|
+
if (cfg) {
|
|
3923
|
+
hasCfg = true;
|
|
3924
|
+
} else if (decl) {
|
|
3925
|
+
hasDecl = true;
|
|
3926
|
+
}
|
|
3927
|
+
const ch = o.children;
|
|
3928
|
+
if (Array.isArray(ch)) {
|
|
3929
|
+
for (const c of ch) {
|
|
3930
|
+
walk(c);
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
for (const n of nodes) {
|
|
3935
|
+
walk(n);
|
|
3936
|
+
}
|
|
3937
|
+
return { hasDecl, hasCfg }
|
|
4205
3938
|
}
|
|
4206
3939
|
|
|
4207
3940
|
/**
|
|
4208
|
-
*
|
|
4209
|
-
*
|
|
3941
|
+
* 单插件在宿主侧的 API 句柄。工厂请传 `(id, router, kit) => createHostApi(id, r, kit)` 以便 bridge 白名单等到位。
|
|
3942
|
+
*
|
|
3943
|
+
* @param {string} pluginId
|
|
3944
|
+
* @param {import('vue-router').default} router
|
|
3945
|
+
* @param {Record<string, unknown>} [hostKitOptions] 与 `resolveRuntimeOptions` 中路由/bridge 等字段一致
|
|
3946
|
+
*/
|
|
3947
|
+
function createHostApi(pluginId, router, hostKitOptions = {}) {
|
|
3948
|
+
const bridgePrefixes =
|
|
3949
|
+
Array.isArray(hostKitOptions.bridgeAllowedPathPrefixes) &&
|
|
3950
|
+
hostKitOptions.bridgeAllowedPathPrefixes.length > 0
|
|
3951
|
+
? hostKitOptions.bridgeAllowedPathPrefixes
|
|
3952
|
+
: defaultWebExtendPluginRuntime.bridgeAllowedPathPrefixes;
|
|
3953
|
+
const bridge = createRequestBridge({ allowedPathPrefixes: bridgePrefixes });
|
|
3954
|
+
|
|
3955
|
+
const parentName =
|
|
3956
|
+
typeof hostKitOptions.pluginRoutesParentName === 'string'
|
|
3957
|
+
? hostKitOptions.pluginRoutesParentName.trim()
|
|
3958
|
+
: '';
|
|
3959
|
+
|
|
3960
|
+
/** @param {import('vue-router').RouteConfig[]} rawRouteConfigs */
|
|
3961
|
+
function applyInternalRegister(rawRouteConfigs) {
|
|
3962
|
+
const wrapped = rawRouteConfigs.map((r) => ({
|
|
3963
|
+
...r,
|
|
3964
|
+
name: r.name || `__wep_${pluginId}_${routeSynthSeq++}`,
|
|
3965
|
+
meta: { ...(r.meta || {}), pluginId }
|
|
3966
|
+
}));
|
|
3967
|
+
if (typeof router.addRoute === 'function') {
|
|
3968
|
+
if (parentName) {
|
|
3969
|
+
for (const r of wrapped) {
|
|
3970
|
+
router.addRoute(parentName, r);
|
|
3971
|
+
}
|
|
3972
|
+
} else {
|
|
3973
|
+
for (const r of wrapped) {
|
|
3974
|
+
router.addRoute(r);
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
} else {
|
|
3978
|
+
if (parentName) {
|
|
3979
|
+
console.warn(
|
|
3980
|
+
'[wep] pluginRoutesParentName requires vue-router 3.5+ addRoute; falling back to top-level addRoutes'
|
|
3981
|
+
);
|
|
3982
|
+
}
|
|
3983
|
+
router.addRoutes(wrapped);
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
function injectStylesheet(href) {
|
|
3988
|
+
const link = document.createElement('link');
|
|
3989
|
+
link.rel = 'stylesheet';
|
|
3990
|
+
link.href = href;
|
|
3991
|
+
link.setAttribute('data-plugin-asset', pluginId);
|
|
3992
|
+
document.head.appendChild(link);
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
/** @param {string} src */
|
|
3996
|
+
function injectScript(src) {
|
|
3997
|
+
return new Promise((resolve, reject) => {
|
|
3998
|
+
const s = document.createElement('script');
|
|
3999
|
+
s.async = true;
|
|
4000
|
+
s.src = src;
|
|
4001
|
+
s.setAttribute('data-plugin-asset', pluginId);
|
|
4002
|
+
s.onload = () => resolve();
|
|
4003
|
+
s.onerror = () => reject(new Error('script failed: ' + src));
|
|
4004
|
+
document.head.appendChild(s);
|
|
4005
|
+
})
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
return {
|
|
4009
|
+
hostPluginApiVersion: HOST_PLUGIN_API_VERSION,
|
|
4010
|
+
|
|
4011
|
+
registerRoutes(routes) {
|
|
4012
|
+
const list = Array.isArray(routes) ? routes : [];
|
|
4013
|
+
if (list.length === 0) {
|
|
4014
|
+
return
|
|
4015
|
+
}
|
|
4016
|
+
const { hasDecl, hasCfg } = analyzeRouteInputTree(list);
|
|
4017
|
+
if (hasDecl && hasCfg) {
|
|
4018
|
+
throw new Error(
|
|
4019
|
+
'[wep] registerRoutes: cannot mix RouteDeclaration (componentRef) with RouteConfig (component)'
|
|
4020
|
+
)
|
|
4021
|
+
}
|
|
4022
|
+
let /** @type {import('vue-router').RouteConfig[]} */ configs;
|
|
4023
|
+
if (hasDecl) {
|
|
4024
|
+
const adapt = hostKitOptions.adaptRouteDeclarations;
|
|
4025
|
+
if (typeof adapt !== 'function') {
|
|
4026
|
+
throw new Error(
|
|
4027
|
+
'[wep] registerRoutes: RouteDeclaration (componentRef) requires adaptRouteDeclarations on the host'
|
|
4028
|
+
)
|
|
4029
|
+
}
|
|
4030
|
+
configs = adapt({
|
|
4031
|
+
pluginId,
|
|
4032
|
+
router,
|
|
4033
|
+
declarations: /** @type {unknown[]} */ (list)
|
|
4034
|
+
});
|
|
4035
|
+
} else {
|
|
4036
|
+
configs = /** @type {import('vue-router').RouteConfig[]} */ (/** @type {unknown} */ (list));
|
|
4037
|
+
}
|
|
4038
|
+
|
|
4039
|
+
if (typeof hostKitOptions.transformRoutes === 'function') {
|
|
4040
|
+
configs = hostKitOptions.transformRoutes({
|
|
4041
|
+
pluginId,
|
|
4042
|
+
router,
|
|
4043
|
+
routes: configs
|
|
4044
|
+
});
|
|
4045
|
+
}
|
|
4046
|
+
|
|
4047
|
+
if (typeof hostKitOptions.interceptRegisterRoutes === 'function') {
|
|
4048
|
+
hostKitOptions.interceptRegisterRoutes({
|
|
4049
|
+
pluginId,
|
|
4050
|
+
router,
|
|
4051
|
+
routes: configs,
|
|
4052
|
+
applyInternalRegister
|
|
4053
|
+
});
|
|
4054
|
+
} else {
|
|
4055
|
+
applyInternalRegister(configs);
|
|
4056
|
+
}
|
|
4057
|
+
},
|
|
4058
|
+
|
|
4059
|
+
registerMenuItems(items) {
|
|
4060
|
+
for (const item of items) {
|
|
4061
|
+
registries.menus.push({ ...item, pluginId });
|
|
4062
|
+
}
|
|
4063
|
+
registries.menus.sort(
|
|
4064
|
+
(a, b) => (a.order != null ? a.order : 0) - (b.order != null ? b.order : 0)
|
|
4065
|
+
);
|
|
4066
|
+
},
|
|
4067
|
+
|
|
4068
|
+
registerSlotComponents(pointId, components) {
|
|
4069
|
+
if (!pointId) {
|
|
4070
|
+
return
|
|
4071
|
+
}
|
|
4072
|
+
if (!registries.slots[pointId]) {
|
|
4073
|
+
Vue.set(registries.slots, pointId, []);
|
|
4074
|
+
}
|
|
4075
|
+
const list = registries.slots[pointId];
|
|
4076
|
+
for (const c of components) {
|
|
4077
|
+
list.push({
|
|
4078
|
+
pluginId,
|
|
4079
|
+
component: c.component,
|
|
4080
|
+
priority: c.priority != null ? c.priority : 0,
|
|
4081
|
+
key: `${pluginId}-${pointId}-${++slotItemKeySeq}`
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
list.sort((a, b) => b.priority - a.priority);
|
|
4085
|
+
registries.slotRevision++;
|
|
4086
|
+
},
|
|
4087
|
+
|
|
4088
|
+
registerStylesheetUrls(urls) {
|
|
4089
|
+
for (const u of urls || []) {
|
|
4090
|
+
if (typeof u === 'string' && u) {
|
|
4091
|
+
injectStylesheet(u);
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
},
|
|
4095
|
+
|
|
4096
|
+
registerScriptUrls(urls) {
|
|
4097
|
+
const chain = (urls || []).filter((u) => typeof u === 'string' && u).reduce(
|
|
4098
|
+
(p, u) => p.then(() => injectScript(u)),
|
|
4099
|
+
Promise.resolve()
|
|
4100
|
+
);
|
|
4101
|
+
chain.catch((e) => console.warn('[wep] registerScriptUrls', pluginId, e));
|
|
4102
|
+
},
|
|
4103
|
+
|
|
4104
|
+
registerSanitizedHtmlSnippet() {
|
|
4105
|
+
throw new Error('registerSanitizedHtmlSnippet is not enabled')
|
|
4106
|
+
},
|
|
4107
|
+
|
|
4108
|
+
getBridge: () => bridge,
|
|
4109
|
+
|
|
4110
|
+
onTeardown(_pluginId, fn) {
|
|
4111
|
+
if (typeof fn === 'function') {
|
|
4112
|
+
registerPluginTeardown(pluginId, fn);
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
/**
|
|
4119
|
+
* 卸载单个插件:执行 teardown、清理注册表与 activator、移除带 `data-plugin-asset` 的 DOM。
|
|
4120
|
+
* 注意:Vue Router 3 无公开 `removeRoute`,动态路由通常需整页刷新或宿主自行维护。
|
|
4121
|
+
*/
|
|
4122
|
+
|
|
4123
|
+
/**
|
|
4124
|
+
* @param {string} pluginId 与 manifest `id` 一致
|
|
4125
|
+
*/
|
|
4126
|
+
function disposeWebPlugin(pluginId) {
|
|
4127
|
+
if (!pluginId || typeof pluginId !== 'string') {
|
|
4128
|
+
return
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
runPluginTeardowns(pluginId);
|
|
4132
|
+
|
|
4133
|
+
for (let i = registries.menus.length - 1; i >= 0; i--) {
|
|
4134
|
+
if (registries.menus[i].pluginId === pluginId) {
|
|
4135
|
+
registries.menus.splice(i, 1);
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
const slots = registries.slots;
|
|
4140
|
+
for (const pointId of Object.keys(slots)) {
|
|
4141
|
+
const list = slots[pointId];
|
|
4142
|
+
if (!Array.isArray(list)) {
|
|
4143
|
+
continue
|
|
4144
|
+
}
|
|
4145
|
+
const next = list.filter((x) => x.pluginId !== pluginId);
|
|
4146
|
+
if (next.length === 0) {
|
|
4147
|
+
Vue.delete(slots, pointId);
|
|
4148
|
+
} else if (next.length !== list.length) {
|
|
4149
|
+
Vue.set(slots, pointId, next);
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
registries.slotRevision++;
|
|
4153
|
+
|
|
4154
|
+
if (typeof window !== 'undefined' && window.__PLUGIN_ACTIVATORS__) {
|
|
4155
|
+
delete window.__PLUGIN_ACTIVATORS__[pluginId];
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
if (typeof document !== 'undefined') {
|
|
4159
|
+
document.querySelectorAll('[data-plugin-asset]').forEach((el) => {
|
|
4160
|
+
if (el.getAttribute('data-plugin-asset') === pluginId) {
|
|
4161
|
+
el.remove();
|
|
4162
|
+
}
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
|
|
4167
|
+
/**
|
|
4168
|
+
* 布局中的扩展点占位;插件通过 `hostApi.registerSlotComponents(pointId, ...)` 注入组件。
|
|
4210
4169
|
*/
|
|
4211
4170
|
|
|
4212
4171
|
const SlotErrorBoundary = {
|
|
@@ -4217,7 +4176,7 @@ const SlotErrorBoundary = {
|
|
|
4217
4176
|
},
|
|
4218
4177
|
errorCaptured(err) {
|
|
4219
4178
|
this.error = err && err.message ? err.message : String(err);
|
|
4220
|
-
console.error('[ExtensionPoint]
|
|
4179
|
+
console.error('[wep:ExtensionPoint]', this.label, err);
|
|
4221
4180
|
return false
|
|
4222
4181
|
},
|
|
4223
4182
|
render(h) {
|
|
@@ -4272,17 +4231,13 @@ var ExtensionPoint = {
|
|
|
4272
4231
|
};
|
|
4273
4232
|
|
|
4274
4233
|
/**
|
|
4275
|
-
*
|
|
4276
|
-
* @module install
|
|
4234
|
+
* 注册全局 `ExtensionPoint` 并异步拉取清单、激活插件。
|
|
4277
4235
|
*/
|
|
4278
4236
|
|
|
4279
4237
|
/**
|
|
4280
|
-
* 注册全局组件 `ExtensionPoint` 并异步引导插件清单。
|
|
4281
|
-
*
|
|
4282
4238
|
* @param {*} Vue
|
|
4283
|
-
* @param {*} router
|
|
4284
|
-
* @param {Record<string, unknown>} [options] 传给 `resolveRuntimeOptions
|
|
4285
|
-
* @returns {Promise<void>}
|
|
4239
|
+
* @param {*} router
|
|
4240
|
+
* @param {Record<string, unknown>} [options] 传给 `resolveRuntimeOptions`;可含 `env` 以读取 `VITE_*`
|
|
4286
4241
|
*/
|
|
4287
4242
|
function installWebExtendPluginVue2(Vue, router, options) {
|
|
4288
4243
|
const opts = options || {};
|
|
@@ -4298,23 +4253,20 @@ function installWebExtendPluginVue2(Vue, router, options) {
|
|
|
4298
4253
|
}
|
|
4299
4254
|
|
|
4300
4255
|
/**
|
|
4301
|
-
*
|
|
4302
|
-
* 对外以 {@link presetVueCliAxios} 聚合;亦保留具名函数便于 tree-shaking。
|
|
4303
|
-
*
|
|
4304
|
-
* @module presets/vue-cli-axios
|
|
4256
|
+
* Vue CLI + 统一 axios(如 RuoYi `utils/request`)场景的 `install` 预设。
|
|
4305
4257
|
*/
|
|
4306
4258
|
|
|
4307
4259
|
/**
|
|
4308
|
-
* @typedef {object}
|
|
4309
|
-
* @property {(config: { url: string, method?: string
|
|
4260
|
+
* @typedef {object} VueCliAxiosPresetDeps
|
|
4261
|
+
* @property {(config: { url: string, method?: string }) => Promise<unknown>} request
|
|
4310
4262
|
*/
|
|
4311
4263
|
|
|
4312
4264
|
/**
|
|
4313
|
-
*
|
|
4265
|
+
* 将完整 manifest URL 转为相对 `apiBase` 的请求 path,供 axios `baseURL` 拼接。
|
|
4314
4266
|
* @param {string} manifestUrl
|
|
4315
4267
|
* @param {string} [apiBase]
|
|
4316
4268
|
*/
|
|
4317
|
-
function
|
|
4269
|
+
function resolveManifestPathUnderApiBase(manifestUrl, apiBase) {
|
|
4318
4270
|
const base = String(
|
|
4319
4271
|
apiBase !== undefined
|
|
4320
4272
|
? apiBase
|
|
@@ -4332,11 +4284,11 @@ function manifestPathForVueCliApiBase(manifestUrl, apiBase) {
|
|
|
4332
4284
|
}
|
|
4333
4285
|
|
|
4334
4286
|
/**
|
|
4335
|
-
*
|
|
4287
|
+
* 将裸 `{ plugins }` 与 `{ code, data: { plugins } }` 式响应解包为清单对象。
|
|
4336
4288
|
* @param {unknown} body
|
|
4337
4289
|
* @returns {object|null}
|
|
4338
4290
|
*/
|
|
4339
|
-
function
|
|
4291
|
+
function unwrapNestedManifestBody(body) {
|
|
4340
4292
|
if (!body || typeof body !== 'object') {
|
|
4341
4293
|
return null
|
|
4342
4294
|
}
|
|
@@ -4368,15 +4320,13 @@ function bridgePrefixesFromVueCliEnv() {
|
|
|
4368
4320
|
}
|
|
4369
4321
|
|
|
4370
4322
|
/**
|
|
4371
|
-
*
|
|
4372
|
-
* @param {
|
|
4373
|
-
* @param {Record<string, unknown>} [extra] 合并覆盖,如 `manifestListPath`、`env` 等
|
|
4374
|
-
* @returns {Record<string, unknown>}
|
|
4323
|
+
* @param {VueCliAxiosPresetDeps} deps
|
|
4324
|
+
* @param {Record<string, unknown>} [extra]
|
|
4375
4325
|
*/
|
|
4376
4326
|
function createVueCliAxiosInstallOptions(deps, extra = {}) {
|
|
4377
4327
|
const { request } = deps;
|
|
4378
4328
|
if (typeof request !== 'function') {
|
|
4379
|
-
throw new Error('[
|
|
4329
|
+
throw new Error('[wep] createVueCliAxiosInstallOptions requires deps.request')
|
|
4380
4330
|
}
|
|
4381
4331
|
const envBase = (
|
|
4382
4332
|
typeof process !== 'undefined' && process.env && process.env.VUE_APP_BASE_API
|
|
@@ -4391,16 +4341,16 @@ function createVueCliAxiosInstallOptions(deps, extra = {}) {
|
|
|
4391
4341
|
|
|
4392
4342
|
const fetchManifest = async (ctx) => {
|
|
4393
4343
|
try {
|
|
4394
|
-
const url =
|
|
4344
|
+
const url = resolveManifestPathUnderApiBase(ctx.manifestUrl, stripBase);
|
|
4395
4345
|
const body = await request({
|
|
4396
4346
|
url,
|
|
4397
4347
|
method: 'get'
|
|
4398
4348
|
});
|
|
4399
|
-
const data =
|
|
4349
|
+
const data = unwrapNestedManifestBody(body);
|
|
4400
4350
|
if (!data || typeof data !== 'object') {
|
|
4401
4351
|
return {
|
|
4402
4352
|
ok: false,
|
|
4403
|
-
error: new Error('[
|
|
4353
|
+
error: new Error('[wep] invalid manifest response'),
|
|
4404
4354
|
data: null
|
|
4405
4355
|
}
|
|
4406
4356
|
}
|
|
@@ -4426,28 +4376,18 @@ function createVueCliAxiosInstallOptions(deps, extra = {}) {
|
|
|
4426
4376
|
return opts
|
|
4427
4377
|
}
|
|
4428
4378
|
|
|
4429
|
-
/**
|
|
4430
|
-
* Vue CLI + axios 预设的**对外聚合入口**(与具名导出函数等价,便于按需查阅与扩展多预设)。
|
|
4431
|
-
* @type {Readonly<{ id: string, description: string, createInstallOptions: typeof createVueCliAxiosInstallOptions, manifestPathForApiBase: typeof manifestPathForVueCliApiBase, unwrapManifestBody: typeof unwrapTableStyleManifestBody }>}
|
|
4432
|
-
*/
|
|
4433
4379
|
const presetVueCliAxios = Object.freeze({
|
|
4434
4380
|
id: 'vue-cli-axios',
|
|
4435
|
-
description: 'Vue CLI +
|
|
4381
|
+
description: 'Vue CLI + unified axios request; manifest uses host request()',
|
|
4436
4382
|
createInstallOptions: createVueCliAxiosInstallOptions,
|
|
4437
|
-
manifestPathForApiBase:
|
|
4438
|
-
unwrapManifestBody:
|
|
4383
|
+
manifestPathForApiBase: resolveManifestPathUnderApiBase,
|
|
4384
|
+
unwrapManifestBody: unwrapNestedManifestBody
|
|
4439
4385
|
});
|
|
4440
4386
|
|
|
4441
4387
|
/**
|
|
4442
|
-
*
|
|
4443
|
-
* 语义化版本内保持本文件导出的符号与聚合结构兼容。
|
|
4444
|
-
*
|
|
4445
|
-
* `PluginRuntime` 与 `manifest-fetch-composer` 通过 namespace 绑定到 `WebExtendPluginVue2.runtime`,避免具名导出与聚合对象重复列举。
|
|
4446
|
-
*
|
|
4447
|
-
* @module public
|
|
4388
|
+
* 包对外稳定导出与 `WebExtendPluginVue2` 命名空间。
|
|
4448
4389
|
*/
|
|
4449
4390
|
|
|
4450
|
-
|
|
4451
4391
|
const {
|
|
4452
4392
|
bootstrapPlugins,
|
|
4453
4393
|
defaultFetchWebPluginManifest,
|
|
@@ -4460,18 +4400,6 @@ const {
|
|
|
4460
4400
|
wrapManifestFetchWithCache
|
|
4461
4401
|
} = manifestComposer;
|
|
4462
4402
|
|
|
4463
|
-
/**
|
|
4464
|
-
* 根命名空间:宿主可通过 `WebExtendPluginVue2.presets.vueCliAxios` 等路径发现能力,避免仅依赖散落的具名导出。
|
|
4465
|
-
* @type {Readonly<{
|
|
4466
|
-
* install: typeof installWebExtendPluginVue2,
|
|
4467
|
-
* runtime: Readonly<{ bootstrapPlugins: typeof pluginRuntime.bootstrapPlugins, resolveRuntimeOptions: typeof pluginRuntime.resolveRuntimeOptions, defaultFetchWebPluginManifest: typeof pluginRuntime.defaultFetchWebPluginManifest, composeManifestFetch: typeof manifestComposer.composeManifestFetch, manifestFetchCacheMiddleware: typeof manifestComposer.manifestFetchCacheMiddleware, wrapManifestFetchWithCache: typeof manifestComposer.wrapManifestFetchWithCache }>,
|
|
4468
|
-
* host: Readonly<{ createHostApi: typeof createHostApi, disposeWebPlugin: typeof disposeWebPlugin, createRequestBridge: typeof createRequestBridge, registries: typeof registries }>,
|
|
4469
|
-
* config: Readonly<{ defaultWebExtendPluginRuntime: typeof defaultWebExtendPluginRuntime, setWebExtendPluginEnv: typeof setWebExtendPluginEnv }>,
|
|
4470
|
-
* constants: Readonly<{ HOST_PLUGIN_API_VERSION: typeof HOST_PLUGIN_API_VERSION }>,
|
|
4471
|
-
* components: Readonly<{ ExtensionPoint: typeof ExtensionPoint }>,
|
|
4472
|
-
* presets: Readonly<{ vueCliAxios: typeof presetVueCliAxios }>
|
|
4473
|
-
* }>}
|
|
4474
|
-
*/
|
|
4475
4403
|
const WebExtendPluginVue2 = Object.freeze({
|
|
4476
4404
|
install: installWebExtendPluginVue2,
|
|
4477
4405
|
runtime: Object.freeze({
|
|
@@ -4493,7 +4421,8 @@ const WebExtendPluginVue2 = Object.freeze({
|
|
|
4493
4421
|
setWebExtendPluginEnv
|
|
4494
4422
|
}),
|
|
4495
4423
|
constants: Object.freeze({
|
|
4496
|
-
HOST_PLUGIN_API_VERSION
|
|
4424
|
+
HOST_PLUGIN_API_VERSION,
|
|
4425
|
+
RUNTIME_CONSOLE_LABEL
|
|
4497
4426
|
}),
|
|
4498
4427
|
components: Object.freeze({
|
|
4499
4428
|
ExtensionPoint
|
|
@@ -4503,5 +4432,5 @@ const WebExtendPluginVue2 = Object.freeze({
|
|
|
4503
4432
|
})
|
|
4504
4433
|
});
|
|
4505
4434
|
|
|
4506
|
-
export { ExtensionPoint, HOST_PLUGIN_API_VERSION, WebExtendPluginVue2, bootstrapPlugins, composeManifestFetch, createHostApi, createRequestBridge, createVueCliAxiosInstallOptions, defaultFetchWebPluginManifest, defaultWebExtendPluginRuntime, disposeWebPlugin, installWebExtendPluginVue2, manifestFetchCacheMiddleware,
|
|
4435
|
+
export { ExtensionPoint, HOST_PLUGIN_API_VERSION, RUNTIME_CONSOLE_LABEL, WebExtendPluginVue2, bootstrapPlugins, composeManifestFetch, createHostApi, createRequestBridge, createVueCliAxiosInstallOptions, defaultFetchWebPluginManifest, defaultWebExtendPluginRuntime, disposeWebPlugin, installWebExtendPluginVue2, manifestFetchCacheMiddleware, presetVueCliAxios, registries, resolveManifestPathUnderApiBase, resolveRuntimeOptions, setWebExtendPluginEnv, unwrapNestedManifestBody, wrapManifestFetchWithCache };
|
|
4507
4436
|
//# sourceMappingURL=index.mjs.map
|