@vaadin/hilla-file-router 24.7.0-alpha2 → 24.7.0-alpha3
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/package.json +18 -16
- package/runtime/RouterConfigurationBuilder.d.ts +14 -2
- package/runtime/RouterConfigurationBuilder.d.ts.map +1 -1
- package/runtime/RouterConfigurationBuilder.js +73 -35
- package/runtime/RouterConfigurationBuilder.js.map +2 -2
- package/runtime/createMenuItems.js +1 -1
- package/vite-plugin.d.ts.map +1 -1
- package/vite-plugin.js +2 -1
- package/vite-plugin.js.map +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/hilla-file-router",
|
|
3
|
-
"version": "24.7.0-
|
|
3
|
+
"version": "24.7.0-alpha3",
|
|
4
4
|
"description": "Hilla file-based router",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -62,30 +62,32 @@
|
|
|
62
62
|
"react-router": "^7"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@esm-bundle/chai": "^4.3.4-fix.0",
|
|
66
65
|
"@types/chai-as-promised": "^7.1.8",
|
|
67
|
-
"@types/chai-fs": "^2.0.
|
|
66
|
+
"@types/chai-fs": "^2.0.5",
|
|
68
67
|
"@types/chai-like": "^1.1.3",
|
|
69
|
-
"@types/deep-equal-in-any-order": "^1.0.
|
|
70
|
-
"@types/mocha": "^10.0.
|
|
71
|
-
"@types/sinon": "^10.0.
|
|
68
|
+
"@types/deep-equal-in-any-order": "^1.0.4",
|
|
69
|
+
"@types/mocha": "^10.0.10",
|
|
70
|
+
"@types/sinon": "^10.0.20",
|
|
72
71
|
"@types/sinon-chai": "^3.2.12",
|
|
73
|
-
"chai
|
|
72
|
+
"chai": "^5.1.2",
|
|
73
|
+
"chai-as-promised": "^7.1.2",
|
|
74
74
|
"chai-deep-equal-ignore-undefined": "^1.1.1",
|
|
75
75
|
"chai-fs": "^2.0.0",
|
|
76
|
-
"chai-like": "^1.1.
|
|
76
|
+
"chai-like": "^1.1.3",
|
|
77
77
|
"deep-equal-in-any-order": "^2.0.6",
|
|
78
|
-
"mocha": "^10.2
|
|
79
|
-
"sinon": "^16.
|
|
78
|
+
"mocha": "^10.8.2",
|
|
79
|
+
"sinon": "^16.1.3",
|
|
80
80
|
"sinon-chai": "^3.7.0",
|
|
81
|
-
"type-fest": "^4.
|
|
81
|
+
"type-fest": "^4.30.2"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@
|
|
85
|
-
"@vaadin/hilla-
|
|
86
|
-
"@vaadin/hilla-react-
|
|
84
|
+
"@types/chai": "^5.0.1",
|
|
85
|
+
"@vaadin/hilla-generator-utils": "24.7.0-alpha3",
|
|
86
|
+
"@vaadin/hilla-react-auth": "24.7.0-alpha3",
|
|
87
|
+
"@vaadin/hilla-react-signals": "24.7.0-alpha3",
|
|
88
|
+
"c8": "^10.1.3",
|
|
87
89
|
"react": "^18.2.0",
|
|
88
|
-
"rollup": "^4.
|
|
89
|
-
"typescript": "5.
|
|
90
|
+
"rollup": "^4.21.0",
|
|
91
|
+
"typescript": "5.7.2"
|
|
90
92
|
}
|
|
91
93
|
}
|
|
@@ -7,8 +7,13 @@ interface RouteBase {
|
|
|
7
7
|
}
|
|
8
8
|
export type RouteList = readonly RouteObject[];
|
|
9
9
|
export type WritableRouteList = RouteObject[];
|
|
10
|
-
export type
|
|
11
|
-
|
|
10
|
+
export type RouteTransformerOptions<T> = Readonly<{
|
|
11
|
+
children?: RouteList;
|
|
12
|
+
original?: RouteObject;
|
|
13
|
+
overriding?: T;
|
|
14
|
+
dupe: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
export type RouteTransformer<T> = (opts: RouteTransformerOptions<T>) => RouteObject | undefined;
|
|
12
17
|
/**
|
|
13
18
|
* A builder for creating a Vaadin-specific router for React with
|
|
14
19
|
* authentication and server routes support.
|
|
@@ -54,6 +59,13 @@ export declare class RouterConfigurationBuilder {
|
|
|
54
59
|
* and the user is not authenticated.
|
|
55
60
|
*/
|
|
56
61
|
protect(redirectPath?: string): this;
|
|
62
|
+
/**
|
|
63
|
+
* Deeply updates the current list of routes with the given routes merging
|
|
64
|
+
* them in process.
|
|
65
|
+
*
|
|
66
|
+
* @param routes - A list of routes to merge with the current list.
|
|
67
|
+
* @param callback - A callback to transform the routes during the merge.
|
|
68
|
+
*/
|
|
57
69
|
update<T extends RouteBase>(routes: undefined, callback: RouteTransformer<undefined>): this;
|
|
58
70
|
update<T extends RouteBase>(routes: readonly T[], callback?: RouteTransformer<T>): this;
|
|
59
71
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouterConfigurationBuilder.d.ts","sourceRoot":"","sources":["../src/runtime/RouterConfigurationBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAwE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAGtH,OAAO,KAAK,EACV,aAAa,EAGb,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CAC5B;AAaD,MAAM,MAAM,SAAS,GAAG,SAAS,WAAW,EAAE,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,WAAW,EAAE,CAAC;AAE9C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"RouterConfigurationBuilder.d.ts","sourceRoot":"","sources":["../src/runtime/RouterConfigurationBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAwE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAGtH,OAAO,KAAK,EACV,aAAa,EAGb,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CAC5B;AAaD,MAAM,MAAM,SAAS,GAAG,SAAS,WAAW,EAAE,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,WAAW,EAAE,CAAC;AAE9C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,QAAQ,CAAC;IAChD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,UAAU,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,WAAW,GAAG,SAAS,CAAC;AAsBhG;;;GAGG;AACH,qBAAa,0BAA0B;;IAGrC;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIxC;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IAuCtD;;;;;;;;OAQG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAqCjE;;;;OAIG;IACH,UAAU,CAAC,eAAe,EAAE,aAAa,GAAG,IAAI;IA+FhD;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAUpC;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,SAAS,CAAC,GAAG,IAAI;IAC3F,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI;IAuHvF;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,mBAAmB;CAsFzD"}
|
|
@@ -9,8 +9,8 @@ function isReactRouteModule(module) {
|
|
|
9
9
|
}
|
|
10
10
|
return "default" in module && typeof module.default === "function" || "config" in module && typeof module.config === "object";
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
return
|
|
12
|
+
function createRouteKey(route) {
|
|
13
|
+
return `${route.path ?? ""}-${route.children ? "n" : "i"}`;
|
|
14
14
|
}
|
|
15
15
|
var RouteHandleFlags = /* @__PURE__ */ ((RouteHandleFlags2) => {
|
|
16
16
|
RouteHandleFlags2["FLOW_LAYOUT"] = "flowLayout";
|
|
@@ -43,7 +43,7 @@ class RouterConfigurationBuilder {
|
|
|
43
43
|
* @param routes - A list of routes to add to the current list.
|
|
44
44
|
*/
|
|
45
45
|
withFileRoutes(routes) {
|
|
46
|
-
return this.update(routes, (original, added, children) => {
|
|
46
|
+
return this.update(routes, ({ original, overriding: added, children }) => {
|
|
47
47
|
if (added) {
|
|
48
48
|
const { module, path, flowLayout } = added;
|
|
49
49
|
if (!isReactRouteModule(module)) {
|
|
@@ -91,8 +91,8 @@ class RouterConfigurationBuilder {
|
|
|
91
91
|
{ path: "*", element: createElement(component), handle: config },
|
|
92
92
|
{ index: true, element: createElement(component), handle: config }
|
|
93
93
|
];
|
|
94
|
-
this.update(fallbackRoutes, (original, added, children) => {
|
|
95
|
-
if (original && !getRouteHandleFlag(original, "ignoreFallback" /* IGNORE_FALLBACK */)) {
|
|
94
|
+
this.update(fallbackRoutes, ({ original, overriding: added, children, dupe }) => {
|
|
95
|
+
if (original && !getRouteHandleFlag(original, "ignoreFallback" /* IGNORE_FALLBACK */) && !dupe) {
|
|
96
96
|
if (!children) {
|
|
97
97
|
return original;
|
|
98
98
|
}
|
|
@@ -193,50 +193,88 @@ class RouterConfigurationBuilder {
|
|
|
193
193
|
* and the user is not authenticated.
|
|
194
194
|
*/
|
|
195
195
|
protect(redirectPath) {
|
|
196
|
-
this.update(void 0, (route,
|
|
196
|
+
this.update(void 0, ({ original: route, children }) => {
|
|
197
197
|
const finalRoute = protectRoute(route, redirectPath);
|
|
198
198
|
finalRoute.children = children;
|
|
199
199
|
return finalRoute;
|
|
200
200
|
});
|
|
201
201
|
return this;
|
|
202
202
|
}
|
|
203
|
-
update(routes, callback = (original, overriding, children) => ({
|
|
203
|
+
update(routes, callback = ({ original, overriding, children }) => ({
|
|
204
204
|
...original,
|
|
205
205
|
...overriding,
|
|
206
206
|
children
|
|
207
207
|
})) {
|
|
208
208
|
this.#modifiers.push(
|
|
209
|
-
(existingRoutes) =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
209
|
+
(existingRoutes) => (
|
|
210
|
+
// Going through the existing and added list of routes.
|
|
211
|
+
transformTree(
|
|
212
|
+
[existingRoutes, routes],
|
|
213
|
+
null,
|
|
214
|
+
([original, added], next) => {
|
|
215
|
+
if (original && added) {
|
|
216
|
+
const final = [];
|
|
217
|
+
const pathKeys = /* @__PURE__ */ new Set([...original.map(createRouteKey), ...added.map(createRouteKey)]);
|
|
218
|
+
for (const pathKey of pathKeys) {
|
|
219
|
+
const originalRoutes = original.filter((r) => createRouteKey(r) === pathKey);
|
|
220
|
+
const addedRoutes = added.filter((r) => createRouteKey(r) === pathKey);
|
|
221
|
+
if (addedRoutes.length > 1) {
|
|
222
|
+
throw new Error("Adding multiple routes with the same path is not allowed");
|
|
223
|
+
}
|
|
224
|
+
const addedRoute = addedRoutes[0];
|
|
225
|
+
if (originalRoutes.length > 0 && addedRoute) {
|
|
226
|
+
for (let i = 0; i < originalRoutes.length; i++) {
|
|
227
|
+
final.push(
|
|
228
|
+
callback({
|
|
229
|
+
original: originalRoutes[i],
|
|
230
|
+
overriding: addedRoute,
|
|
231
|
+
children: next([originalRoutes[i].children, addedRoute.children]),
|
|
232
|
+
dupe: i < originalRoutes.length - 1
|
|
233
|
+
}) ?? originalRoutes[i]
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
} else if (originalRoutes.length > 0) {
|
|
237
|
+
for (let i = 0; i < originalRoutes.length; i++) {
|
|
238
|
+
final.push(
|
|
239
|
+
callback({
|
|
240
|
+
original: originalRoutes[i],
|
|
241
|
+
children: next([originalRoutes[i].children, void 0]),
|
|
242
|
+
dupe: i < originalRoutes.length - 1
|
|
243
|
+
}) ?? originalRoutes[i]
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
const result = callback({
|
|
248
|
+
overriding: addedRoute,
|
|
249
|
+
children: next([void 0, addedRoute.children]),
|
|
250
|
+
dupe: false
|
|
251
|
+
});
|
|
252
|
+
if (result) {
|
|
253
|
+
final.push(result);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
230
256
|
}
|
|
257
|
+
return final.filter((r) => r != null);
|
|
258
|
+
} else if (original) {
|
|
259
|
+
return original.map(
|
|
260
|
+
(route) => callback({
|
|
261
|
+
original: route,
|
|
262
|
+
children: next([route.children, void 0]),
|
|
263
|
+
dupe: false
|
|
264
|
+
})
|
|
265
|
+
).filter((r) => r != null);
|
|
266
|
+
} else if (added) {
|
|
267
|
+
return added.map(
|
|
268
|
+
(route) => callback({
|
|
269
|
+
overriding: route,
|
|
270
|
+
children: next([void 0, route.children]),
|
|
271
|
+
dupe: false
|
|
272
|
+
})
|
|
273
|
+
).filter((r) => r != null);
|
|
231
274
|
}
|
|
232
|
-
return
|
|
233
|
-
} else if (original) {
|
|
234
|
-
return original.map((route) => callback(route, void 0, next([route.children, void 0]))).filter((r) => r != null);
|
|
235
|
-
} else if (added) {
|
|
236
|
-
return added.map((route) => callback(void 0, route, next([void 0, route.children]))).filter((r) => r != null);
|
|
275
|
+
return void 0;
|
|
237
276
|
}
|
|
238
|
-
|
|
239
|
-
}
|
|
277
|
+
)
|
|
240
278
|
)
|
|
241
279
|
);
|
|
242
280
|
return this;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/RouterConfigurationBuilder.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/consistent-type-assertions */\nimport { protectRoute } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement } from 'react';\nimport { createBrowserRouter, type IndexRouteObject, type NonIndexRouteObject, type RouteObject } from 'react-router';\nimport { convertComponentNameToTitle } from '../shared/convertComponentNameToTitle.js';\nimport { transformTree } from '../shared/transformTree.js';\nimport type {\n AgnosticRoute,\n Module,\n RouteModule,\n RouterBuildOptions,\n RouterConfiguration,\n ViewConfig,\n} from '../types.js';\n\ninterface RouteBase {\n path?: string;\n children?: readonly this[];\n}\n\nfunction isReactRouteModule(module?: Module): module is RouteModule<ComponentType> | undefined {\n if (!module) {\n return true;\n }\n\n return (\n ('default' in module && typeof module.default === 'function') ||\n ('config' in module && typeof module.config === 'object')\n );\n}\n\nexport type RouteList = readonly RouteObject[];\nexport type WritableRouteList = RouteObject[];\n\nexport type RouteTransformer<T> = (\n original: RouteObject | undefined,\n overriding: T | undefined,\n children?: RouteList,\n) => RouteObject | undefined;\n\nexport type RouteListSplittingRule = (route: RouteObject) => boolean;\n\ntype RoutesModifier = (routes: RouteList | undefined) => RouteList | undefined;\n\nfunction createRouteEntry<T extends RouteBase>(route: T): readonly [key: string, value: T] {\n return [`${route.path ?? ''}-${route.children ? 'n' : 'i'}`, route];\n}\n\nenum RouteHandleFlags {\n FLOW_LAYOUT = 'flowLayout',\n IGNORE_FALLBACK = 'ignoreFallback',\n SKIP_LAYOUTS = 'skipLayouts',\n}\n\nfunction getRouteHandleFlag<T extends RouteHandleFlags>(route: RouteObject, flag: T): boolean | undefined {\n if (typeof route.handle === 'object' && flag in route.handle) {\n return (route.handle as Record<T, boolean>)[flag];\n }\n\n return undefined;\n}\n\n/**\n * A builder for creating a Vaadin-specific router for React with\n * authentication and server routes support.\n */\nexport class RouterConfigurationBuilder {\n readonly #modifiers: RoutesModifier[] = [];\n\n /**\n * Adds the given routes to the current list of routes. All the routes are\n * deeply merged to preserve the path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withReactRoutes(routes: RouteList): this {\n return this.update(routes);\n }\n\n /**\n * Adds the given file routes to the current list of routes. All the routes\n * are transformed to React RouterObjects and deeply merged to preserve the\n * path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withFileRoutes(routes: readonly AgnosticRoute[]): this {\n return this.update(routes, (original, added, children) => {\n if (added) {\n const { module, path, flowLayout } = added;\n if (!isReactRouteModule(module)) {\n throw new Error(\n `The module for the \"${path}\" section doesn't have the React component exported by default or a ViewConfig object exported as \"config\"`,\n );\n }\n\n const element = module?.default ? createElement(module.default) : undefined;\n const handle = {\n ...module?.config,\n title: module?.config?.title ?? convertComponentNameToTitle(module?.default),\n flowLayout: module?.config?.flowLayout ?? flowLayout,\n };\n\n if (path === '' && !children) {\n return {\n ...original,\n element,\n handle,\n index: true,\n } as IndexRouteObject;\n }\n\n return {\n ...original,\n path: module?.config?.route ?? path,\n element,\n children,\n handle,\n } as NonIndexRouteObject;\n }\n\n return original;\n });\n }\n\n /**\n * Adds the given server route element to each branch of the current list of\n * routes.\n *\n * @param component - The React component to add to each branch of the\n * current list of routes.\n * @param config - An optional configuration that will be applied to\n * each fallback component.\n */\n withFallback(component: ComponentType, config?: ViewConfig): this {\n this.withLayout(component);\n\n // Fallback adds two routes, so that the index (empty path) has a fallback too\n const fallbackRoutes: RouteList = [\n { path: '*', element: createElement(component), handle: config },\n { index: true, element: createElement(component), handle: config },\n ];\n\n this.update(fallbackRoutes, (original, added, children) => {\n if (original && !getRouteHandleFlag(original, RouteHandleFlags.IGNORE_FALLBACK)) {\n if (!children) {\n return original;\n }\n\n const _fallback = [...fallbackRoutes];\n\n if (children.some(({ path }) => path === '*')) {\n _fallback.shift();\n }\n\n if (children.some(({ index: i, path }) => i ?? path?.includes('?'))) {\n _fallback.pop();\n }\n\n return {\n ...original,\n children: [...children, ..._fallback],\n } as RouteObject;\n }\n\n return added!;\n });\n\n return this;\n }\n\n /**\n * Adds the layoutComponent as the parent layout to views with the flowLayouts ViewConfiguration set.\n *\n * @param layoutComponent - layout component to use, usually Flow\n */\n withLayout(layoutComponent: ComponentType): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n type Accumulator<T extends RouteList> = Readonly<{\n server: T;\n client: T;\n ambivalent: T;\n }>;\n\n const result = transformTree<RouteList, Accumulator<RouteList>>(originalRoutes, null, (routes, next) =>\n // Split a single routes list onto three separate lists:\n // - A list of server routes\n // - A list of client routes\n // - A list of routes which will be moved to either server or client\n // list. It depends on the parent route.\n routes.reduce<Accumulator<WritableRouteList>>(\n (lists, route) => {\n const { server, client, ambivalent } = next(route.children ?? []);\n\n const flag = getRouteHandleFlag(route, RouteHandleFlags.FLOW_LAYOUT);\n\n // If the route has `flowLayout` flag explicitly enabled, it goes to\n // the server list. The children are also affected by the flag\n // unless they have it explicitly disabled.\n if (flag === true) {\n lists.server.push({\n ...route,\n children: server.length + ambivalent.length > 0 ? [...server, ...ambivalent] : undefined,\n } as RouteObject);\n } else if (server.length > 0) {\n // Even if the route doesn't have the flag, it goes to the server\n // list if any of the children has the flag enabled.\n lists.server.push({\n ...route,\n children: server,\n } as RouteObject);\n }\n\n // If the route has `flowLayout` flag explicitly disabled, it goes\n // to the client list. The route children are not affected by the\n // flag.\n if (flag === false || client.length > 0) {\n lists.client.push({\n ...route,\n children: client.length > 0 ? client : undefined,\n } as RouteObject);\n }\n\n // The route without the flag go to the `default` list. Then it will\n // be moved to either server or client list based on the parent\n // route.\n if (\n flag === undefined &&\n (lists.server.every(({ path }) => path !== route.path) || ambivalent.length > 0)\n ) {\n lists.ambivalent.push({\n ...route,\n children: ambivalent.length > 0 ? ambivalent : undefined,\n } as RouteObject);\n }\n\n return lists;\n },\n { server: [], client: [], ambivalent: [] },\n ),\n );\n\n return [\n ...(result.server.length\n ? [\n // The server routes are wrapped with the route that has a layout\n // element. It also has the `IGNORE_FALLBACK` flag to remove the\n // fallback route from reach.\n {\n element: createElement(layoutComponent),\n children: result.server as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n // The client routes are preserved without wrapping.\n ...result.client,\n // The ambivalent routes are considered as client routes.\n ...result.ambivalent,\n ];\n });\n\n return this;\n }\n\n /**\n * Protects all the routes that require authentication. For more details see\n * {@link @vaadin/hilla-react-auth#protectRoutes} function.\n *\n * @param redirectPath - the path to redirect to if the route is protected\n * and the user is not authenticated.\n */\n protect(redirectPath?: string): this {\n this.update(undefined, (route, _, children) => {\n const finalRoute = protectRoute(route!, redirectPath);\n finalRoute.children = children as RouteObject[] | undefined;\n return finalRoute;\n });\n\n return this;\n }\n\n update<T extends RouteBase>(routes: undefined, callback: RouteTransformer<undefined>): this;\n update<T extends RouteBase>(routes: readonly T[], callback?: RouteTransformer<T>): this;\n update<T extends RouteBase>(\n routes: readonly T[] | undefined,\n callback: RouteTransformer<T | undefined> = (original, overriding, children) =>\n ({\n ...original,\n ...overriding,\n children,\n }) as RouteObject,\n ): this {\n this.#modifiers.push((existingRoutes) =>\n transformTree<[RouteList | undefined, readonly T[] | undefined], RouteList | undefined>(\n [existingRoutes, routes],\n null,\n ([original, added], next) => {\n if (original && added) {\n const originalMap = new Map(original.map((route) => createRouteEntry(route)));\n const addedMap = new Map(added.map((route) => createRouteEntry(route)));\n\n const paths = new Set([...originalMap.keys(), ...addedMap.keys()]);\n\n for (const path of paths) {\n const originalRoute = originalMap.get(path);\n const addedRoute = addedMap.get(path);\n\n let route: RouteObject | undefined;\n if (originalRoute && addedRoute) {\n route = callback(originalRoute, addedRoute, next([originalRoute.children, addedRoute.children]));\n } else if (originalRoute) {\n route = callback(originalRoute, undefined, next([originalRoute.children, undefined]));\n } else {\n route = callback(undefined, addedRoute, next([undefined, addedRoute!.children]));\n }\n\n if (route) {\n originalMap.set(path, route);\n }\n }\n\n return [...originalMap.values()];\n } else if (original) {\n return original\n .map((route) => callback(route, undefined, next([route.children, undefined])))\n .filter((r) => r != null);\n } else if (added) {\n return added\n .map((route) => callback(undefined, route, next([undefined, route.children])))\n .filter((r) => r != null);\n }\n\n return undefined;\n },\n ),\n );\n return this;\n }\n\n /**\n * Builds the router with the current list of routes.\n */\n build(options?: RouterBuildOptions): RouterConfiguration {\n this.#withLayoutSkipping();\n const routes = this.#modifiers.reduce<RouteList | undefined>((acc, mod) => mod(acc) ?? acc, undefined) ?? [];\n\n return {\n routes,\n router: createBrowserRouter([...routes], { basename: new URL(document.baseURI).pathname, ...options }),\n };\n }\n\n #withLayoutSkipping(): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n type Accumulator<T extends RouteList> = Readonly<{\n skipped: T;\n regular: T;\n }>;\n\n const result = transformTree<RouteList, Accumulator<RouteList>>(originalRoutes, null, (routes, next) =>\n // Split a single routes list onto two separate lists.\n routes.reduce<Accumulator<WritableRouteList>>(\n (lists, route) => {\n // If the route has `skipLayout` flag, it goes to the `skipped` list.\n if (getRouteHandleFlag(route, RouteHandleFlags.SKIP_LAYOUTS)) {\n lists.skipped.push(route);\n return lists;\n }\n\n // If the route is leaf, it goes to the `regular` list.\n if (!route.children?.length) {\n lists.regular.push(route);\n return lists;\n }\n\n // As of children, we have to split them into two lists as well.\n const { skipped, regular } = next(route.children ?? []);\n\n // If we have `skipped` list of children, we have to remove the\n // `element` property of the router to prevent the layout from\n // rendering. Then, we add the current route to the `skipped` list.\n if (skipped.length > 0) {\n const { element, ...rest } = route;\n\n lists.skipped.push({\n ...rest,\n children: skipped,\n } as RouteObject);\n }\n\n // In case of `regular` children, we just add the current route to\n // the `regular` list if there are any children.\n if (regular.length > 0) {\n lists.regular.push({\n ...route,\n children: regular,\n } as RouteObject);\n }\n\n return lists;\n },\n { skipped: [], regular: [] },\n ),\n );\n\n // We don't need a fallback for the skipped routes, so we have to wrap\n // them with the route with the `IGNORE_FALLBACK` flag.\n return [\n ...(result.skipped.length\n ? [\n {\n children: result.skipped as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n ...result.regular,\n ];\n });\n\n return this;\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAA6B,qBAAqB;AAClD,SAAS,2BAA8F;AACvG,SAAS,mCAAmC;AAC5C,SAAS,qBAAqB;AAe9B,SAAS,mBAAmB,QAAmE;AAC7F,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SACG,aAAa,UAAU,OAAO,OAAO,YAAY,cACjD,YAAY,UAAU,OAAO,OAAO,WAAW;AAEpD;
|
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/consistent-type-assertions */\nimport { protectRoute } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement } from 'react';\nimport { createBrowserRouter, type IndexRouteObject, type NonIndexRouteObject, type RouteObject } from 'react-router';\nimport { convertComponentNameToTitle } from '../shared/convertComponentNameToTitle.js';\nimport { transformTree } from '../shared/transformTree.js';\nimport type {\n AgnosticRoute,\n Module,\n RouteModule,\n RouterBuildOptions,\n RouterConfiguration,\n ViewConfig,\n} from '../types.js';\n\ninterface RouteBase {\n path?: string;\n children?: readonly this[];\n}\n\nfunction isReactRouteModule(module?: Module): module is RouteModule<ComponentType> | undefined {\n if (!module) {\n return true;\n }\n\n return (\n ('default' in module && typeof module.default === 'function') ||\n ('config' in module && typeof module.config === 'object')\n );\n}\n\nexport type RouteList = readonly RouteObject[];\nexport type WritableRouteList = RouteObject[];\n\nexport type RouteTransformerOptions<T> = Readonly<{\n children?: RouteList;\n original?: RouteObject;\n overriding?: T;\n dupe: boolean;\n}>;\n\nexport type RouteTransformer<T> = (opts: RouteTransformerOptions<T>) => RouteObject | undefined;\n\ntype RoutesModifier = (routes: RouteList | undefined) => RouteList | undefined;\n\nfunction createRouteKey<T extends RouteBase>(route: T): string {\n return `${route.path ?? ''}-${route.children ? 'n' : 'i'}`;\n}\n\nenum RouteHandleFlags {\n FLOW_LAYOUT = 'flowLayout',\n IGNORE_FALLBACK = 'ignoreFallback',\n SKIP_LAYOUTS = 'skipLayouts',\n}\n\nfunction getRouteHandleFlag<T extends RouteHandleFlags>(route: RouteObject, flag: T): boolean | undefined {\n if (typeof route.handle === 'object' && flag in route.handle) {\n return (route.handle as Record<T, boolean>)[flag];\n }\n\n return undefined;\n}\n\n/**\n * A builder for creating a Vaadin-specific router for React with\n * authentication and server routes support.\n */\nexport class RouterConfigurationBuilder {\n readonly #modifiers: RoutesModifier[] = [];\n\n /**\n * Adds the given routes to the current list of routes. All the routes are\n * deeply merged to preserve the path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withReactRoutes(routes: RouteList): this {\n return this.update(routes);\n }\n\n /**\n * Adds the given file routes to the current list of routes. All the routes\n * are transformed to React RouterObjects and deeply merged to preserve the\n * path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withFileRoutes(routes: readonly AgnosticRoute[]): this {\n return this.update(routes, ({ original, overriding: added, children }) => {\n if (added) {\n const { module, path, flowLayout } = added;\n if (!isReactRouteModule(module)) {\n throw new Error(\n `The module for the \"${path}\" section doesn't have the React component exported by default or a ViewConfig object exported as \"config\"`,\n );\n }\n\n const element = module?.default ? createElement(module.default) : undefined;\n const handle = {\n ...module?.config,\n title: module?.config?.title ?? convertComponentNameToTitle(module?.default),\n flowLayout: module?.config?.flowLayout ?? flowLayout,\n };\n\n if (path === '' && !children) {\n return {\n ...original,\n element,\n handle,\n index: true,\n } as IndexRouteObject;\n }\n\n return {\n ...original,\n path: module?.config?.route ?? path,\n element,\n children,\n handle,\n } as NonIndexRouteObject;\n }\n\n return original;\n });\n }\n\n /**\n * Adds the given server route element to each branch of the current list of\n * routes.\n *\n * @param component - The React component to add to each branch of the\n * current list of routes.\n * @param config - An optional configuration that will be applied to\n * each fallback component.\n */\n withFallback(component: ComponentType, config?: ViewConfig): this {\n this.withLayout(component);\n\n // Fallback adds two routes, so that the index (empty path) has a fallback too\n const fallbackRoutes: RouteList = [\n { path: '*', element: createElement(component), handle: config },\n { index: true, element: createElement(component), handle: config },\n ];\n\n this.update(fallbackRoutes, ({ original, overriding: added, children, dupe }) => {\n if (original && !getRouteHandleFlag(original, RouteHandleFlags.IGNORE_FALLBACK) && !dupe) {\n if (!children) {\n return original;\n }\n\n const _fallback = [...fallbackRoutes];\n\n if (children.some(({ path }) => path === '*')) {\n _fallback.shift();\n }\n\n if (children.some(({ index: i, path }) => i ?? path?.includes('?'))) {\n _fallback.pop();\n }\n\n return {\n ...original,\n children: [...children, ..._fallback],\n } as RouteObject;\n }\n\n return added!;\n });\n\n return this;\n }\n\n /**\n * Adds the layoutComponent as the parent layout to views with the flowLayouts ViewConfiguration set.\n *\n * @param layoutComponent - layout component to use, usually Flow\n */\n withLayout(layoutComponent: ComponentType): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n type Accumulator<T extends RouteList> = Readonly<{\n server: T;\n client: T;\n ambivalent: T;\n }>;\n\n const result = transformTree<RouteList, Accumulator<RouteList>>(originalRoutes, null, (routes, next) =>\n // Split a single routes list onto three separate lists:\n // - A list of server routes\n // - A list of client routes\n // - A list of routes which will be moved to either server or client\n // list. It depends on the parent route.\n routes.reduce<Accumulator<WritableRouteList>>(\n (lists, route) => {\n const { server, client, ambivalent } = next(route.children ?? []);\n\n const flag = getRouteHandleFlag(route, RouteHandleFlags.FLOW_LAYOUT);\n\n // If the route has `flowLayout` flag explicitly enabled, it goes to\n // the server list. The children are also affected by the flag\n // unless they have it explicitly disabled.\n if (flag === true) {\n lists.server.push({\n ...route,\n children: server.length + ambivalent.length > 0 ? [...server, ...ambivalent] : undefined,\n } as RouteObject);\n } else if (server.length > 0) {\n // Even if the route doesn't have the flag, it goes to the server\n // list if any of the children has the flag enabled.\n lists.server.push({\n ...route,\n children: server,\n } as RouteObject);\n }\n\n // If the route has `flowLayout` flag explicitly disabled, it goes\n // to the client list. The route children are not affected by the\n // flag.\n if (flag === false || client.length > 0) {\n lists.client.push({\n ...route,\n children: client.length > 0 ? client : undefined,\n } as RouteObject);\n }\n\n // The route without the flag go to the `default` list. Then it will\n // be moved to either server or client list based on the parent\n // route.\n if (\n flag === undefined &&\n (lists.server.every(({ path }) => path !== route.path) || ambivalent.length > 0)\n ) {\n lists.ambivalent.push({\n ...route,\n children: ambivalent.length > 0 ? ambivalent : undefined,\n } as RouteObject);\n }\n\n return lists;\n },\n { server: [], client: [], ambivalent: [] },\n ),\n );\n\n return [\n ...(result.server.length\n ? [\n // The server routes are wrapped with the route that has a layout\n // element. It also has the `IGNORE_FALLBACK` flag to remove the\n // fallback route from reach.\n {\n element: createElement(layoutComponent),\n children: result.server as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n // The client routes are preserved without wrapping.\n ...result.client,\n // The ambivalent routes are considered as client routes.\n ...result.ambivalent,\n ];\n });\n\n return this;\n }\n\n /**\n * Protects all the routes that require authentication. For more details see\n * {@link @vaadin/hilla-react-auth#protectRoutes} function.\n *\n * @param redirectPath - the path to redirect to if the route is protected\n * and the user is not authenticated.\n */\n protect(redirectPath?: string): this {\n this.update(undefined, ({ original: route, children }) => {\n const finalRoute = protectRoute(route!, redirectPath);\n finalRoute.children = children as RouteObject[] | undefined;\n return finalRoute;\n });\n\n return this;\n }\n\n /**\n * Deeply updates the current list of routes with the given routes merging\n * them in process.\n *\n * @param routes - A list of routes to merge with the current list.\n * @param callback - A callback to transform the routes during the merge.\n */\n update<T extends RouteBase>(routes: undefined, callback: RouteTransformer<undefined>): this;\n update<T extends RouteBase>(routes: readonly T[], callback?: RouteTransformer<T>): this;\n update<T extends RouteBase>(\n routes: readonly T[] | undefined,\n callback: RouteTransformer<T | undefined> = ({ original, overriding, children }) =>\n ({\n ...original,\n ...overriding,\n children,\n }) as RouteObject,\n ): this {\n this.#modifiers.push((existingRoutes) =>\n // Going through the existing and added list of routes.\n transformTree<readonly [RouteList | undefined, readonly T[] | undefined], RouteList | undefined>(\n [existingRoutes, routes],\n null,\n ([original, added], next) => {\n if (original && added) {\n // If we have both original and added routes, we have to merge them.\n const final: Array<RouteObject | undefined> = [];\n const pathKeys = new Set([...original.map(createRouteKey), ...added.map(createRouteKey)]);\n\n for (const pathKey of pathKeys) {\n // We can have multiple routes with the same path, so we have to\n // consider all of them.\n const originalRoutes = original.filter((r) => createRouteKey(r) === pathKey);\n // We can have only one route with the same path in the added list.\n const addedRoutes = added.filter((r) => createRouteKey(r) === pathKey);\n\n if (addedRoutes.length > 1) {\n throw new Error('Adding multiple routes with the same path is not allowed');\n }\n\n const addedRoute = addedRoutes[0] as T | undefined;\n\n if (originalRoutes.length > 0 && addedRoute) {\n // In case we have both original and added routes, we run\n // the callback for each original route in pair with the added\n // route. To make the difference, we flag all the routes except\n // the last one as `dupe`.\n //\n // Why the last one is not `dupe`? According to the\n // `react-router` logic, the last route is the fallback for all\n // routes with the same path. So, if we apply callback to it,\n // we implicitly apply it to all other routes with the same\n // path.\n //\n // In case this logic doesn't work, the user can apply the\n // callback without considering the `dupe` flag.\n for (let i = 0; i < originalRoutes.length; i++) {\n final.push(\n callback({\n original: originalRoutes[i],\n overriding: addedRoute,\n children: next([originalRoutes[i].children, addedRoute.children]),\n dupe: i < originalRoutes.length - 1,\n }) ?? originalRoutes[i],\n );\n }\n } else if (originalRoutes.length > 0) {\n // In case we don't have the added route with the path being\n // processed, we run the callback for each original route.\n for (let i = 0; i < originalRoutes.length; i++) {\n final.push(\n callback({\n original: originalRoutes[i],\n children: next([originalRoutes[i].children, undefined]),\n dupe: i < originalRoutes.length - 1,\n }) ?? originalRoutes[i],\n );\n }\n } else {\n // In case we don't have the original route with the path being\n // processed, we run the callback for only the added route.\n const result = callback({\n overriding: addedRoute,\n children: next([undefined, addedRoute!.children]),\n dupe: false,\n });\n\n if (result) {\n final.push(result);\n }\n }\n }\n\n return final.filter((r) => r != null);\n } else if (original) {\n // If we have only original routes, we run the callback for each\n // original route.\n return original\n .map((route) =>\n callback({\n original: route,\n children: next([route.children, undefined]),\n dupe: false,\n }),\n )\n .filter((r) => r != null);\n } else if (added) {\n // If we have only added routes, we run the callback for each added\n // route.\n return added\n .map((route) =>\n callback({\n overriding: route,\n children: next([undefined, route.children]),\n dupe: false,\n }),\n )\n .filter((r) => r != null);\n }\n\n return undefined;\n },\n ),\n );\n return this;\n }\n\n /**\n * Builds the router with the current list of routes.\n */\n build(options?: RouterBuildOptions): RouterConfiguration {\n this.#withLayoutSkipping();\n const routes = this.#modifiers.reduce<RouteList | undefined>((acc, mod) => mod(acc) ?? acc, undefined) ?? [];\n\n return {\n routes,\n router: createBrowserRouter([...routes], { basename: new URL(document.baseURI).pathname, ...options }),\n };\n }\n\n #withLayoutSkipping(): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n type Accumulator<T extends RouteList> = Readonly<{\n skipped: T;\n regular: T;\n }>;\n\n const result = transformTree<RouteList, Accumulator<RouteList>>(originalRoutes, null, (routes, next) =>\n // Split a single routes list onto two separate lists.\n routes.reduce<Accumulator<WritableRouteList>>(\n (lists, route) => {\n // If the route has `skipLayout` flag, it goes to the `skipped` list.\n if (getRouteHandleFlag(route, RouteHandleFlags.SKIP_LAYOUTS)) {\n lists.skipped.push(route);\n return lists;\n }\n\n // If the route is leaf, it goes to the `regular` list.\n if (!route.children?.length) {\n lists.regular.push(route);\n return lists;\n }\n\n // As of children, we have to split them into two lists as well.\n const { skipped, regular } = next(route.children ?? []);\n\n // If we have `skipped` list of children, we have to remove the\n // `element` property of the router to prevent the layout from\n // rendering. Then, we add the current route to the `skipped` list.\n if (skipped.length > 0) {\n const { element, ...rest } = route;\n\n lists.skipped.push({\n ...rest,\n children: skipped,\n } as RouteObject);\n }\n\n // In case of `regular` children, we just add the current route to\n // the `regular` list if there are any children.\n if (regular.length > 0) {\n lists.regular.push({\n ...route,\n children: regular,\n } as RouteObject);\n }\n\n return lists;\n },\n { skipped: [], regular: [] },\n ),\n );\n\n // We don't need a fallback for the skipped routes, so we have to wrap\n // them with the route with the `IGNORE_FALLBACK` flag.\n return [\n ...(result.skipped.length\n ? [\n {\n children: result.skipped as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n ...result.regular,\n ];\n });\n\n return this;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["RouteHandleFlags"]
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ function __REGISTER__(feature, vaadinObj = window.Vaadin ??= {}) {
|
|
|
2
2
|
vaadinObj.registrations ??= [];
|
|
3
3
|
vaadinObj.registrations.push({
|
|
4
4
|
is: feature ? `${"@vaadin/hilla-file-router"}/${feature}` : "@vaadin/hilla-file-router",
|
|
5
|
-
version: "24.7.0-
|
|
5
|
+
version: "24.7.0-alpha3"
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
8
|
import { signal } from "@vaadin/hilla-react-signals";
|
package/vite-plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["src/vite-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,MAAM,CAAC;AAM3C;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,0BAA0B,CAAC,EACjD,QAA4B,EAC5B,YAAoC,EACpC,UAA6B,EAC7B,SAAiB,EACjB,KAAa,GACd,GAAE,aAAkB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["src/vite-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,MAAM,CAAC;AAM3C;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,0BAA0B,CAAC,EACjD,QAA4B,EAC5B,YAAoC,EACpC,UAA6B,EAC7B,SAAiB,EACjB,KAAa,GACd,GAAE,aAAkB,GAAG,MAAM,CAgG7B"}
|
package/vite-plugin.js
CHANGED
|
@@ -59,7 +59,8 @@ function vitePluginFileSystemRouter({
|
|
|
59
59
|
},
|
|
60
60
|
transform(code, id) {
|
|
61
61
|
let modifiedCode = code;
|
|
62
|
-
|
|
62
|
+
const viewsDirUsingSlashes = fileURLToPath(_viewsDir).replaceAll("\\", "/");
|
|
63
|
+
if (id.startsWith(viewsDirUsingSlashes) && !basename(id).startsWith("_")) {
|
|
63
64
|
if (isDevMode) {
|
|
64
65
|
const injectionPattern = /import\.meta\.hot\.accept[\s\S]+if\s\(!nextExports\)\s+return;/gu;
|
|
65
66
|
if (injectionPattern.test(modifiedCode)) {
|
package/vite-plugin.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["src/vite-plugin.ts"],
|
|
4
|
-
"sourcesContent": ["import { basename } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport type { TransformResult } from 'rollup';\nimport type { Logger, Plugin } from 'vite';\nimport { generateRuntimeFiles, type RuntimeFileUrls } from './vite-plugin/generateRuntimeFiles.js';\n\nconst INJECTION =\n \"if (Object.keys(nextExports).length === 2 && 'default' in nextExports && 'config' in nextExports) {nextExports = { ...nextExports, config: currentExports.config };}\";\n\n/**\n * The options for the Vite file-based router plugin.\n */\nexport type PluginOptions = Readonly<{\n /**\n * The base directory for the router. The folders and files in this directory\n * will be used as route paths.\n *\n * @defaultValue `frontend/views`\n */\n viewsDir?: URL | string;\n /**\n * The directory where the generated view file will be stored.\n *\n * @defaultValue `frontend/generated`\n */\n generatedDir?: URL | string;\n /**\n * The list of extensions that will be collected as routes of the file-based\n * router.\n *\n * @defaultValue `['.tsx', '.jsx']`\n */\n extensions?: readonly string[];\n /**\n * The flag to indicate whether the plugin is running in development mode.\n *\n * @defaultValue `false`\n */\n isDevMode?: boolean;\n /**\n * The flag to indicate whether to output debug information\n *\n * @defaultValue `false`\n */\n debug?: boolean;\n}>;\n\n/**\n * A Vite plugin that generates a router from the files in the specific directory.\n *\n * @param options - The plugin options.\n * @returns A Vite plugin.\n */\nexport default function vitePluginFileSystemRouter({\n viewsDir = 'frontend/views/',\n generatedDir = 'frontend/generated/',\n extensions = ['.tsx', '.jsx'],\n isDevMode = false,\n debug = false,\n}: PluginOptions = {}): Plugin {\n let _viewsDir: URL;\n let _outDir: URL;\n let _logger: Logger;\n let runtimeUrls: RuntimeFileUrls;\n\n return {\n name: 'vite-plugin-file-router',\n configResolved({ logger, root, build: { outDir } }) {\n const _root = pathToFileURL(root);\n const _generatedDir = new URL(generatedDir, _root);\n\n _viewsDir = new URL(viewsDir, _root);\n _outDir = pathToFileURL(outDir);\n _logger = logger;\n\n if (debug) {\n _logger.info(`The directory of route files: ${String(_viewsDir)}`);\n _logger.info(`The directory of generated files: ${String(_generatedDir)}`);\n _logger.info(`The output directory: ${String(_outDir)}`);\n }\n runtimeUrls = {\n json: new URL('file-routes.json', isDevMode ? _generatedDir : _outDir),\n code: new URL('file-routes.ts', _generatedDir),\n layouts: new URL('layouts.json', _generatedDir),\n };\n },\n async buildStart() {\n try {\n await generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger, debug);\n } catch (e: unknown) {\n _logger.error(String(e));\n }\n },\n configureServer(server) {\n const dir = fileURLToPath(_viewsDir);\n\n const changeListener = (file: string): void => {\n if (!file.startsWith(dir)) {\n if (file === fileURLToPath(runtimeUrls.json)) {\n server.hot.send({ type: 'custom', event: 'fs-route-update' });\n } else if (file !== fileURLToPath(runtimeUrls.layouts)) {\n // outside views folder, only changes to layouts file should trigger files generation\n return;\n }\n }\n\n generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger, debug).catch((e: unknown) =>\n _logger.error(String(e)),\n );\n };\n\n server.watcher.on('add', changeListener);\n server.watcher.on('change', changeListener);\n server.watcher.on('unlink', changeListener);\n },\n transform(code, id): Promise<TransformResult> | TransformResult {\n let modifiedCode = code;\n if (id.startsWith(
|
|
5
|
-
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,eAAe,qBAAqB;AAG7C,SAAS,4BAAkD;AAE3D,MAAM,YACJ;AA8Ca,SAAR,2BAA4C;AAAA,EACjD,WAAW;AAAA,EACX,eAAe;AAAA,EACf,aAAa,CAAC,QAAQ,MAAM;AAAA,EAC5B,YAAY;AAAA,EACZ,QAAQ;AACV,IAAmB,CAAC,GAAW;AAC7B,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,EAAE,QAAQ,MAAM,OAAO,EAAE,OAAO,EAAE,GAAG;AAClD,YAAM,QAAQ,cAAc,IAAI;AAChC,YAAM,gBAAgB,IAAI,IAAI,cAAc,KAAK;AAEjD,kBAAY,IAAI,IAAI,UAAU,KAAK;AACnC,gBAAU,cAAc,MAAM;AAC9B,gBAAU;AAEV,UAAI,OAAO;AACT,gBAAQ,KAAK,iCAAiC,OAAO,SAAS,CAAC,EAAE;AACjE,gBAAQ,KAAK,qCAAqC,OAAO,aAAa,CAAC,EAAE;AACzE,gBAAQ,KAAK,yBAAyB,OAAO,OAAO,CAAC,EAAE;AAAA,MACzD;AACA,oBAAc;AAAA,QACZ,MAAM,IAAI,IAAI,oBAAoB,YAAY,gBAAgB,OAAO;AAAA,QACrE,MAAM,IAAI,IAAI,kBAAkB,aAAa;AAAA,QAC7C,SAAS,IAAI,IAAI,gBAAgB,aAAa;AAAA,MAChD;AAAA,IACF;AAAA,IACA,MAAM,aAAa;AACjB,UAAI;AACF,cAAM,qBAAqB,WAAW,aAAa,YAAY,SAAS,KAAK;AAAA,MAC/E,SAAS,GAAY;AACnB,gBAAQ,MAAM,OAAO,CAAC,CAAC;AAAA,MACzB;AAAA,IACF;AAAA,IACA,gBAAgB,QAAQ;AACtB,YAAM,MAAM,cAAc,SAAS;AAEnC,YAAM,iBAAiB,CAAC,SAAuB;AAC7C,YAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,cAAI,SAAS,cAAc,YAAY,IAAI,GAAG;AAC5C,mBAAO,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,kBAAkB,CAAC;AAAA,UAC9D,WAAW,SAAS,cAAc,YAAY,OAAO,GAAG;AAEtD;AAAA,UACF;AAAA,QACF;AAEA,6BAAqB,WAAW,aAAa,YAAY,SAAS,KAAK,EAAE;AAAA,UAAM,CAAC,MAC9E,QAAQ,MAAM,OAAO,CAAC,CAAC;AAAA,QACzB;AAAA,MACF;AAEA,aAAO,QAAQ,GAAG,OAAO,cAAc;AACvC,aAAO,QAAQ,GAAG,UAAU,cAAc;AAC1C,aAAO,QAAQ,GAAG,UAAU,cAAc;AAAA,IAC5C;AAAA,IACA,UAAU,MAAM,IAAgD;AAC9D,UAAI,eAAe;AACnB,UAAI,GAAG,WAAW,
|
|
4
|
+
"sourcesContent": ["import { basename } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport type { TransformResult } from 'rollup';\nimport type { Logger, Plugin } from 'vite';\nimport { generateRuntimeFiles, type RuntimeFileUrls } from './vite-plugin/generateRuntimeFiles.js';\n\nconst INJECTION =\n \"if (Object.keys(nextExports).length === 2 && 'default' in nextExports && 'config' in nextExports) {nextExports = { ...nextExports, config: currentExports.config };}\";\n\n/**\n * The options for the Vite file-based router plugin.\n */\nexport type PluginOptions = Readonly<{\n /**\n * The base directory for the router. The folders and files in this directory\n * will be used as route paths.\n *\n * @defaultValue `frontend/views`\n */\n viewsDir?: URL | string;\n /**\n * The directory where the generated view file will be stored.\n *\n * @defaultValue `frontend/generated`\n */\n generatedDir?: URL | string;\n /**\n * The list of extensions that will be collected as routes of the file-based\n * router.\n *\n * @defaultValue `['.tsx', '.jsx']`\n */\n extensions?: readonly string[];\n /**\n * The flag to indicate whether the plugin is running in development mode.\n *\n * @defaultValue `false`\n */\n isDevMode?: boolean;\n /**\n * The flag to indicate whether to output debug information\n *\n * @defaultValue `false`\n */\n debug?: boolean;\n}>;\n\n/**\n * A Vite plugin that generates a router from the files in the specific directory.\n *\n * @param options - The plugin options.\n * @returns A Vite plugin.\n */\nexport default function vitePluginFileSystemRouter({\n viewsDir = 'frontend/views/',\n generatedDir = 'frontend/generated/',\n extensions = ['.tsx', '.jsx'],\n isDevMode = false,\n debug = false,\n}: PluginOptions = {}): Plugin {\n let _viewsDir: URL;\n let _outDir: URL;\n let _logger: Logger;\n let runtimeUrls: RuntimeFileUrls;\n\n return {\n name: 'vite-plugin-file-router',\n configResolved({ logger, root, build: { outDir } }) {\n const _root = pathToFileURL(root);\n const _generatedDir = new URL(generatedDir, _root);\n\n _viewsDir = new URL(viewsDir, _root);\n _outDir = pathToFileURL(outDir);\n _logger = logger;\n\n if (debug) {\n _logger.info(`The directory of route files: ${String(_viewsDir)}`);\n _logger.info(`The directory of generated files: ${String(_generatedDir)}`);\n _logger.info(`The output directory: ${String(_outDir)}`);\n }\n runtimeUrls = {\n json: new URL('file-routes.json', isDevMode ? _generatedDir : _outDir),\n code: new URL('file-routes.ts', _generatedDir),\n layouts: new URL('layouts.json', _generatedDir),\n };\n },\n async buildStart() {\n try {\n await generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger, debug);\n } catch (e: unknown) {\n _logger.error(String(e));\n }\n },\n configureServer(server) {\n const dir = fileURLToPath(_viewsDir);\n\n const changeListener = (file: string): void => {\n if (!file.startsWith(dir)) {\n if (file === fileURLToPath(runtimeUrls.json)) {\n server.hot.send({ type: 'custom', event: 'fs-route-update' });\n } else if (file !== fileURLToPath(runtimeUrls.layouts)) {\n // outside views folder, only changes to layouts file should trigger files generation\n return;\n }\n }\n\n generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger, debug).catch((e: unknown) =>\n _logger.error(String(e)),\n );\n };\n\n server.watcher.on('add', changeListener);\n server.watcher.on('change', changeListener);\n server.watcher.on('unlink', changeListener);\n },\n transform(code, id): Promise<TransformResult> | TransformResult {\n let modifiedCode = code;\n const viewsDirUsingSlashes = fileURLToPath(_viewsDir).replaceAll('\\\\', '/');\n if (id.startsWith(viewsDirUsingSlashes) && !basename(id).startsWith('_')) {\n if (isDevMode) {\n // To enable HMR for route files with exported configurations, we need\n // to address a limitation in `react-refresh`. This library requires\n // strict equality (`===`) for non-component exports. However, the\n // dynamic nature of HMR makes maintaining this equality between object\n // literals challenging.\n //\n // To work around this, we implement a strategy that preserves the\n // reference to the original configuration object (`currentExports.config`),\n // replacing any newly created configuration objects (`nextExports.config`)\n // with it. This ensures that the HMR mechanism perceives the\n // configuration as unchanged.\n const injectionPattern = /import\\.meta\\.hot\\.accept[\\s\\S]+if\\s\\(!nextExports\\)\\s+return;/gu;\n if (injectionPattern.test(modifiedCode)) {\n modifiedCode = `${modifiedCode.substring(0, injectionPattern.lastIndex)}${INJECTION}${modifiedCode.substring(\n injectionPattern.lastIndex,\n )}`;\n }\n } else {\n // In production mode, the function name is assigned as name to the function itself to avoid minification\n const functionNames = /export\\s+default\\s+(?:function\\s+)?(\\w+)/u.exec(modifiedCode);\n\n if (functionNames?.length) {\n const [, functionName] = functionNames;\n modifiedCode += `Object.defineProperty(${functionName}, 'name', { value: '${functionName}' });\\n`;\n }\n }\n\n return {\n code: modifiedCode,\n };\n }\n\n return undefined;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,eAAe,qBAAqB;AAG7C,SAAS,4BAAkD;AAE3D,MAAM,YACJ;AA8Ca,SAAR,2BAA4C;AAAA,EACjD,WAAW;AAAA,EACX,eAAe;AAAA,EACf,aAAa,CAAC,QAAQ,MAAM;AAAA,EAC5B,YAAY;AAAA,EACZ,QAAQ;AACV,IAAmB,CAAC,GAAW;AAC7B,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,EAAE,QAAQ,MAAM,OAAO,EAAE,OAAO,EAAE,GAAG;AAClD,YAAM,QAAQ,cAAc,IAAI;AAChC,YAAM,gBAAgB,IAAI,IAAI,cAAc,KAAK;AAEjD,kBAAY,IAAI,IAAI,UAAU,KAAK;AACnC,gBAAU,cAAc,MAAM;AAC9B,gBAAU;AAEV,UAAI,OAAO;AACT,gBAAQ,KAAK,iCAAiC,OAAO,SAAS,CAAC,EAAE;AACjE,gBAAQ,KAAK,qCAAqC,OAAO,aAAa,CAAC,EAAE;AACzE,gBAAQ,KAAK,yBAAyB,OAAO,OAAO,CAAC,EAAE;AAAA,MACzD;AACA,oBAAc;AAAA,QACZ,MAAM,IAAI,IAAI,oBAAoB,YAAY,gBAAgB,OAAO;AAAA,QACrE,MAAM,IAAI,IAAI,kBAAkB,aAAa;AAAA,QAC7C,SAAS,IAAI,IAAI,gBAAgB,aAAa;AAAA,MAChD;AAAA,IACF;AAAA,IACA,MAAM,aAAa;AACjB,UAAI;AACF,cAAM,qBAAqB,WAAW,aAAa,YAAY,SAAS,KAAK;AAAA,MAC/E,SAAS,GAAY;AACnB,gBAAQ,MAAM,OAAO,CAAC,CAAC;AAAA,MACzB;AAAA,IACF;AAAA,IACA,gBAAgB,QAAQ;AACtB,YAAM,MAAM,cAAc,SAAS;AAEnC,YAAM,iBAAiB,CAAC,SAAuB;AAC7C,YAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,cAAI,SAAS,cAAc,YAAY,IAAI,GAAG;AAC5C,mBAAO,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,kBAAkB,CAAC;AAAA,UAC9D,WAAW,SAAS,cAAc,YAAY,OAAO,GAAG;AAEtD;AAAA,UACF;AAAA,QACF;AAEA,6BAAqB,WAAW,aAAa,YAAY,SAAS,KAAK,EAAE;AAAA,UAAM,CAAC,MAC9E,QAAQ,MAAM,OAAO,CAAC,CAAC;AAAA,QACzB;AAAA,MACF;AAEA,aAAO,QAAQ,GAAG,OAAO,cAAc;AACvC,aAAO,QAAQ,GAAG,UAAU,cAAc;AAC1C,aAAO,QAAQ,GAAG,UAAU,cAAc;AAAA,IAC5C;AAAA,IACA,UAAU,MAAM,IAAgD;AAC9D,UAAI,eAAe;AACnB,YAAM,uBAAuB,cAAc,SAAS,EAAE,WAAW,MAAM,GAAG;AAC1E,UAAI,GAAG,WAAW,oBAAoB,KAAK,CAAC,SAAS,EAAE,EAAE,WAAW,GAAG,GAAG;AACxE,YAAI,WAAW;AAYb,gBAAM,mBAAmB;AACzB,cAAI,iBAAiB,KAAK,YAAY,GAAG;AACvC,2BAAe,GAAG,aAAa,UAAU,GAAG,iBAAiB,SAAS,CAAC,GAAG,SAAS,GAAG,aAAa;AAAA,cACjG,iBAAiB;AAAA,YACnB,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AAEL,gBAAM,gBAAgB,4CAA4C,KAAK,YAAY;AAEnF,cAAI,eAAe,QAAQ;AACzB,kBAAM,CAAC,EAAE,YAAY,IAAI;AACzB,4BAAgB,yBAAyB,YAAY,uBAAuB,YAAY;AAAA;AAAA,UAC1F;AAAA,QACF;AAEA,eAAO;AAAA,UACL,MAAM;AAAA,QACR;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|