web-extend-plugin-vue2 0.2.5 → 0.3.0
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 -28
- package/dist/index.cjs +141 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +140 -58
- package/dist/index.mjs.map +1 -1
- package/index.d.ts +26 -22
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -338,15 +338,9 @@ function resolveRuntimeOptions$1(user = {}) {
|
|
|
338
338
|
return String(DEF.devFallbackStaticManifestUrl).trim();
|
|
339
339
|
})();
|
|
340
340
|
const hostLayoutComponent = user.hostLayoutComponent;
|
|
341
|
-
const pluginRoutesParentName = (()
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
if (hostLayoutComponent != null) {
|
|
346
|
-
return String(DEF.pluginRoutesParentName).trim();
|
|
347
|
-
}
|
|
348
|
-
return '';
|
|
349
|
-
})();
|
|
341
|
+
const pluginRoutesParentName = user.pluginRoutesParentName !== undefined && String(user.pluginRoutesParentName).trim() !== ''
|
|
342
|
+
? String(user.pluginRoutesParentName).trim()
|
|
343
|
+
: '';
|
|
350
344
|
const pluginMountRaw = user.pluginMountPath !== undefined && String(user.pluginMountPath).trim() !== ''
|
|
351
345
|
? String(user.pluginMountPath).trim()
|
|
352
346
|
: String(resolveBundledEnv(EK.mountPath, '') || DEF.pluginMountPath).trim();
|
|
@@ -354,7 +348,7 @@ function resolveRuntimeOptions$1(user = {}) {
|
|
|
354
348
|
const pluginHostRouteMeta = user.pluginHostRouteMeta !== undefined && user.pluginHostRouteMeta !== null
|
|
355
349
|
? user.pluginHostRouteMeta
|
|
356
350
|
: undefined;
|
|
357
|
-
const ensurePluginHostRoute = user.ensurePluginHostRoute
|
|
351
|
+
const ensurePluginHostRoute = user.ensurePluginHostRoute === true;
|
|
358
352
|
const devManifestFallback = (() => {
|
|
359
353
|
if (manifestMode === 'static') {
|
|
360
354
|
return false;
|
|
@@ -417,12 +411,6 @@ function resolveRuntimeOptions$1(user = {}) {
|
|
|
417
411
|
...(typeof user.adaptRouteDeclarations === 'function'
|
|
418
412
|
? { adaptRouteDeclarations: user.adaptRouteDeclarations }
|
|
419
413
|
: {}),
|
|
420
|
-
...(typeof user.applyPluginMenuItems === 'function'
|
|
421
|
-
? { applyPluginMenuItems: user.applyPluginMenuItems }
|
|
422
|
-
: {}),
|
|
423
|
-
...(typeof user.revokePluginMenuItems === 'function'
|
|
424
|
-
? { revokePluginMenuItems: user.revokePluginMenuItems }
|
|
425
|
-
: {}),
|
|
426
414
|
...(user.hostContext !== undefined &&
|
|
427
415
|
user.hostContext !== null &&
|
|
428
416
|
typeof user.hostContext === 'object' &&
|
|
@@ -3214,21 +3202,18 @@ var semverExports = requireSemver();
|
|
|
3214
3202
|
var semver = /*@__PURE__*/getDefaultExportFromCjs(semverExports);
|
|
3215
3203
|
|
|
3216
3204
|
/**
|
|
3217
|
-
*
|
|
3205
|
+
* 引导时注入的 router 引用,供 disposeWebPlugin 按插件批量 removeRoute。
|
|
3218
3206
|
*/
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3208
|
+
let bootstrapRouter;
|
|
3209
|
+
/** 由 bootstrapPlugins 在浏览器环境调用 */
|
|
3210
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3211
|
+
function setPluginBootstrapRouter(router) {
|
|
3212
|
+
bootstrapRouter = router;
|
|
3222
3213
|
}
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
revokePluginMenuItems(pluginId);
|
|
3227
|
-
}
|
|
3228
|
-
catch (e) {
|
|
3229
|
-
console.warn('[wep] revokePluginMenuItems failed', pluginId, e);
|
|
3230
|
-
}
|
|
3231
|
-
}
|
|
3214
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3215
|
+
function getPluginBootstrapRouter() {
|
|
3216
|
+
return bootstrapRouter;
|
|
3232
3217
|
}
|
|
3233
3218
|
|
|
3234
3219
|
/**
|
|
@@ -3485,7 +3470,8 @@ async function fetchStaticManifestViaHttp(ctx) {
|
|
|
3485
3470
|
}
|
|
3486
3471
|
|
|
3487
3472
|
/**
|
|
3488
|
-
*
|
|
3473
|
+
* 当 `ensurePluginHostRoute === true` 且提供 `pluginRoutesParentName` + `hostLayoutComponent` 时,
|
|
3474
|
+
* 注册 `pluginMountPath` + Layout 的命名父路由,供 `router.addRoute(parentName, child)` 挂载插件页。
|
|
3489
3475
|
*/
|
|
3490
3476
|
function routeNameExists(router, name) {
|
|
3491
3477
|
if (!name) {
|
|
@@ -3512,7 +3498,7 @@ function walkRouteNames(routes, name) {
|
|
|
3512
3498
|
return false;
|
|
3513
3499
|
}
|
|
3514
3500
|
function ensurePluginHostRoute$1(router, opts) {
|
|
3515
|
-
if (opts.ensurePluginHostRoute
|
|
3501
|
+
if (opts.ensurePluginHostRoute !== true) {
|
|
3516
3502
|
return;
|
|
3517
3503
|
}
|
|
3518
3504
|
if (!router || typeof router.addRoute !== 'function') {
|
|
@@ -3641,7 +3627,7 @@ createHostApiFactory, runtimeOptions) {
|
|
|
3641
3627
|
}
|
|
3642
3628
|
printRuntimeBannerOnce();
|
|
3643
3629
|
const opts = resolveRuntimeOptions$1(runtimeOptions || {});
|
|
3644
|
-
|
|
3630
|
+
setPluginBootstrapRouter(router);
|
|
3645
3631
|
ensurePluginHostRoute$1(router, opts);
|
|
3646
3632
|
const base = String(opts.manifestBase).replace(/\/$/, '');
|
|
3647
3633
|
const isStatic = opts.manifestMode === 'static';
|
|
@@ -3718,12 +3704,6 @@ createHostApiFactory, runtimeOptions) {
|
|
|
3718
3704
|
: {}),
|
|
3719
3705
|
...(typeof opts.adaptRouteDeclarations === 'function'
|
|
3720
3706
|
? { adaptRouteDeclarations: opts.adaptRouteDeclarations }
|
|
3721
|
-
: {}),
|
|
3722
|
-
...(typeof opts.applyPluginMenuItems === 'function'
|
|
3723
|
-
? { applyPluginMenuItems: opts.applyPluginMenuItems }
|
|
3724
|
-
: {}),
|
|
3725
|
-
...(typeof opts.revokePluginMenuItems === 'function'
|
|
3726
|
-
? { revokePluginMenuItems: opts.revokePluginMenuItems }
|
|
3727
3707
|
: {})
|
|
3728
3708
|
};
|
|
3729
3709
|
if (!manifestResult.ok) {
|
|
@@ -4013,7 +3993,7 @@ var manifestComposer = /*#__PURE__*/Object.freeze({
|
|
|
4013
3993
|
|
|
4014
3994
|
/**
|
|
4015
3995
|
* 宿主侧响应式注册表:扩展点槽位(供布局与 `ExtensionPoint` 消费)。
|
|
4016
|
-
*
|
|
3996
|
+
* 菜单由宿主从路由 `meta` 推导(见 `buildMenuDescriptorsFromRoutes`),框架不维护平行菜单列表。
|
|
4017
3997
|
*/
|
|
4018
3998
|
const registries = Vue.observable({
|
|
4019
3999
|
slots: {},
|
|
@@ -4076,6 +4056,47 @@ function createRequestBridge(config = {}) {
|
|
|
4076
4056
|
};
|
|
4077
4057
|
}
|
|
4078
4058
|
|
|
4059
|
+
/**
|
|
4060
|
+
* 记录各插件通过 registerRoutes 挂到 router 上的顶层 route name,便于 dispose 时 removeRoute。
|
|
4061
|
+
*/
|
|
4062
|
+
const pluginIdToRouteNames = new Map();
|
|
4063
|
+
function recordPluginTopRouteNames(pluginId, names) {
|
|
4064
|
+
if (!pluginId || names.length === 0) {
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
const cur = pluginIdToRouteNames.get(pluginId) || [];
|
|
4068
|
+
pluginIdToRouteNames.set(pluginId, cur.concat(names));
|
|
4069
|
+
}
|
|
4070
|
+
/**
|
|
4071
|
+
* 从 matcher 移除该插件登记过的顶层路由(含其子树)。
|
|
4072
|
+
* 需 vue-router ≥3.5 的 removeRoute;否则静默跳过。
|
|
4073
|
+
*/
|
|
4074
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4075
|
+
function removeRegisteredRoutesForPlugin(router, pluginId) {
|
|
4076
|
+
const names = pluginIdToRouteNames.get(pluginId);
|
|
4077
|
+
if (!names || names.length === 0) {
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
if (!router || typeof router.removeRoute !== 'function') {
|
|
4081
|
+
console.warn('[wep] router.removeRoute 不可用,跳过动态路由卸载', pluginId);
|
|
4082
|
+
pluginIdToRouteNames.delete(pluginId);
|
|
4083
|
+
return;
|
|
4084
|
+
}
|
|
4085
|
+
for (let i = names.length - 1; i >= 0; i--) {
|
|
4086
|
+
try {
|
|
4087
|
+
router.removeRoute(names[i]);
|
|
4088
|
+
}
|
|
4089
|
+
catch (e) {
|
|
4090
|
+
console.warn('[wep] removeRoute failed', names[i], e);
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
pluginIdToRouteNames.delete(pluginId);
|
|
4094
|
+
}
|
|
4095
|
+
/** 测试或宿主高级场景:查询已登记 name(勿依赖顺序语义) */
|
|
4096
|
+
function getRegisteredTopRouteNamesForPlugin(pluginId) {
|
|
4097
|
+
return [...(pluginIdToRouteNames.get(pluginId) || [])];
|
|
4098
|
+
}
|
|
4099
|
+
|
|
4079
4100
|
/**
|
|
4080
4101
|
* 构造插件 `activator(hostApi)` 使用的宿主 API:路由、菜单、扩展点、资源与受控请求桥。
|
|
4081
4102
|
*/
|
|
@@ -4131,6 +4152,7 @@ function createHostApi(pluginId, router, hostKitOptions = {}) {
|
|
|
4131
4152
|
if (typeof router.addRoute !== 'function') {
|
|
4132
4153
|
throw new Error('[wep] vue-router 3.5+ 必需:请使用 router.addRoute(不再支持 addRoutes)');
|
|
4133
4154
|
}
|
|
4155
|
+
recordPluginTopRouteNames(pluginId, wrapped.map((r) => String(r.name)));
|
|
4134
4156
|
if (parentName) {
|
|
4135
4157
|
for (const r of wrapped) {
|
|
4136
4158
|
router.addRoute(parentName, r);
|
|
@@ -4210,16 +4232,6 @@ function createHostApi(pluginId, router, hostKitOptions = {}) {
|
|
|
4210
4232
|
applyInternalRegister(configs);
|
|
4211
4233
|
}
|
|
4212
4234
|
},
|
|
4213
|
-
registerMenuItems(items) {
|
|
4214
|
-
const apply = hostKitOptions.applyPluginMenuItems;
|
|
4215
|
-
if (typeof apply !== 'function') {
|
|
4216
|
-
throw new Error('[wep] registerMenuItems 需要宿主在 resolveRuntimeOptions 中提供 applyPluginMenuItems,将菜单数据并入宿主侧栏/目录 state(框架不再维护 registries.menus)');
|
|
4217
|
-
}
|
|
4218
|
-
const list = Array.isArray(items) ? items : [];
|
|
4219
|
-
const enriched = list.map((item) => ({ ...item, pluginId }));
|
|
4220
|
-
enriched.sort((a, b) => (a.order != null ? Number(a.order) : 0) - (b.order != null ? Number(b.order) : 0));
|
|
4221
|
-
apply({ pluginId, items: enriched });
|
|
4222
|
-
},
|
|
4223
4235
|
registerSlotComponents(pointId, components) {
|
|
4224
4236
|
if (!pointId) {
|
|
4225
4237
|
return;
|
|
@@ -4263,15 +4275,15 @@ function createHostApi(pluginId, router, hostKitOptions = {}) {
|
|
|
4263
4275
|
}
|
|
4264
4276
|
|
|
4265
4277
|
/**
|
|
4266
|
-
* 卸载单个插件:执行 teardown、清理注册表与 activator、移除带 `data-plugin-asset` 的 DOM。
|
|
4267
|
-
*
|
|
4278
|
+
* 卸载单个插件:执行 teardown、按登记 name 批量 removeRoute、清理注册表与 activator、移除带 `data-plugin-asset` 的 DOM。
|
|
4279
|
+
* 依赖 vue-router ≥3.5 的 removeRoute;引导时由 bootstrapPlugins 注入 router。
|
|
4268
4280
|
*/
|
|
4269
4281
|
function disposeWebPlugin(pluginId) {
|
|
4270
4282
|
if (!pluginId || typeof pluginId !== 'string') {
|
|
4271
4283
|
return;
|
|
4272
4284
|
}
|
|
4273
4285
|
runPluginTeardowns(pluginId);
|
|
4274
|
-
|
|
4286
|
+
removeRegisteredRoutesForPlugin(getPluginBootstrapRouter(), pluginId);
|
|
4275
4287
|
const slots = registries.slots;
|
|
4276
4288
|
for (const pointId of Object.keys(slots)) {
|
|
4277
4289
|
const list = slots[pointId];
|
|
@@ -4299,6 +4311,75 @@ function disposeWebPlugin(pluginId) {
|
|
|
4299
4311
|
}
|
|
4300
4312
|
}
|
|
4301
4313
|
|
|
4314
|
+
/**
|
|
4315
|
+
* 从路由配置(含 meta)推导侧栏/目录用菜单描述,与 registerRoutes 入参同源。
|
|
4316
|
+
*
|
|
4317
|
+
* 约定:
|
|
4318
|
+
* - `meta.menu === false`:该节点及其子树不参与菜单
|
|
4319
|
+
* - 节点出现条件:`meta.title` 或 `meta.menuTitle` 非空字符串,或存在非空的子菜单列表
|
|
4320
|
+
* - `meta.order` 数字越小越靠前;缺省为 0
|
|
4321
|
+
* - 可选:`meta.icon`、`meta.permission`、`meta.hidden`、`meta.external`
|
|
4322
|
+
*/
|
|
4323
|
+
function pickTitle(meta, route) {
|
|
4324
|
+
if (typeof meta.menuTitle === 'string' && meta.menuTitle) {
|
|
4325
|
+
return meta.menuTitle;
|
|
4326
|
+
}
|
|
4327
|
+
if (typeof meta.title === 'string' && meta.title) {
|
|
4328
|
+
return meta.title;
|
|
4329
|
+
}
|
|
4330
|
+
if (route.name != null && String(route.name)) {
|
|
4331
|
+
return String(route.name);
|
|
4332
|
+
}
|
|
4333
|
+
return String(route.path || '');
|
|
4334
|
+
}
|
|
4335
|
+
function sortDescriptors(items) {
|
|
4336
|
+
items.sort((a, b) => a.order - b.order || a.path.localeCompare(b.path));
|
|
4337
|
+
for (const x of items) {
|
|
4338
|
+
if (x.children && x.children.length) {
|
|
4339
|
+
sortDescriptors(x.children);
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
/**
|
|
4344
|
+
* 从插件侧 RouteConfig 树构建菜单描述(不含 component,便于并入宿主菜单 state)。
|
|
4345
|
+
*/
|
|
4346
|
+
function buildMenuDescriptorsFromRoutes(routes, pluginId) {
|
|
4347
|
+
const out = [];
|
|
4348
|
+
function walk(route) {
|
|
4349
|
+
const meta = (route.meta || {});
|
|
4350
|
+
if (meta.menu === false) {
|
|
4351
|
+
return null;
|
|
4352
|
+
}
|
|
4353
|
+
const chIn = Array.isArray(route.children) ? route.children : [];
|
|
4354
|
+
const childMenus = chIn.map(walk).filter(Boolean);
|
|
4355
|
+
const hasTitle = typeof meta.title === 'string' || typeof meta.menuTitle === 'string';
|
|
4356
|
+
if (!hasTitle && childMenus.length === 0) {
|
|
4357
|
+
return null;
|
|
4358
|
+
}
|
|
4359
|
+
const item = {
|
|
4360
|
+
path: String(route.path || ''),
|
|
4361
|
+
name: route.name,
|
|
4362
|
+
title: pickTitle(meta, route),
|
|
4363
|
+
order: meta.order != null ? Number(meta.order) : 0,
|
|
4364
|
+
...(pluginId ? { pluginId } : {}),
|
|
4365
|
+
...(meta.icon !== undefined ? { icon: meta.icon } : {}),
|
|
4366
|
+
...(meta.permission !== undefined ? { permission: meta.permission } : {}),
|
|
4367
|
+
...(meta.hidden === true ? { hidden: true } : {}),
|
|
4368
|
+
...(meta.external === true ? { external: true } : {}),
|
|
4369
|
+
...(childMenus.length ? { children: childMenus } : {})
|
|
4370
|
+
};
|
|
4371
|
+
return item;
|
|
4372
|
+
}
|
|
4373
|
+
for (const r of routes) {
|
|
4374
|
+
const m = walk(r);
|
|
4375
|
+
if (m) {
|
|
4376
|
+
out.push(m);
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
sortDescriptors(out);
|
|
4380
|
+
return out;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4302
4383
|
/**
|
|
4303
4384
|
* 布局中的扩展点占位;插件通过 `hostApi.registerSlotComponents(pointId, ...)` 注入组件。
|
|
4304
4385
|
* 样式由宿主全局 CSS 覆盖 `.extension-point` / `.plugin-point-error`。
|
|
@@ -4469,7 +4550,7 @@ function createVueCliAxiosInstallOptions(deps, extra = {}) {
|
|
|
4469
4550
|
function createVueCliAxiosQuickInstallOptions(
|
|
4470
4551
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4471
4552
|
router, deps, extra = {}) {
|
|
4472
|
-
const { request, hostLayoutComponent, store, hostContext: depHostContext
|
|
4553
|
+
const { request, hostLayoutComponent, store, hostContext: depHostContext } = deps;
|
|
4473
4554
|
const { hostContext: extraHostContext, isDev: extraIsDev, manifestListPath: extraListPath, ...restExtra } = extra;
|
|
4474
4555
|
const hostContext = {
|
|
4475
4556
|
router,
|
|
@@ -4483,8 +4564,6 @@ router, deps, extra = {}) {
|
|
|
4483
4564
|
return createVueCliAxiosInstallOptions({ request }, {
|
|
4484
4565
|
hostLayoutComponent,
|
|
4485
4566
|
hostContext,
|
|
4486
|
-
applyPluginMenuItems,
|
|
4487
|
-
revokePluginMenuItems,
|
|
4488
4567
|
isDev: extraIsDev !== undefined ? Boolean(extraIsDev) : resolveBundledIsDev(),
|
|
4489
4568
|
manifestListPath,
|
|
4490
4569
|
...restExtra
|
|
@@ -4505,7 +4584,8 @@ const presetVueCliAxios = Object.freeze({
|
|
|
4505
4584
|
*/
|
|
4506
4585
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4507
4586
|
function installVueCliAxiosWebPlugins(Vue, router, deps, extra) {
|
|
4508
|
-
|
|
4587
|
+
/** 避免输出 `?.`:Vue CLI 4 / Webpack 4 默认不转译 node_modules */
|
|
4588
|
+
const exposeGlobalVue = extra == null || extra.exposeGlobalVue !== false;
|
|
4509
4589
|
if (exposeGlobalVue && typeof window !== 'undefined') {
|
|
4510
4590
|
window.Vue = Vue;
|
|
4511
4591
|
}
|
|
@@ -4534,7 +4614,9 @@ const WebExtendPluginVue2 = Object.freeze({
|
|
|
4534
4614
|
createHostApi,
|
|
4535
4615
|
disposeWebPlugin,
|
|
4536
4616
|
createRequestBridge,
|
|
4537
|
-
registries
|
|
4617
|
+
registries,
|
|
4618
|
+
buildMenuDescriptorsFromRoutes,
|
|
4619
|
+
getRegisteredTopRouteNamesForPlugin
|
|
4538
4620
|
}),
|
|
4539
4621
|
config: Object.freeze({
|
|
4540
4622
|
defaultWebExtendPluginRuntime,
|
|
@@ -4557,5 +4639,5 @@ const WebExtendPluginVue2 = Object.freeze({
|
|
|
4557
4639
|
})
|
|
4558
4640
|
});
|
|
4559
4641
|
|
|
4560
|
-
export { ExtensionPoint, HOST_PLUGIN_API_VERSION, RUNTIME_CONSOLE_LABEL, WebExtendPluginVue2, bootstrapPlugins, composeManifestFetch, createHostApi, createRequestBridge, createVueCliAxiosInstallOptions, createVueCliAxiosQuickInstallOptions, defaultFetchWebPluginManifest, defaultManifestFetchCache, defaultManifestMode, defaultVueCliJavaManifestListPath, defaultWebExtendPluginRuntime, disposeWebPlugin, ensurePluginHostRoute, installVueCliAxiosWebPlugins, installWebExtendPluginVue2, manifestFetchCacheMiddleware, peerMinimumVersions, presetVueCliAxios, registries, resolveManifestPathUnderApiBase, resolveRuntimeOptions, routeSynthNamePrefix, setWebExtendPluginEnv, unwrapNestedManifestBody, webExtendPluginEnvKeys, wrapManifestFetchWithCache };
|
|
4642
|
+
export { ExtensionPoint, HOST_PLUGIN_API_VERSION, RUNTIME_CONSOLE_LABEL, WebExtendPluginVue2, bootstrapPlugins, buildMenuDescriptorsFromRoutes, composeManifestFetch, createHostApi, createRequestBridge, createVueCliAxiosInstallOptions, createVueCliAxiosQuickInstallOptions, defaultFetchWebPluginManifest, defaultManifestFetchCache, defaultManifestMode, defaultVueCliJavaManifestListPath, defaultWebExtendPluginRuntime, disposeWebPlugin, ensurePluginHostRoute, getRegisteredTopRouteNamesForPlugin, installVueCliAxiosWebPlugins, installWebExtendPluginVue2, manifestFetchCacheMiddleware, peerMinimumVersions, presetVueCliAxios, registries, resolveManifestPathUnderApiBase, resolveRuntimeOptions, routeSynthNamePrefix, setWebExtendPluginEnv, unwrapNestedManifestBody, webExtendPluginEnvKeys, wrapManifestFetchWithCache };
|
|
4561
4643
|
//# sourceMappingURL=index.mjs.map
|