@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 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
- _renderList: Component[] | null
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 `_isGlobal` option:
315
+ You may also mark a router as global at runtime by passing the `isGlobal` option:
316
316
 
317
317
  ```ts
318
- useVRouter(routes, { _isGlobal: true })
318
+ useVRouter(routes, { isGlobal: true })
319
319
  ```
320
320
 
321
321
  That router will stay registered even after components that use it unmount.
@@ -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.0",
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.mts",
26
- "default": "./dist/index.mjs"
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
27
  },
28
- "main": "./dist/index.mjs",
29
- "types": "./dist/index.d.mts",
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.6.1",
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": "unbuild"
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 };