@virou/core 1.1.0 → 1.1.2
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 +3 -3
- package/dist/index.d.ts +116 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +211 -0
- package/dist/index.js.map +1 -0
- package/package.json +7 -10
- package/dist/index.d.mts +0 -107
- package/dist/index.mjs +0 -181
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ const { router, route } = useVRouter('my-wizard', routes)
|
|
|
186
186
|
hash: string
|
|
187
187
|
meta?: Record<PropertyKey, unknown>
|
|
188
188
|
params?: Record<string, string>
|
|
189
|
-
|
|
189
|
+
'~renderList': Component[] | null
|
|
190
190
|
}
|
|
191
191
|
```
|
|
192
192
|
- `router`:
|
|
@@ -312,10 +312,10 @@ const { router, route } = useVRouter('embedded-widget-app')
|
|
|
312
312
|
|
|
313
313
|
#### Runtime-Registered Globals
|
|
314
314
|
|
|
315
|
-
You may also mark a router as global at runtime by passing the `
|
|
315
|
+
You may also mark a router as global at runtime by passing the `isGlobal` option:
|
|
316
316
|
|
|
317
317
|
```ts
|
|
318
|
-
useVRouter(routes, {
|
|
318
|
+
useVRouter(routes, { isGlobal: true })
|
|
319
319
|
```
|
|
320
320
|
|
|
321
321
|
That router will stay registered even after components that use it unmount.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RouterContext } from "rou3";
|
|
2
|
+
import * as vue0 from "vue";
|
|
3
|
+
import { Component, DefineComponent, Plugin, PropType, ShallowRef, SlotsType, VNodeChild } from "vue";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
type Lazy<T> = () => Promise<T>;
|
|
7
|
+
type VRouteComponent = Component | DefineComponent;
|
|
8
|
+
type VRouteLazyComponent = Lazy<VRouteComponent>;
|
|
9
|
+
type VRouteRenderComponent = VRouteComponent | VRouteLazyComponent;
|
|
10
|
+
type VRouteMeta = Record<PropertyKey, unknown>;
|
|
11
|
+
interface VRouteRaw {
|
|
12
|
+
path: string;
|
|
13
|
+
component: VRouteRenderComponent;
|
|
14
|
+
meta?: VRouteMeta;
|
|
15
|
+
children?: VRouteRaw[];
|
|
16
|
+
}
|
|
17
|
+
type VRouteId = Readonly<[path: string, depth: number]>;
|
|
18
|
+
interface VRouteMatchedData {
|
|
19
|
+
id: VRouteId;
|
|
20
|
+
meta?: VRouteMeta;
|
|
21
|
+
}
|
|
22
|
+
interface VRouteNormalized extends Omit<VRouteRaw, 'path' | 'children'> {
|
|
23
|
+
parentId?: VRouteId;
|
|
24
|
+
}
|
|
25
|
+
type VRoutesMap = Map<VRouteId, VRouteNormalized>;
|
|
26
|
+
interface VRoute {
|
|
27
|
+
fullPath: string;
|
|
28
|
+
meta?: VRouteMeta;
|
|
29
|
+
params?: Record<string, string>;
|
|
30
|
+
path: string;
|
|
31
|
+
search: string;
|
|
32
|
+
hash: string;
|
|
33
|
+
'~renderList': Component[] | null;
|
|
34
|
+
}
|
|
35
|
+
interface VRouterData {
|
|
36
|
+
context: RouterContext<VRouteMatchedData>;
|
|
37
|
+
routes: VRoutesMap;
|
|
38
|
+
activePath: ShallowRef<string>;
|
|
39
|
+
route: ShallowRef<VRoute>;
|
|
40
|
+
isGlobal: boolean;
|
|
41
|
+
'~deps': number;
|
|
42
|
+
'~dispose': () => void;
|
|
43
|
+
}
|
|
44
|
+
interface VRouterOptions {
|
|
45
|
+
initialPath?: string;
|
|
46
|
+
isGlobal?: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface VRouter {
|
|
49
|
+
route: VRouterData['route'];
|
|
50
|
+
router: {
|
|
51
|
+
addRoute: (route: VRouteRaw) => void;
|
|
52
|
+
replace: (path: string) => void;
|
|
53
|
+
'~depthKey': symbol;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
interface VirouPluginOptions {
|
|
57
|
+
routers?: Record<string, {
|
|
58
|
+
routes: VRouteRaw[];
|
|
59
|
+
options?: Omit<VRouterOptions, 'isGlobal'>;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/components/VRouterView.d.ts
|
|
64
|
+
declare const VRouterView: vue0.DefineComponent<vue0.ExtractPropTypes<{
|
|
65
|
+
routerKey: StringConstructor;
|
|
66
|
+
keepAlive: {
|
|
67
|
+
type: BooleanConstructor;
|
|
68
|
+
default: boolean;
|
|
69
|
+
};
|
|
70
|
+
viewKey: {
|
|
71
|
+
type: PropType<string | ((route: VRoute, key: string) => string)>;
|
|
72
|
+
};
|
|
73
|
+
}>, () => string | number | boolean | vue0.VNode<vue0.RendererNode, vue0.RendererElement, {
|
|
74
|
+
[key: string]: any;
|
|
75
|
+
}> | vue0.VNodeArrayChildren | null, {}, {}, {}, vue0.ComponentOptionsMixin, vue0.ComponentOptionsMixin, {}, string, vue0.PublicProps, Readonly<vue0.ExtractPropTypes<{
|
|
76
|
+
routerKey: StringConstructor;
|
|
77
|
+
keepAlive: {
|
|
78
|
+
type: BooleanConstructor;
|
|
79
|
+
default: boolean;
|
|
80
|
+
};
|
|
81
|
+
viewKey: {
|
|
82
|
+
type: PropType<string | ((route: VRoute, key: string) => string)>;
|
|
83
|
+
};
|
|
84
|
+
}>> & Readonly<{}>, {
|
|
85
|
+
keepAlive: boolean;
|
|
86
|
+
}, SlotsType<{
|
|
87
|
+
default: (payload: {
|
|
88
|
+
Component: VNodeChild;
|
|
89
|
+
route: VRoute;
|
|
90
|
+
}) => VNodeChild;
|
|
91
|
+
fallback: (payload: {
|
|
92
|
+
route: VRoute;
|
|
93
|
+
}) => VNodeChild;
|
|
94
|
+
}>, {}, {}, string, vue0.ComponentProvideOptions, true, {}, any>;
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/composables/useVRouter.d.ts
|
|
97
|
+
declare function useVRouter(routes?: VRouteRaw[], options?: VRouterOptions): VRouter;
|
|
98
|
+
declare function useVRouter(key?: string, routes?: VRouteRaw[], options?: VRouterOptions): VRouter;
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/constants.d.ts
|
|
101
|
+
declare const virouSymbol: unique symbol;
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/plugin.d.ts
|
|
104
|
+
declare const virou: Plugin<[VirouPluginOptions?]>;
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/router/create.d.ts
|
|
107
|
+
declare function createVRouter(routes: VRouteRaw[], options?: VRouterOptions): VRouterData;
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/router/register.d.ts
|
|
110
|
+
declare function registerRoutes(ctx: RouterContext<VRouteMatchedData>, routes: VRouteRaw[], registry: VRoutesMap): void;
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/router/render.d.ts
|
|
113
|
+
declare function createRenderList(data: VRouteMatchedData, routes: VRoutesMap): VRouteRenderComponent[];
|
|
114
|
+
//#endregion
|
|
115
|
+
export { VRoute, VRouteComponent, VRouteId, VRouteLazyComponent, VRouteMatchedData, VRouteMeta, VRouteNormalized, VRouteRaw, VRouteRenderComponent, VRouter, VRouterData, VRouterOptions, VRouterView, VRoutesMap, VirouPluginOptions, createRenderList, createVRouter, registerRoutes, useVRouter, virou, virouSymbol };
|
|
116
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/components/VRouterView.ts","../src/composables/useVRouter.ts","../src/constants.ts","../src/plugin.ts","../src/router/create.ts","../src/router/register.ts","../src/router/render.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { addRoute, createRouter, findRoute } from "rou3";
|
|
2
|
+
import { KeepAlive, Suspense, defineAsyncComponent, defineComponent, getCurrentInstance, h, inject, onScopeDispose, provide, shallowRef, useId, watchEffect } from "vue";
|
|
3
|
+
import { joinURL, parseURL } from "ufo";
|
|
4
|
+
|
|
5
|
+
//#region src/constants.ts
|
|
6
|
+
const virouSymbol = Symbol("virou");
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/utils.ts
|
|
10
|
+
function normalizeComponent(component) {
|
|
11
|
+
if (typeof component === "function" && component.length === 0) return defineAsyncComponent(component);
|
|
12
|
+
return component;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/router/register.ts
|
|
17
|
+
function registerRoutes(ctx, routes, registry) {
|
|
18
|
+
const stack = [];
|
|
19
|
+
for (let i = routes.length - 1; i >= 0; i--) stack.push({ route: routes[i] });
|
|
20
|
+
while (stack.length > 0) {
|
|
21
|
+
const { route, parentId } = stack.pop();
|
|
22
|
+
const { path, meta, component, children } = route;
|
|
23
|
+
const fullPath = joinURL(parentId?.[0] ?? "/", path);
|
|
24
|
+
const depth = (parentId?.[1] ?? -1) + 1;
|
|
25
|
+
const id = Object.freeze([fullPath, depth]);
|
|
26
|
+
registry.set(id, {
|
|
27
|
+
meta,
|
|
28
|
+
component: normalizeComponent(component),
|
|
29
|
+
parentId
|
|
30
|
+
});
|
|
31
|
+
let isShadowed = false;
|
|
32
|
+
if (children && children.length > 0) {
|
|
33
|
+
isShadowed = children.some((c) => c.path === "" || c.path === "/");
|
|
34
|
+
for (let i = children.length - 1; i >= 0; i--) stack.push({
|
|
35
|
+
route: children[i],
|
|
36
|
+
parentId: id
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (!isShadowed) addRoute(ctx, "GET", fullPath, {
|
|
40
|
+
id,
|
|
41
|
+
meta
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/router/render.ts
|
|
48
|
+
const renderListCache = /* @__PURE__ */ new WeakMap();
|
|
49
|
+
function createRenderList(data, routes) {
|
|
50
|
+
let cacheForRoutes = renderListCache.get(routes);
|
|
51
|
+
if (!cacheForRoutes) {
|
|
52
|
+
cacheForRoutes = /* @__PURE__ */ new Map();
|
|
53
|
+
renderListCache.set(routes, cacheForRoutes);
|
|
54
|
+
}
|
|
55
|
+
const cached = cacheForRoutes.get(data.id);
|
|
56
|
+
if (cached) return cached;
|
|
57
|
+
const depth = data.id[1];
|
|
58
|
+
const list = Array.from({ length: depth });
|
|
59
|
+
let idx = depth;
|
|
60
|
+
let cursor = routes.get(data.id);
|
|
61
|
+
while (cursor) {
|
|
62
|
+
list[idx--] = cursor.component;
|
|
63
|
+
cursor = cursor.parentId !== void 0 ? routes.get(cursor.parentId) : void 0;
|
|
64
|
+
}
|
|
65
|
+
cacheForRoutes.set(data.id, list);
|
|
66
|
+
return list;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/router/create.ts
|
|
71
|
+
function createVRouter(routes, options) {
|
|
72
|
+
const context = createRouter();
|
|
73
|
+
const routeRegistry = /* @__PURE__ */ new Map();
|
|
74
|
+
registerRoutes(context, routes, routeRegistry);
|
|
75
|
+
let lastMatchedId;
|
|
76
|
+
let lastRenderList = null;
|
|
77
|
+
const activePath = shallowRef(options?.initialPath ?? "/");
|
|
78
|
+
const snapshot = () => {
|
|
79
|
+
const matchedRoute = findRoute(context, "GET", activePath.value);
|
|
80
|
+
if (matchedRoute) {
|
|
81
|
+
if (matchedRoute.data.id !== lastMatchedId) {
|
|
82
|
+
lastRenderList = createRenderList(matchedRoute.data, routeRegistry);
|
|
83
|
+
lastMatchedId = matchedRoute.data.id;
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
lastMatchedId = void 0;
|
|
87
|
+
lastRenderList = null;
|
|
88
|
+
}
|
|
89
|
+
const { pathname, hash, search } = parseURL(activePath.value);
|
|
90
|
+
return {
|
|
91
|
+
fullPath: activePath.value,
|
|
92
|
+
path: pathname,
|
|
93
|
+
search,
|
|
94
|
+
hash,
|
|
95
|
+
meta: matchedRoute?.data.meta,
|
|
96
|
+
params: matchedRoute?.params,
|
|
97
|
+
"~renderList": lastRenderList
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
const route = shallowRef(snapshot());
|
|
101
|
+
const unwatch = watchEffect(() => {
|
|
102
|
+
route.value = snapshot();
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
context,
|
|
106
|
+
routes: routeRegistry,
|
|
107
|
+
activePath,
|
|
108
|
+
route,
|
|
109
|
+
isGlobal: options?.isGlobal ?? false,
|
|
110
|
+
"~deps": 0,
|
|
111
|
+
"~dispose": unwatch
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/composables/useVRouter.ts
|
|
117
|
+
function useVRouter(...args) {
|
|
118
|
+
if (typeof args[0] !== "string") args.unshift(inject(virouSymbol, useId()));
|
|
119
|
+
const [key, routes = [], options = {}] = args;
|
|
120
|
+
if (!key || typeof key !== "string") throw new TypeError(`[virou] [useVRouter] key must be a string: ${key}`);
|
|
121
|
+
provide(virouSymbol, key);
|
|
122
|
+
const vm = getCurrentInstance();
|
|
123
|
+
if (!vm) throw new Error("[virou] [useVRouter] useVRouter must be called in setup()");
|
|
124
|
+
const virou$1 = vm.proxy?.$virou;
|
|
125
|
+
if (!virou$1) throw new Error("[virou] [useVRouter] virou plugin not installed");
|
|
126
|
+
if (routes.length) {
|
|
127
|
+
if (virou$1.get(key)) throw new Error(`[virou] [useVRouter] router with key "${key}" already exists`);
|
|
128
|
+
virou$1.set(key, createVRouter(routes, options));
|
|
129
|
+
}
|
|
130
|
+
const router = virou$1.get(key);
|
|
131
|
+
if (!router) throw new Error(`[virou] [useVRouter] router with key "${key}" not found`);
|
|
132
|
+
router["~deps"]++;
|
|
133
|
+
onScopeDispose(() => {
|
|
134
|
+
router["~deps"]--;
|
|
135
|
+
if (router["~deps"] === 0 && !router.isGlobal) {
|
|
136
|
+
router["~dispose"]();
|
|
137
|
+
virou$1.delete(key);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
route: router.route,
|
|
142
|
+
router: {
|
|
143
|
+
addRoute: (route) => {
|
|
144
|
+
registerRoutes(router.context, [route], router.routes);
|
|
145
|
+
},
|
|
146
|
+
replace: (path) => {
|
|
147
|
+
router.activePath.value = path;
|
|
148
|
+
},
|
|
149
|
+
"~depthKey": Symbol.for(key)
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/components/VRouterView.ts
|
|
156
|
+
const VRouterView = defineComponent({
|
|
157
|
+
name: "VRouterView",
|
|
158
|
+
inheritAttrs: false,
|
|
159
|
+
props: {
|
|
160
|
+
routerKey: String,
|
|
161
|
+
keepAlive: {
|
|
162
|
+
type: Boolean,
|
|
163
|
+
default: false
|
|
164
|
+
},
|
|
165
|
+
viewKey: { type: [String, Function] }
|
|
166
|
+
},
|
|
167
|
+
slots: Object,
|
|
168
|
+
setup(props, { slots, attrs }) {
|
|
169
|
+
const key = props.routerKey ?? inject(virouSymbol);
|
|
170
|
+
if (key === void 0) throw new Error("[virou] [VRouterView] routerKey is required");
|
|
171
|
+
const { route, router } = useVRouter(key);
|
|
172
|
+
const depth = inject(router["~depthKey"], 0);
|
|
173
|
+
provide(router["~depthKey"], depth + 1);
|
|
174
|
+
return () => {
|
|
175
|
+
const component = route.value["~renderList"]?.[depth];
|
|
176
|
+
if (!component) return slots.default?.({
|
|
177
|
+
Component: null,
|
|
178
|
+
route: route.value
|
|
179
|
+
}) ?? null;
|
|
180
|
+
const vnodeKey = typeof props.viewKey === "function" ? props.viewKey(route.value, key) : props.viewKey ?? `${key}-${depth}-${route.value.path}`;
|
|
181
|
+
const suspenseVNode = h(Suspense, null, {
|
|
182
|
+
default: () => h(component, {
|
|
183
|
+
key: vnodeKey,
|
|
184
|
+
...attrs
|
|
185
|
+
}),
|
|
186
|
+
fallback: () => slots.fallback?.({ route: route.value }) ?? null
|
|
187
|
+
});
|
|
188
|
+
const vnode = props.keepAlive ? h(KeepAlive, null, { default: () => suspenseVNode }) : suspenseVNode;
|
|
189
|
+
return slots.default?.({
|
|
190
|
+
Component: vnode,
|
|
191
|
+
route: route.value
|
|
192
|
+
}) ?? vnode;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/plugin.ts
|
|
199
|
+
const virou = (app, options = {}) => {
|
|
200
|
+
const { routers } = options;
|
|
201
|
+
const map = /* @__PURE__ */ new Map();
|
|
202
|
+
app.config.globalProperties.$virou = map;
|
|
203
|
+
if (routers) for (const [key, router] of Object.entries(routers)) map.set(key, createVRouter(router.routes, {
|
|
204
|
+
...router.options,
|
|
205
|
+
isGlobal: true
|
|
206
|
+
}));
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
export { VRouterView, createRenderList, createVRouter, registerRoutes, useVRouter, virou, virouSymbol };
|
|
211
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["stack: StackItem[]","id: VRouteId","routeRegistry: VRoutesMap","lastMatchedId: VRouteId | undefined","lastRenderList: VRouteRenderComponent[] | null","virou","virou: Plugin<[VirouPluginOptions?]>"],"sources":["../src/constants.ts","../src/utils.ts","../src/router/register.ts","../src/router/render.ts","../src/router/create.ts","../src/composables/useVRouter.ts","../src/components/VRouterView.ts","../src/plugin.ts"],"sourcesContent":["export const virouSymbol = Symbol('virou')\n","import type { Component } from 'vue'\nimport type { VRouteLazyComponent, VRouteRenderComponent } from './types'\nimport { defineAsyncComponent } from 'vue'\n\nexport function normalizeComponent(component: VRouteRenderComponent): Component {\n if (typeof component === 'function' && (component as VRouteLazyComponent).length === 0) {\n return defineAsyncComponent(component as VRouteLazyComponent)\n }\n return component as Component\n}\n","import type { RouterContext } from 'rou3'\nimport type { VRouteId, VRouteMatchedData, VRouteRaw, VRoutesMap } from '../types'\nimport { addRoute } from 'rou3'\nimport { joinURL } from 'ufo'\nimport { normalizeComponent } from '../utils'\n\ninterface StackItem {\n route: VRouteRaw\n parentId?: VRouteId\n}\n\nexport function registerRoutes(\n ctx: RouterContext<VRouteMatchedData>,\n routes: VRouteRaw[],\n registry: VRoutesMap,\n): void {\n const stack: StackItem[] = []\n for (let i = routes.length - 1; i >= 0; i--) {\n stack.push({ route: routes[i] })\n }\n\n while (stack.length > 0) {\n const { route, parentId } = stack.pop()!\n const { path, meta, component, children } = route\n\n const parentPath = parentId?.[0] ?? '/'\n const fullPath = joinURL(parentPath, path)\n const depth = (parentId?.[1] ?? -1) + 1\n const id: VRouteId = Object.freeze([fullPath, depth])\n\n registry.set(id, {\n meta,\n component: normalizeComponent(component),\n parentId,\n })\n\n let isShadowed = false\n if (children && children.length > 0) {\n isShadowed = children.some(c => c.path === '' || c.path === '/')\n\n for (let i = children.length - 1; i >= 0; i--) {\n stack.push({ route: children[i], parentId: id })\n }\n }\n\n if (!isShadowed) {\n addRoute(ctx, 'GET', fullPath, { id, meta })\n }\n }\n}\n","import type { Component } from 'vue'\nimport type { VRouteId, VRouteMatchedData, VRouteRenderComponent, VRoutesMap } from '../types'\n\nconst renderListCache = new WeakMap<VRoutesMap, Map<VRouteId, Component[]>>()\n\nexport function createRenderList(\n data: VRouteMatchedData,\n routes: VRoutesMap,\n): VRouteRenderComponent[] {\n let cacheForRoutes = renderListCache.get(routes)\n if (!cacheForRoutes) {\n cacheForRoutes = new Map<VRouteId, Component[]>()\n renderListCache.set(routes, cacheForRoutes)\n }\n\n const cached = cacheForRoutes.get(data.id)\n if (cached) {\n return cached\n }\n\n const depth = data.id[1]\n const list = Array.from<VRouteRenderComponent>({ length: depth })\n let idx = depth\n let cursor = routes.get(data.id)\n while (cursor) {\n list[idx--] = cursor.component\n cursor = cursor.parentId !== undefined ? routes.get(cursor.parentId) : undefined\n }\n\n cacheForRoutes.set(data.id, list)\n return list\n}\n","import type {\n VRoute,\n VRouteId,\n VRouteMatchedData,\n VRouteRaw,\n VRouterData,\n VRouteRenderComponent,\n VRouterOptions,\n VRoutesMap,\n} from '../types'\nimport { createRouter, findRoute } from 'rou3'\nimport { parseURL } from 'ufo'\nimport { shallowRef, watchEffect } from 'vue'\nimport { registerRoutes } from './register'\nimport { createRenderList } from './render'\n\nexport function createVRouter(routes: VRouteRaw[], options?: VRouterOptions): VRouterData {\n const context = createRouter<VRouteMatchedData>()\n const routeRegistry: VRoutesMap = new Map()\n\n registerRoutes(context, routes, routeRegistry)\n\n let lastMatchedId: VRouteId | undefined\n let lastRenderList: VRouteRenderComponent[] | null = null\n\n const activePath = shallowRef(options?.initialPath ?? '/')\n\n const snapshot = (): VRoute => {\n const matchedRoute = findRoute(context, 'GET', activePath.value)\n if (matchedRoute) {\n if (matchedRoute.data.id !== lastMatchedId) {\n lastRenderList = createRenderList(matchedRoute.data, routeRegistry)\n lastMatchedId = matchedRoute.data.id\n }\n }\n else {\n lastMatchedId = undefined\n lastRenderList = null\n }\n\n const { pathname, hash, search } = parseURL(activePath.value)\n\n return {\n fullPath: activePath.value,\n path: pathname,\n search,\n hash,\n meta: matchedRoute?.data.meta,\n params: matchedRoute?.params,\n '~renderList': lastRenderList,\n }\n }\n\n const route = shallowRef<VRoute>(snapshot())\n\n const unwatch = watchEffect(() => {\n route.value = snapshot()\n })\n\n return {\n context,\n routes: routeRegistry,\n activePath,\n route,\n isGlobal: options?.isGlobal ?? false,\n '~deps': 0,\n '~dispose': unwatch,\n }\n}\n","import type { VRouter, VRouteRaw, VRouterOptions } from '../types'\nimport { getCurrentInstance, inject, onScopeDispose, provide, useId } from 'vue'\nimport { virouSymbol } from '../constants'\nimport { createVRouter, registerRoutes } from '../router'\n\nexport function useVRouter(routes?: VRouteRaw[], options?: VRouterOptions): VRouter\nexport function useVRouter(key?: string, routes?: VRouteRaw[], options?: VRouterOptions): VRouter\nexport function useVRouter(...args: any[]): VRouter {\n if (typeof args[0] !== 'string') {\n args.unshift(inject<string>(virouSymbol, useId()))\n }\n\n const [key, routes = [], options = {}] = args as [string, VRouteRaw[], VRouterOptions]\n\n if (!key || typeof key !== 'string') {\n throw new TypeError(`[virou] [useVRouter] key must be a string: ${key}`)\n }\n\n provide(virouSymbol, key)\n\n const vm = getCurrentInstance()\n if (!vm) {\n throw new Error('[virou] [useVRouter] useVRouter must be called in setup()')\n }\n\n const virou = vm.proxy?.$virou\n if (!virou) {\n throw new Error('[virou] [useVRouter] virou plugin not installed')\n }\n\n if (routes.length) {\n if (virou.get(key)) {\n throw new Error(`[virou] [useVRouter] router with key \"${key}\" already exists`)\n }\n\n virou.set(key, createVRouter(routes, options))\n }\n\n const router = virou.get(key)\n if (!router) {\n throw new Error(`[virou] [useVRouter] router with key \"${key}\" not found`)\n }\n\n router['~deps']++\n onScopeDispose(() => {\n router['~deps']--\n\n if (router['~deps'] === 0 && !router.isGlobal) {\n router['~dispose']()\n virou.delete(key)\n }\n })\n\n return {\n route: router.route,\n router: {\n addRoute: (route: VRouteRaw) => {\n registerRoutes(router.context, [route], router.routes)\n },\n replace: (path: string) => {\n router.activePath.value = path\n },\n '~depthKey': Symbol.for(key),\n },\n }\n}\n","import type { PropType, SlotsType, VNodeChild } from 'vue'\nimport type { VRoute } from '../types'\nimport {\n defineComponent,\n h,\n inject,\n KeepAlive,\n provide,\n Suspense,\n} from 'vue'\nimport { useVRouter } from '../composables'\nimport { virouSymbol } from '../constants'\n\nexport const VRouterView = defineComponent({\n name: 'VRouterView',\n inheritAttrs: false,\n props: {\n routerKey: String,\n keepAlive: { type: Boolean, default: false },\n viewKey: { type: [String, Function] as PropType<string | ((route: VRoute, key: string) => string)> },\n },\n slots: Object as SlotsType<{\n default: (payload: { Component: VNodeChild, route: VRoute }) => VNodeChild\n fallback: (payload: { route: VRoute }) => VNodeChild\n }>,\n setup(props, { slots, attrs }) {\n const key = props.routerKey ?? inject<string>(virouSymbol)\n if (key === undefined) {\n throw new Error('[virou] [VRouterView] routerKey is required')\n }\n\n const { route, router } = useVRouter(key)\n\n const depth = inject<number>(router['~depthKey'], 0)\n provide(router['~depthKey'], depth + 1)\n\n return () => {\n const component = route.value['~renderList']?.[depth]\n if (!component) {\n return slots.default?.({ Component: null, route: route.value }) ?? null\n }\n\n const vnodeKey = typeof props.viewKey === 'function'\n ? props.viewKey(route.value, key)\n : props.viewKey ?? `${key}-${depth}-${route.value.path}`\n\n const suspenseVNode = h(\n Suspense,\n null,\n {\n default: () => h(component, { key: vnodeKey, ...attrs }),\n fallback: () => slots.fallback?.({ route: route.value }) ?? null,\n },\n )\n\n const vnode = props.keepAlive\n ? h(KeepAlive, null, { default: () => suspenseVNode })\n : suspenseVNode\n\n return slots.default?.({ Component: vnode, route: route.value }) ?? vnode\n }\n },\n})\n","import type { Plugin } from 'vue'\nimport type { VirouPluginOptions, VRouterData } from './types'\nimport { createVRouter } from './router'\n\nexport const virou: Plugin<[VirouPluginOptions?]> = (app, options = {}) => {\n const { routers } = options\n\n const map = new Map<string, VRouterData>()\n app.config.globalProperties.$virou = map\n\n if (routers) {\n for (const [key, router] of Object.entries(routers)) {\n map.set(key, createVRouter(router.routes, { ...router.options, isGlobal: true }))\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@virou/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.2",
|
|
5
5
|
"description": "Virtual router with multiple instance support for Vue",
|
|
6
6
|
"author": "Tankosin<https://github.com/tankosinn>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
],
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"exports": {
|
|
25
|
-
"types": "./dist/index.d.
|
|
26
|
-
"default": "./dist/index.
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
27
|
},
|
|
28
|
-
"main": "./dist/index.
|
|
29
|
-
"types": "./dist/index.d.
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
30
|
"files": [
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
@@ -34,13 +34,10 @@
|
|
|
34
34
|
"vue": "^3.5.0"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"rou3": "^0.
|
|
37
|
+
"rou3": "^0.7.12",
|
|
38
38
|
"ufo": "^1.6.1"
|
|
39
39
|
},
|
|
40
|
-
"devDependencies": {
|
|
41
|
-
"unbuild": "3.5.0"
|
|
42
|
-
},
|
|
43
40
|
"scripts": {
|
|
44
|
-
"build": "
|
|
41
|
+
"build": "pnpm -w tsdown -F @virou/core"
|
|
45
42
|
}
|
|
46
43
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { RouterContext } from 'rou3';
|
|
2
|
-
import * as vue from 'vue';
|
|
3
|
-
import { Component, DefineComponent, Ref, ShallowRef, PropType, SlotsType, VNodeChild, Plugin } from 'vue';
|
|
4
|
-
|
|
5
|
-
type Lazy<T> = () => Promise<T>;
|
|
6
|
-
type VRouteComponent = Component | DefineComponent;
|
|
7
|
-
type VRouteLazyComponent = Lazy<VRouteComponent>;
|
|
8
|
-
type VRouteRenderComponent = VRouteComponent | VRouteLazyComponent;
|
|
9
|
-
type VRouteMeta = Record<PropertyKey, unknown>;
|
|
10
|
-
interface VRouteRaw {
|
|
11
|
-
path: string;
|
|
12
|
-
component: VRouteRenderComponent;
|
|
13
|
-
meta?: VRouteMeta;
|
|
14
|
-
children?: VRouteRaw[];
|
|
15
|
-
}
|
|
16
|
-
type VRouteId = Readonly<[path: string, depth: number]>;
|
|
17
|
-
interface VRouteMatchedData {
|
|
18
|
-
id: VRouteId;
|
|
19
|
-
meta?: VRouteMeta;
|
|
20
|
-
}
|
|
21
|
-
interface VRouteNormalized extends Omit<VRouteRaw, 'path' | 'children'> {
|
|
22
|
-
parentId?: VRouteId;
|
|
23
|
-
}
|
|
24
|
-
type VRoutesMap = Map<VRouteId, VRouteNormalized>;
|
|
25
|
-
interface VRoute {
|
|
26
|
-
fullPath: string;
|
|
27
|
-
meta?: VRouteMeta;
|
|
28
|
-
params?: Record<string, string>;
|
|
29
|
-
path: string;
|
|
30
|
-
search: string;
|
|
31
|
-
hash: string;
|
|
32
|
-
_renderList: Component[] | null;
|
|
33
|
-
}
|
|
34
|
-
interface VRouterData {
|
|
35
|
-
context: RouterContext<VRouteMatchedData>;
|
|
36
|
-
routes: VRoutesMap;
|
|
37
|
-
activePath: Ref<string>;
|
|
38
|
-
route: ShallowRef<VRoute>;
|
|
39
|
-
_isGlobal: boolean;
|
|
40
|
-
_deps: number;
|
|
41
|
-
_dispose: () => void;
|
|
42
|
-
}
|
|
43
|
-
interface VRouterOptions {
|
|
44
|
-
initialPath?: string;
|
|
45
|
-
_isGlobal?: boolean;
|
|
46
|
-
}
|
|
47
|
-
interface VRouter {
|
|
48
|
-
route: VRouterData['route'];
|
|
49
|
-
router: {
|
|
50
|
-
addRoute: (route: VRouteRaw) => void;
|
|
51
|
-
replace: (path: string) => void;
|
|
52
|
-
_depthKey: symbol;
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
interface VirouPluginOptions {
|
|
56
|
-
routers?: Record<string, {
|
|
57
|
-
routes: VRouteRaw[];
|
|
58
|
-
options?: Omit<VRouterOptions, '_isGlobal'>;
|
|
59
|
-
}>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
declare module 'vue' {
|
|
63
|
-
interface ComponentCustomProperties {
|
|
64
|
-
$virou: Map<string, VRouterData>
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
declare const VRouterView: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
69
|
-
routerKey: StringConstructor;
|
|
70
|
-
keepAlive: {
|
|
71
|
-
type: BooleanConstructor;
|
|
72
|
-
default: boolean;
|
|
73
|
-
};
|
|
74
|
-
viewKey: {
|
|
75
|
-
type: PropType<string | ((route: VRoute, key: string) => string)>;
|
|
76
|
-
};
|
|
77
|
-
}>, () => string | number | boolean | vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
78
|
-
[key: string]: any;
|
|
79
|
-
}> | vue.VNodeArrayChildren | null, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
80
|
-
routerKey: StringConstructor;
|
|
81
|
-
keepAlive: {
|
|
82
|
-
type: BooleanConstructor;
|
|
83
|
-
default: boolean;
|
|
84
|
-
};
|
|
85
|
-
viewKey: {
|
|
86
|
-
type: PropType<string | ((route: VRoute, key: string) => string)>;
|
|
87
|
-
};
|
|
88
|
-
}>> & Readonly<{}>, {
|
|
89
|
-
keepAlive: boolean;
|
|
90
|
-
}, SlotsType<{
|
|
91
|
-
default: (payload: {
|
|
92
|
-
Component: VNodeChild;
|
|
93
|
-
route: VRoute;
|
|
94
|
-
}) => VNodeChild;
|
|
95
|
-
fallback: (payload: {
|
|
96
|
-
route: VRoute;
|
|
97
|
-
}) => VNodeChild;
|
|
98
|
-
}>, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
99
|
-
|
|
100
|
-
declare const virou: Plugin<[VirouPluginOptions?]>;
|
|
101
|
-
|
|
102
|
-
declare const virouSymbol: unique symbol;
|
|
103
|
-
declare function createVRouter(routes: VRouteRaw[], options?: VRouterOptions): VRouterData;
|
|
104
|
-
declare function useVRouter(routes?: VRouteRaw[], options?: VRouterOptions): VRouter;
|
|
105
|
-
declare function useVRouter(key?: string, routes?: VRouteRaw[], options?: VRouterOptions): VRouter;
|
|
106
|
-
|
|
107
|
-
export { type VRoute, type VRouteComponent, type VRouteId, type VRouteLazyComponent, type VRouteMatchedData, type VRouteMeta, type VRouteNormalized, type VRouteRaw, type VRouteRenderComponent, type VRouter, type VRouterData, type VRouterOptions, VRouterView, type VRoutesMap, type VirouPluginOptions, createVRouter, useVRouter, virou, virouSymbol };
|
package/dist/index.mjs
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { defineAsyncComponent, ref, shallowRef, watchEffect, inject, useId, provide, getCurrentInstance, onScopeDispose, defineComponent, h, Suspense, KeepAlive } from 'vue';
|
|
2
|
-
import { addRoute, createRouter, findRoute } from 'rou3';
|
|
3
|
-
import { joinURL, parseURL } from 'ufo';
|
|
4
|
-
|
|
5
|
-
const renderListCache = /* @__PURE__ */ new WeakMap();
|
|
6
|
-
function normalizeComponent(component) {
|
|
7
|
-
if (typeof component === "function" && component.length === 0) {
|
|
8
|
-
return defineAsyncComponent(component);
|
|
9
|
-
}
|
|
10
|
-
return component;
|
|
11
|
-
}
|
|
12
|
-
function registerRoutes(ctx, routes, registry, parentId) {
|
|
13
|
-
for (const { path, meta, component, children } of routes) {
|
|
14
|
-
const fullPath = joinURL(parentId?.[0] ?? "/", path);
|
|
15
|
-
const depth = (parentId?.[1] ?? -1) + 1;
|
|
16
|
-
const id = Object.freeze([fullPath, depth]);
|
|
17
|
-
registry.set(id, {
|
|
18
|
-
meta,
|
|
19
|
-
component: normalizeComponent(component),
|
|
20
|
-
parentId
|
|
21
|
-
});
|
|
22
|
-
if (children && children.length) {
|
|
23
|
-
registerRoutes(ctx, children, registry, id);
|
|
24
|
-
}
|
|
25
|
-
addRoute(ctx, "GET", fullPath, { id, meta });
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function createRenderList(data, routes) {
|
|
29
|
-
let cacheForRoutes = renderListCache.get(routes);
|
|
30
|
-
if (!cacheForRoutes) {
|
|
31
|
-
cacheForRoutes = /* @__PURE__ */ new Map();
|
|
32
|
-
renderListCache.set(routes, cacheForRoutes);
|
|
33
|
-
}
|
|
34
|
-
const cached = cacheForRoutes.get(data.id);
|
|
35
|
-
if (cached) {
|
|
36
|
-
return cached;
|
|
37
|
-
}
|
|
38
|
-
const depth = data.id[1];
|
|
39
|
-
const list = Array.from({ length: depth });
|
|
40
|
-
let idx = depth;
|
|
41
|
-
let cursor = routes.get(data.id);
|
|
42
|
-
while (cursor) {
|
|
43
|
-
list[idx--] = cursor.component;
|
|
44
|
-
cursor = cursor.parentId !== void 0 ? routes.get(cursor.parentId) : void 0;
|
|
45
|
-
}
|
|
46
|
-
cacheForRoutes.set(data.id, list);
|
|
47
|
-
return list;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const virouSymbol = Symbol("virou");
|
|
51
|
-
function createVRouter(routes, options) {
|
|
52
|
-
const context = createRouter();
|
|
53
|
-
const routeRegistry = /* @__PURE__ */ new Map();
|
|
54
|
-
registerRoutes(context, routes, routeRegistry);
|
|
55
|
-
const activePath = ref(options?.initialPath ?? "/");
|
|
56
|
-
const snapshot = () => {
|
|
57
|
-
const matchedRoute = findRoute(context, "GET", activePath.value);
|
|
58
|
-
const _renderList = matchedRoute ? createRenderList(matchedRoute.data, routeRegistry) : null;
|
|
59
|
-
const { pathname, hash, search } = parseURL(activePath.value);
|
|
60
|
-
return {
|
|
61
|
-
fullPath: activePath.value,
|
|
62
|
-
path: pathname,
|
|
63
|
-
search,
|
|
64
|
-
hash,
|
|
65
|
-
meta: matchedRoute?.data.meta,
|
|
66
|
-
params: matchedRoute?.params,
|
|
67
|
-
_renderList
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
const route = shallowRef(snapshot());
|
|
71
|
-
const unwatch = watchEffect(() => {
|
|
72
|
-
route.value = snapshot();
|
|
73
|
-
});
|
|
74
|
-
return {
|
|
75
|
-
context,
|
|
76
|
-
routes: routeRegistry,
|
|
77
|
-
activePath,
|
|
78
|
-
route,
|
|
79
|
-
_isGlobal: options?._isGlobal ?? false,
|
|
80
|
-
_deps: 0,
|
|
81
|
-
_dispose: unwatch
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function useVRouter(...args) {
|
|
85
|
-
if (typeof args[0] !== "string") {
|
|
86
|
-
args.unshift(inject(virouSymbol, useId()));
|
|
87
|
-
}
|
|
88
|
-
const [key, routes = [], options = {}] = args;
|
|
89
|
-
if (!key || typeof key !== "string") {
|
|
90
|
-
throw new TypeError(`[virou] [useVRouter] key must be a string: ${key}`);
|
|
91
|
-
}
|
|
92
|
-
provide(virouSymbol, key);
|
|
93
|
-
const vm = getCurrentInstance();
|
|
94
|
-
if (!vm) {
|
|
95
|
-
throw new TypeError("[virou] [useVRouter] useVRouter must be called in setup()");
|
|
96
|
-
}
|
|
97
|
-
const virou = vm.proxy?.$virou;
|
|
98
|
-
if (!virou) {
|
|
99
|
-
throw new Error("[virou] [useVRouter] virou plugin not installed");
|
|
100
|
-
}
|
|
101
|
-
if (routes.length) {
|
|
102
|
-
if (virou.get(key)) {
|
|
103
|
-
throw new Error(`[virou] [useVRouter] router with key "${key}" already exists`);
|
|
104
|
-
}
|
|
105
|
-
virou.set(key, createVRouter(routes, options));
|
|
106
|
-
}
|
|
107
|
-
const router = virou.get(key);
|
|
108
|
-
if (!router) {
|
|
109
|
-
throw new Error(`[virou] [useVRouter] router with key "${key}" not found`);
|
|
110
|
-
}
|
|
111
|
-
router._deps++;
|
|
112
|
-
onScopeDispose(() => {
|
|
113
|
-
router._deps--;
|
|
114
|
-
if (router._deps === 0 && !router._isGlobal) {
|
|
115
|
-
router._dispose();
|
|
116
|
-
virou.delete(key);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
return {
|
|
120
|
-
route: router.route,
|
|
121
|
-
router: {
|
|
122
|
-
addRoute: (route) => {
|
|
123
|
-
registerRoutes(router.context, [route], router.routes);
|
|
124
|
-
},
|
|
125
|
-
replace: (path) => {
|
|
126
|
-
router.activePath.value = path;
|
|
127
|
-
},
|
|
128
|
-
_depthKey: Symbol.for(key)
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const VRouterView = defineComponent({
|
|
134
|
-
name: "VRouterView",
|
|
135
|
-
inheritAttrs: false,
|
|
136
|
-
props: {
|
|
137
|
-
routerKey: String,
|
|
138
|
-
keepAlive: { type: Boolean, default: false },
|
|
139
|
-
viewKey: { type: [String, Function] }
|
|
140
|
-
},
|
|
141
|
-
slots: Object,
|
|
142
|
-
setup(props, { slots, attrs }) {
|
|
143
|
-
const key = props.routerKey ?? inject(virouSymbol);
|
|
144
|
-
if (key === void 0) {
|
|
145
|
-
throw new Error("[virou] [VRouterView] routerKey is required");
|
|
146
|
-
}
|
|
147
|
-
const { route, router } = useVRouter(key);
|
|
148
|
-
const depth = inject(router._depthKey, 0);
|
|
149
|
-
provide(router._depthKey, depth + 1);
|
|
150
|
-
return () => {
|
|
151
|
-
const component = route.value._renderList?.[depth];
|
|
152
|
-
if (!component) {
|
|
153
|
-
return slots.default?.({ Component: null, route: route.value }) ?? null;
|
|
154
|
-
}
|
|
155
|
-
const vnodeKey = typeof props.viewKey === "function" ? props.viewKey(route.value, key) : props.viewKey ?? `${key}-${depth}-${route.value.path}`;
|
|
156
|
-
const suspenseVNode = h(
|
|
157
|
-
Suspense,
|
|
158
|
-
null,
|
|
159
|
-
{
|
|
160
|
-
default: () => h(component, { key: vnodeKey, ...attrs }),
|
|
161
|
-
fallback: () => slots.fallback?.({ route: route.value }) ?? null
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
const vnode = props.keepAlive ? h(KeepAlive, null, { default: () => suspenseVNode }) : suspenseVNode;
|
|
165
|
-
return slots.default?.({ Component: vnode, route: route.value }) ?? vnode;
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const virou = (app, options = {}) => {
|
|
171
|
-
const { routers } = options;
|
|
172
|
-
const map = /* @__PURE__ */ new Map();
|
|
173
|
-
app.config.globalProperties.$virou = map;
|
|
174
|
-
if (routers) {
|
|
175
|
-
for (const [key, router] of Object.entries(routers)) {
|
|
176
|
-
map.set(key, createVRouter(router.routes, { ...router.options, _isGlobal: true }));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export { VRouterView, createVRouter, useVRouter, virou, virouSymbol };
|