next-vite-router 1.2.4 → 1.3.1
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 +27 -10
- package/dist/cli.cjs +66 -26
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +144 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +126 -121
- package/dist/plugin.cjs +63 -0
- package/dist/plugin.d.cts +12 -0
- package/dist/plugin.js +104 -107
- package/dist/{tree-DW5A1s6W.js → tree-DfnssFxU.js} +2 -2
- package/dist/tree-hc1dSMdb.cjs +10 -0
- package/package.json +21 -8
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ File-based routing for React + Vite.
|
|
|
4
4
|
|
|
5
5
|
Define routes with folders and let the package generate the
|
|
6
6
|
[React Router](https://reactrouter.com/) `RouteObject[]`. It does not replace
|
|
7
|
-
React Router, navigation, history,
|
|
7
|
+
React Router, navigation, history, or application state.
|
|
8
8
|
|
|
9
9
|
## Start here
|
|
10
10
|
|
|
@@ -31,6 +31,10 @@ export default defineConfig({
|
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
The plugin ships both ESM and CJS, so this works when `package.json` has no
|
|
35
|
+
`"type": "module"` (Vite 5 loads `vite.config.ts` with `require()` in that
|
|
36
|
+
case). You can also rename the file to `vite.config.mts` to force ESM.
|
|
37
|
+
|
|
34
38
|
Create your route tree:
|
|
35
39
|
|
|
36
40
|
```text
|
|
@@ -88,10 +92,12 @@ npm run dev
|
|
|
88
92
|
|
|
89
93
|
## Use React Router directly
|
|
90
94
|
|
|
91
|
-
`Router` is only a convenience wrapper around `useRoutes(routes)`.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
`Router` is only a convenience wrapper around `useRoutes(routes)`. The
|
|
96
|
+
lazy-loading behavior and `loadingFallback` configured through `configureRouter`
|
|
97
|
+
are read at render time, so they take effect even when `generateRoutes()` runs
|
|
98
|
+
at module scope before application setup finishes. Register middleware with
|
|
99
|
+
`registerMiddleware` *before* calling `generateRoutes()`, because route elements
|
|
100
|
+
are wrapped while the tree is built. You can keep using React Router APIs:
|
|
95
101
|
|
|
96
102
|
```tsx
|
|
97
103
|
import {
|
|
@@ -115,10 +121,18 @@ export default function App() {
|
|
|
115
121
|
}
|
|
116
122
|
```
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
Keep using React Router's navigation and hooks from `react-router-dom`
|
|
125
|
+
(`useNavigate`, `useLocation`, `Link`, `Outlet`). For parameters, import
|
|
126
|
+
`useParams` from the virtual module instead of `react-router-dom`: dynamic
|
|
127
|
+
`[id]` segments work with either hook, but named catch-all segments
|
|
128
|
+
(`[...slug]`, `[[...slug]]`) are only surfaced as `slug` through the package
|
|
129
|
+
`useParams`. React Router's own `useParams` returns them under `params["*"]`.
|
|
130
|
+
|
|
131
|
+
The generated `RouteObject[]` carries page, layout, and not-found elements only.
|
|
132
|
+
There is no file convention that produces React Router route `loader` or
|
|
133
|
+
`action` functions, and those data APIs run only under a data router
|
|
134
|
+
(`createBrowserRouter` + `RouterProvider`), not under `BrowserRouter` with
|
|
135
|
+
`useRoutes`. Fetch data inside your page components instead.
|
|
122
136
|
|
|
123
137
|
## File conventions
|
|
124
138
|
|
|
@@ -210,6 +224,9 @@ configureRouter({
|
|
|
210
224
|
});
|
|
211
225
|
```
|
|
212
226
|
|
|
227
|
+
The fallback is resolved when a route suspends during render, so the order of
|
|
228
|
+
`configureRouter` relative to `generateRoutes()` does not matter.
|
|
229
|
+
|
|
213
230
|
`enableLazyLoading: false` is available for compatibility and testing. It does
|
|
214
231
|
not turn Vite's asynchronous imports into synchronous imports.
|
|
215
232
|
|
|
@@ -234,7 +251,7 @@ replace React Router.
|
|
|
234
251
|
For an interactive setup:
|
|
235
252
|
|
|
236
253
|
```bash
|
|
237
|
-
npx next-vite-router
|
|
254
|
+
npx next-vite-router create
|
|
238
255
|
```
|
|
239
256
|
|
|
240
257
|
The CLI creates a Vite React project, installs the package and
|
package/dist/cli.cjs
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const commander = require("commander");
|
|
4
4
|
const node_child_process = require("node:child_process");
|
|
5
5
|
const child_process = require("child_process");
|
|
6
|
+
const fs$1 = require("node:fs");
|
|
7
|
+
const path$1 = require("node:path");
|
|
6
8
|
const prompts = require("prompts");
|
|
7
9
|
const fs = require("fs");
|
|
8
10
|
const path = require("path");
|
|
@@ -30,13 +32,13 @@ function detectPackageManager() {
|
|
|
30
32
|
if (fromUA) candidates.push(fromUA);
|
|
31
33
|
if (preferred && !candidates.includes(preferred)) candidates.push(preferred);
|
|
32
34
|
["pnpm", "bun", "yarn", "npm"].forEach((p) => {
|
|
33
|
-
const
|
|
34
|
-
if (!candidates.includes(
|
|
35
|
+
const pm = p;
|
|
36
|
+
if (!candidates.includes(pm)) candidates.push(pm);
|
|
35
37
|
});
|
|
36
38
|
let chosen = null;
|
|
37
|
-
for (const
|
|
38
|
-
if (isAvailable(
|
|
39
|
-
chosen =
|
|
39
|
+
for (const pm of candidates) {
|
|
40
|
+
if (isAvailable(pm)) {
|
|
41
|
+
chosen = pm;
|
|
40
42
|
break;
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -87,7 +89,7 @@ if (typeof process !== "undefined") {
|
|
|
87
89
|
const $ = {
|
|
88
90
|
enabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== "dumb" && (FORCE_COLOR != null && FORCE_COLOR !== "0" || isTTY)
|
|
89
91
|
};
|
|
90
|
-
function init
|
|
92
|
+
function init(x, y) {
|
|
91
93
|
let rgx = new RegExp(`\\x1b\\[${y}m`, "g");
|
|
92
94
|
let open = `\x1B[${x}m`, close = `\x1B[${y}m`;
|
|
93
95
|
return function(txt) {
|
|
@@ -95,10 +97,10 @@ function init$1(x, y) {
|
|
|
95
97
|
return open + (!!~("" + txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close;
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
|
-
const red = init
|
|
99
|
-
const green = init
|
|
100
|
-
const yellow = init
|
|
101
|
-
const cyan = init
|
|
100
|
+
const red = init(31, 39);
|
|
101
|
+
const green = init(32, 39);
|
|
102
|
+
const yellow = init(33, 39);
|
|
103
|
+
const cyan = init(36, 39);
|
|
102
104
|
const highlighter = {
|
|
103
105
|
error: red,
|
|
104
106
|
warn: yellow,
|
|
@@ -164,7 +166,6 @@ function updateAppTsConfig(projectDir, src) {
|
|
|
164
166
|
const aliasPath = src ? "./src/*" : "./*";
|
|
165
167
|
tsConfigApp.compilerOptions = {
|
|
166
168
|
...tsConfigApp.compilerOptions,
|
|
167
|
-
baseUrl: ".",
|
|
168
169
|
paths: {
|
|
169
170
|
...tsConfigApp.compilerOptions?.paths,
|
|
170
171
|
"@/*": [aliasPath]
|
|
@@ -194,12 +195,24 @@ function updateTsConfigJson(projectDir, src) {
|
|
|
194
195
|
if (!tsConfig.compilerOptions) {
|
|
195
196
|
tsConfig.compilerOptions = {};
|
|
196
197
|
}
|
|
197
|
-
tsConfig.compilerOptions.baseUrl = ".";
|
|
198
198
|
tsConfig.compilerOptions.paths = {
|
|
199
199
|
"@/*": [src ? "./src/*" : "./*"]
|
|
200
200
|
};
|
|
201
201
|
fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2), "utf-8");
|
|
202
202
|
}
|
|
203
|
+
function updateIndexHtml(projectDir, src) {
|
|
204
|
+
if (src) return;
|
|
205
|
+
const indexPath = path.join(projectDir, "index.html");
|
|
206
|
+
if (!fs.existsSync(indexPath)) return;
|
|
207
|
+
const content = fs.readFileSync(indexPath, "utf-8");
|
|
208
|
+
const updated = content.replace(
|
|
209
|
+
/(src\s*=\s*["'])\/src\/main\.tsx(["'])/,
|
|
210
|
+
"$1/main.tsx$2"
|
|
211
|
+
);
|
|
212
|
+
if (updated !== content) {
|
|
213
|
+
fs.writeFileSync(indexPath, updated, "utf-8");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
203
216
|
function createVirtualDTS(projectDir, useSrc) {
|
|
204
217
|
const targetDir = useSrc ? path.join(projectDir, "src") : projectDir;
|
|
205
218
|
if (useSrc && !fs.existsSync(targetDir)) {
|
|
@@ -374,7 +387,6 @@ function addTailwindToViteConfig(projectDir) {
|
|
|
374
387
|
}
|
|
375
388
|
writeViteConfig(projectDir, updatedContent);
|
|
376
389
|
}
|
|
377
|
-
const pm$1 = detectPackageManager();
|
|
378
390
|
function startNextViteRouterConfig({
|
|
379
391
|
projectDir = process.cwd(),
|
|
380
392
|
src,
|
|
@@ -382,16 +394,31 @@ function startNextViteRouterConfig({
|
|
|
382
394
|
}) {
|
|
383
395
|
startViteConfig(projectDir, src);
|
|
384
396
|
const srcPath = path.join(projectDir, "src");
|
|
385
|
-
if (
|
|
397
|
+
if (src) {
|
|
398
|
+
for (const entry of [
|
|
399
|
+
"App.tsx",
|
|
400
|
+
"App.css",
|
|
401
|
+
"index.css",
|
|
402
|
+
"main.tsx",
|
|
403
|
+
"assets"
|
|
404
|
+
]) {
|
|
405
|
+
const entryPath = path.join(srcPath, entry);
|
|
406
|
+
if (fs.existsSync(entryPath)) {
|
|
407
|
+
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
} else if (fs.existsSync(srcPath)) {
|
|
386
411
|
fs.rmSync(srcPath, { recursive: true, force: true });
|
|
387
412
|
}
|
|
388
413
|
updateTsConfigJson(projectDir, src);
|
|
389
414
|
updateAppTsConfig(projectDir, src);
|
|
390
415
|
createVirtualDTS(projectDir, src);
|
|
391
416
|
createMainTSX(projectDir, src);
|
|
417
|
+
updateIndexHtml(projectDir, src);
|
|
392
418
|
if (tailwindcss) {
|
|
393
419
|
logger.info("Setting up Tailwind CSS...");
|
|
394
|
-
const
|
|
420
|
+
const pm = detectPackageManager();
|
|
421
|
+
const addDevDepsCmd = pm.addDevDepsCommand([
|
|
395
422
|
"tailwindcss",
|
|
396
423
|
"@tailwindcss/vite"
|
|
397
424
|
]);
|
|
@@ -434,7 +461,7 @@ ${resolveConfig}
|
|
|
434
461
|
}
|
|
435
462
|
const pluginsRegex = /plugins\s*:\s*\[(.*?)\]/s;
|
|
436
463
|
const match = viteConfigContent.match(pluginsRegex);
|
|
437
|
-
const pluginString = "nextViteRouter()";
|
|
464
|
+
const pluginString = src ? "nextViteRouter()" : 'nextViteRouter({ pagesDir: "app" })';
|
|
438
465
|
if (match) {
|
|
439
466
|
const existing = match[1].trim();
|
|
440
467
|
const newPlugins = existing ? `${existing}, ${pluginString}` : pluginString;
|
|
@@ -451,9 +478,9 @@ ${resolveConfig}
|
|
|
451
478
|
}
|
|
452
479
|
writeViteConfig(projectDir, viteConfigContent);
|
|
453
480
|
}
|
|
454
|
-
const
|
|
455
|
-
const
|
|
456
|
-
"
|
|
481
|
+
const PROJECT_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
482
|
+
const create = new commander.Command().name("create").description(
|
|
483
|
+
"Create a new Vite project with next-vite-router configuration"
|
|
457
484
|
).action(async () => {
|
|
458
485
|
const projectNameResponse = await prompts(
|
|
459
486
|
{
|
|
@@ -470,6 +497,16 @@ const init = new commander.Command().name("init").description(
|
|
|
470
497
|
}
|
|
471
498
|
);
|
|
472
499
|
const projectName = projectNameResponse.projectName;
|
|
500
|
+
if (!PROJECT_NAME_RE.test(projectName)) {
|
|
501
|
+
logger.error(
|
|
502
|
+
"Invalid project name (letters, digits, '.', '_' and '-' only)."
|
|
503
|
+
);
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
if (fs$1.existsSync(path$1.resolve(projectName))) {
|
|
507
|
+
logger.error(`Directory "${projectName}" already exists.`);
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
473
510
|
const variantResponse = await prompts(
|
|
474
511
|
{
|
|
475
512
|
type: "select",
|
|
@@ -522,12 +559,10 @@ const init = new commander.Command().name("init").description(
|
|
|
522
559
|
}
|
|
523
560
|
);
|
|
524
561
|
const useTailwind = tailwindResponse.useTailwind;
|
|
562
|
+
const pm = detectPackageManager();
|
|
525
563
|
const createCommand = pm.createProjectCommand(projectName, variant);
|
|
526
564
|
logger.info(`Creating project "${projectName}" using ${pm.name}...`);
|
|
527
|
-
child_process.execSync(createCommand, {
|
|
528
|
-
stdio: ["pipe", "inherit", "inherit"],
|
|
529
|
-
input: "n\n"
|
|
530
|
-
});
|
|
565
|
+
child_process.execSync(createCommand, { stdio: "inherit" });
|
|
531
566
|
logger.info("Installing dependencies...");
|
|
532
567
|
child_process.execSync(pm.installCommand, { stdio: "inherit", cwd: projectName });
|
|
533
568
|
logger.info(
|
|
@@ -548,13 +583,18 @@ const init = new commander.Command().name("init").description(
|
|
|
548
583
|
Project "${projectName}" is ready!
|
|
549
584
|
`);
|
|
550
585
|
});
|
|
551
|
-
const version = "1.
|
|
586
|
+
const version = "1.3.1";
|
|
552
587
|
const pkg = {
|
|
553
588
|
version
|
|
554
589
|
};
|
|
555
590
|
async function main() {
|
|
556
591
|
const program = new commander.Command();
|
|
557
|
-
program.name("
|
|
558
|
-
|
|
592
|
+
program.name("next-vite-router").version(pkg.version).addCommand(create);
|
|
593
|
+
try {
|
|
594
|
+
await program.parseAsync(process.argv);
|
|
595
|
+
} catch (e) {
|
|
596
|
+
logger.error(e instanceof Error ? e.message : String(e));
|
|
597
|
+
process.exit(1);
|
|
598
|
+
}
|
|
559
599
|
}
|
|
560
600
|
main();
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./tree-hc1dSMdb.cjs"),l=require("react"),S=require("react-router-dom"),C={enableLazyLoading:!0};let f={...C};function v(e){f={...f,...e}}function F(){f={...C}}function T(){return f}let g=[];function x(e,t){g.push({pattern:e,middleware:t})}function A(){g=[]}function y(e,t){let r=t;for(const n of g)n.pattern.lastIndex=0,n.pattern.test(e)&&(r=n.middleware(r)),n.pattern.lastIndex=0;return r}const M=()=>l.createElement("div"),h=new Map;function N(){const e=T();if(e.enableLazyLoading===!1)return null;const t=e.loadingFallback||M;return l.createElement(t)}function $(){h.clear()}function p(e,t,r){let n=h.get(t);n||(n=l.lazy(e),h.set(t,n));const a=l.createElement(l.Suspense,{fallback:l.createElement(N)},l.createElement(n));return r?y(r,a):a}const P=l.createContext(void 0);function w({name:e,children:t}){return l.createElement(P.Provider,{value:e},t)}function k(){return l.useContext(P)}function E(e,t){return y(e,l.createElement(t))}function D(e){const t=c.parseRouteSegments(e)[0];return(t==null?void 0:t.kind)==="catchAll"&&t.optional}function d(e){const t=c.parseRouteSegments(e)[0];return t?c.routeSegmentToPath(t):""}function s(e,t){return m(e,t,!0)}function m(e,t,r=!1){const n=e.page;if(!n)throw new Error(`Route node "${e.fullPath}" has no page loader`);const a=p(async()=>({default:(await n()).default}),`page:${e.fullPath||t}`,t),o=c.parseRouteSegments(e.segment)[0],u=(o==null?void 0:o.kind)==="catchAll"?l.createElement(w,{name:o.name,children:a}):a;return r?{index:!0,element:u}:{path:d(e.segment),element:u}}function q(e){const t=e.notFound;if(!t)throw new Error(`Route node "${e.fullPath}" has no not-found loader`);const r=e.fullPath?`/${e.fullPath}`:"/";return{path:"*",element:p(async()=>({default:(await t()).default}),`notfound:${e.fullPath}`,r)}}function L(e){return e.notFound?[q(e)]:[]}function I(e,t,r,n){return{...t?{path:t}:{},element:E(e,r),children:n.length>0?n:void 0}}function b(e,t){const r=[];return[...e.children.entries()].sort(([n],[a])=>n.localeCompare(a)).forEach(([n,a])=>{const o=d(n),u=o?t?`${t}/${o}`:`/${o}`:t;r.push(...R(a,!1,u))}),r}function z(e,t){const r=[];return e.page&&r.push(s(e,t||"/")),r.push(...b(e,t)),r.push(...L(e)),r}function G(e,t,r,n,a,o){if(D(e.segment)){const u=[...a,...o];return[s(e,t),{path:n,element:m(e,r).element,children:u.length>0?u:void 0}]}return a.length>0||o.length>0?[{path:n,children:[s(e,r),...a,...o]}]:[{path:n,element:m(e,r).element}]}function O(e,t,r,n){const a=[...e.page?[s(e,t)]:[],...r,...n];return[{children:a.length>0?a:void 0}]}function j(e){const t=z(e,"");return e.layout?[{path:"/",element:E("/",e.layout),children:t}]:e.page?t.length>1?[{path:"/",children:t}]:[{path:"/",element:m(e,"/",!1).element}]:e.notFound?[{path:"/",children:t}]:t}function R(e,t=!1,r=""){if(t)return j(e);const n=d(e.segment),a=!n,o=a?r:r+"/"+n,u=b(e,o),i=L(e);return e.layout?[I(o,a?"":n,e.layout,z(e,o))]:e.page&&!a?G(e,r,o,n,u,i):e.page||e.notFound||!a?a?O(e,o,u,i):[{path:n,children:[...e.page?[s(e,o)]:[],...u,...i]}]:u}function B(e,t,r,n){return()=>{const a=c.buildRouteTree(e,t,r,n);return R(a,!0)}}function H(){const e=S.useParams(),t=k();return typeof t=="string"&&e["*"]!==void 0?{...e,[t]:e["*"]}:e}exports.assertNoDuplicateRoutes=c.assertNoDuplicateRoutes;exports.assertNoRouteConflicts=c.assertNoRouteConflicts;exports.buildRouteTree=c.buildRouteTree;exports.extractRoutePath=c.extractRoutePath;exports.normalizeSegment=c.normalizeSegment;exports.parseRouteSegments=c.parseRouteSegments;exports.routeSegmentToPath=c.routeSegmentToPath;exports.CatchAllParamProvider=w;exports.clearLazyCache=$;exports.clearMiddlewares=A;exports.configureRouter=v;exports.createLazyElement=p;exports.createRouteGenerator=B;exports.registerMiddleware=x;exports.resetRouterConfig=F;exports.treeToRoutes=R;exports.useParams=H;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
import { default as default_2 } from 'react';
|
|
3
|
+
import { ReactElement } from 'react';
|
|
4
|
+
import { RouteObject } from 'react-router-dom';
|
|
5
|
+
|
|
6
|
+
export declare function assertNoDuplicateRoutes(filePaths: string[], fileOptions?: RouteFileOptions): void;
|
|
7
|
+
|
|
8
|
+
export declare function assertNoRouteConflicts(pageFiles: string[], notFoundFiles: string[], fileOptions?: RouteFileOptions): void;
|
|
9
|
+
|
|
10
|
+
export declare function buildRouteTree(pages: Record<string, () => Promise<any>>, layouts: Record<string, any>, notFounds: Record<string, () => Promise<any>>, fileOptions?: RouteFileOptions): RouteNode;
|
|
11
|
+
|
|
12
|
+
export declare function CatchAllParamProvider({ name, children, }: {
|
|
13
|
+
name: string;
|
|
14
|
+
children: default_2.ReactElement;
|
|
15
|
+
}): default_2.ReactElement;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Clear the module-level lazy component cache.
|
|
19
|
+
*
|
|
20
|
+
* `lazyComponentCache` is a package-wide singleton keyed by route path, so a
|
|
21
|
+
* `React.lazy` component created in one context (for example a previous test)
|
|
22
|
+
* is reused whenever another context requests the same key with a different
|
|
23
|
+
* loader. Exposing an explicit reset keeps that state from leaking, mirroring
|
|
24
|
+
* `clearMiddlewares` for the middleware registry.
|
|
25
|
+
*/
|
|
26
|
+
export declare function clearLazyCache(): void;
|
|
27
|
+
|
|
28
|
+
export declare function clearMiddlewares(): void;
|
|
29
|
+
|
|
30
|
+
export declare function configureRouter(config: RouterConfig): void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a lazy element wrapped with Suspense and apply middlewares
|
|
34
|
+
* @param loader - Function that loads the component
|
|
35
|
+
* @param cacheKey - Unique key for the cache
|
|
36
|
+
* @param routePath - Route path for middlewares
|
|
37
|
+
*/
|
|
38
|
+
export declare function createLazyElement(loader: () => Promise<any>, cacheKey: string, routePath?: string): default_2.ReactElement;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a custom route generator function using your own files
|
|
42
|
+
*
|
|
43
|
+
* ⚠️ NOTE: This function is intended for advanced use only.
|
|
44
|
+
* For most cases, use the Vite plugin which automatically handles the paths.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // In your configuration file
|
|
48
|
+
* const pages = import.meta.glob("../../pages/**\\/page.tsx");
|
|
49
|
+
* const layouts = import.meta.glob("../../pages/**\\/layout.tsx", { eager: true });
|
|
50
|
+
* const notFounds = import.meta.glob("../../pages/**\\/not-found.tsx");
|
|
51
|
+
*
|
|
52
|
+
* export const generateCustomRoutes = createRouteGenerator(pages, layouts, notFounds);
|
|
53
|
+
*
|
|
54
|
+
* // Then use it
|
|
55
|
+
* const routes = generateCustomRoutes();
|
|
56
|
+
*/
|
|
57
|
+
export declare function createRouteGenerator(pages: Record<string, () => Promise<any>>, layouts: Record<string, any>, notFounds: Record<string, () => Promise<any>>, fileOptions?: RouteFileOptions): () => RouteObject[];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extract the route path from a file path
|
|
61
|
+
* @example "../../app/blog/[id]/page.tsx" -> "blog/[id]"
|
|
62
|
+
* @example "../../app/page.tsx" -> ""
|
|
63
|
+
*
|
|
64
|
+
* `pagesDir` may be relative or absolute. The plugin resolves it relative to
|
|
65
|
+
* the Vite project root before passing it here.
|
|
66
|
+
* The prefix is stripped lazily so it matches the FIRST directory boundary
|
|
67
|
+
* that equals `pagesDir` (or the leading `app`/`pages` root marker when no
|
|
68
|
+
* `pagesDir` is supplied). A greedy match would instead consume up to the
|
|
69
|
+
* LAST such folder, which mangles routes that legitimately contain a nested
|
|
70
|
+
* folder named like the pages directory (e.g. `app/docs/app/page.tsx`).
|
|
71
|
+
*/
|
|
72
|
+
export declare function extractRoutePath(filePath: string, { pagesDir, pageFile, layoutFile, notFoundFile }?: RouteFileOptions): string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Normalize a Next.js segment to a React Router segment
|
|
76
|
+
* @example (admin) -> ""
|
|
77
|
+
* @example [id] -> :id
|
|
78
|
+
* @example [...slug] -> *
|
|
79
|
+
*/
|
|
80
|
+
export declare function normalizeSegment(segment: string): string;
|
|
81
|
+
|
|
82
|
+
export declare function parseRouteSegments(routePath: string): RouteSegment[];
|
|
83
|
+
|
|
84
|
+
export declare function registerMiddleware(pattern: RegExp, middleware: RouteMiddleware): void;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Restore the module-level router configuration to its defaults.
|
|
88
|
+
*
|
|
89
|
+
* `configureRouter` merges, so it can never drop keys back to their initial
|
|
90
|
+
* state. A dedicated reset lets isolated contexts (for example tests) start
|
|
91
|
+
* from a known configuration instead of inheriting whatever was set globally
|
|
92
|
+
* before, matching the explicit reset offered by `clearMiddlewares`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function resetRouterConfig(): void;
|
|
95
|
+
|
|
96
|
+
export declare type RouteFileOptions = {
|
|
97
|
+
pagesDir?: string;
|
|
98
|
+
pageFile?: string;
|
|
99
|
+
layoutFile?: string;
|
|
100
|
+
notFoundFile?: string;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export declare type RouteMiddleware = (element: ReactElement) => ReactElement;
|
|
104
|
+
|
|
105
|
+
export declare type RouteModuleLoader = () => Promise<{
|
|
106
|
+
default: ComponentType;
|
|
107
|
+
}>;
|
|
108
|
+
|
|
109
|
+
export declare type RouteNode = {
|
|
110
|
+
segment: string;
|
|
111
|
+
fullPath: string;
|
|
112
|
+
page?: RouteModuleLoader;
|
|
113
|
+
layout?: ComponentType;
|
|
114
|
+
notFound?: RouteModuleLoader;
|
|
115
|
+
children: Map<string, RouteNode>;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export declare type RouterConfig = {
|
|
119
|
+
loadingFallback?: React.ComponentType;
|
|
120
|
+
enableLazyLoading?: boolean;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export declare type RouteSegment = {
|
|
124
|
+
kind: "group";
|
|
125
|
+
name: string;
|
|
126
|
+
} | {
|
|
127
|
+
kind: "static";
|
|
128
|
+
name: string;
|
|
129
|
+
} | {
|
|
130
|
+
kind: "dynamic";
|
|
131
|
+
name: string;
|
|
132
|
+
} | {
|
|
133
|
+
kind: "catchAll";
|
|
134
|
+
name: string;
|
|
135
|
+
optional: boolean;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export declare function routeSegmentToPath(segment: RouteSegment): string;
|
|
139
|
+
|
|
140
|
+
export declare function treeToRoutes(node: RouteNode, isRoot?: boolean, currentPath?: string): RouteObject[];
|
|
141
|
+
|
|
142
|
+
export declare function useParams<T extends Record<string, string | undefined> = Record<string, string | undefined>>(): T;
|
|
143
|
+
|
|
144
|
+
export { }
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,17 @@ export declare function CatchAllParamProvider({ name, children, }: {
|
|
|
14
14
|
children: default_2.ReactElement;
|
|
15
15
|
}): default_2.ReactElement;
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Clear the module-level lazy component cache.
|
|
19
|
+
*
|
|
20
|
+
* `lazyComponentCache` is a package-wide singleton keyed by route path, so a
|
|
21
|
+
* `React.lazy` component created in one context (for example a previous test)
|
|
22
|
+
* is reused whenever another context requests the same key with a different
|
|
23
|
+
* loader. Exposing an explicit reset keeps that state from leaking, mirroring
|
|
24
|
+
* `clearMiddlewares` for the middleware registry.
|
|
25
|
+
*/
|
|
26
|
+
export declare function clearLazyCache(): void;
|
|
27
|
+
|
|
17
28
|
export declare function clearMiddlewares(): void;
|
|
18
29
|
|
|
19
30
|
export declare function configureRouter(config: RouterConfig): void;
|
|
@@ -52,6 +63,11 @@ export declare function createRouteGenerator(pages: Record<string, () => Promise
|
|
|
52
63
|
*
|
|
53
64
|
* `pagesDir` may be relative or absolute. The plugin resolves it relative to
|
|
54
65
|
* the Vite project root before passing it here.
|
|
66
|
+
* The prefix is stripped lazily so it matches the FIRST directory boundary
|
|
67
|
+
* that equals `pagesDir` (or the leading `app`/`pages` root marker when no
|
|
68
|
+
* `pagesDir` is supplied). A greedy match would instead consume up to the
|
|
69
|
+
* LAST such folder, which mangles routes that legitimately contain a nested
|
|
70
|
+
* folder named like the pages directory (e.g. `app/docs/app/page.tsx`).
|
|
55
71
|
*/
|
|
56
72
|
export declare function extractRoutePath(filePath: string, { pagesDir, pageFile, layoutFile, notFoundFile }?: RouteFileOptions): string;
|
|
57
73
|
|
|
@@ -67,6 +83,16 @@ export declare function parseRouteSegments(routePath: string): RouteSegment[];
|
|
|
67
83
|
|
|
68
84
|
export declare function registerMiddleware(pattern: RegExp, middleware: RouteMiddleware): void;
|
|
69
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Restore the module-level router configuration to its defaults.
|
|
88
|
+
*
|
|
89
|
+
* `configureRouter` merges, so it can never drop keys back to their initial
|
|
90
|
+
* state. A dedicated reset lets isolated contexts (for example tests) start
|
|
91
|
+
* from a known configuration instead of inheriting whatever was set globally
|
|
92
|
+
* before, matching the explicit reset offered by `clearMiddlewares`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function resetRouterConfig(): void;
|
|
95
|
+
|
|
70
96
|
export declare type RouteFileOptions = {
|
|
71
97
|
pagesDir?: string;
|
|
72
98
|
pageFile?: string;
|
package/dist/index.js
CHANGED
|
@@ -1,157 +1,160 @@
|
|
|
1
|
-
import { p, r as
|
|
2
|
-
import { a as
|
|
3
|
-
import u, {
|
|
1
|
+
import { p as h, r as F, b } from "./tree-DfnssFxU.js";
|
|
2
|
+
import { a as et, c as nt, e as rt, n as at } from "./tree-DfnssFxU.js";
|
|
3
|
+
import u, { lazy as v, Suspense as z, createContext as $, useContext as A } from "react";
|
|
4
4
|
import { useParams as k } from "react-router-dom";
|
|
5
|
-
const
|
|
5
|
+
const d = {
|
|
6
6
|
enableLazyLoading: !0
|
|
7
7
|
};
|
|
8
|
-
let
|
|
8
|
+
let i = { ...d };
|
|
9
9
|
function U(t) {
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function W() {
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
10
|
+
i = { ...i, ...t };
|
|
11
|
+
}
|
|
12
|
+
function V() {
|
|
13
|
+
i = { ...d };
|
|
14
|
+
}
|
|
15
|
+
function N() {
|
|
16
|
+
return i;
|
|
17
|
+
}
|
|
18
|
+
let p = [];
|
|
19
|
+
function W(t, e) {
|
|
20
|
+
p.push({ pattern: t, middleware: e });
|
|
21
|
+
}
|
|
22
|
+
function X() {
|
|
23
|
+
p = [];
|
|
24
|
+
}
|
|
25
|
+
function R(t, e) {
|
|
26
|
+
let r = e;
|
|
27
|
+
for (const n of p)
|
|
28
|
+
n.pattern.lastIndex = 0, n.pattern.test(t) && (r = n.middleware(r)), n.pattern.lastIndex = 0;
|
|
29
|
+
return r;
|
|
30
|
+
}
|
|
31
|
+
const M = () => u.createElement("div"), m = /* @__PURE__ */ new Map();
|
|
32
|
+
function T() {
|
|
33
|
+
const t = N();
|
|
34
|
+
if (t.enableLazyLoading === !1)
|
|
35
|
+
return null;
|
|
36
|
+
const e = t.loadingFallback || M;
|
|
37
|
+
return u.createElement(e);
|
|
38
|
+
}
|
|
39
|
+
function Y() {
|
|
40
|
+
m.clear();
|
|
41
|
+
}
|
|
42
|
+
function C(t, e, r) {
|
|
43
|
+
let n = m.get(e);
|
|
44
|
+
n || (n = v(t), m.set(e, n));
|
|
45
|
+
const a = u.createElement(
|
|
46
|
+
z,
|
|
47
|
+
{ fallback: u.createElement(T) },
|
|
48
|
+
u.createElement(n)
|
|
46
49
|
);
|
|
47
|
-
return
|
|
50
|
+
return r ? R(r, a) : a;
|
|
48
51
|
}
|
|
49
|
-
const
|
|
50
|
-
function
|
|
52
|
+
const y = $(void 0);
|
|
53
|
+
function I({
|
|
51
54
|
name: t,
|
|
52
55
|
children: e
|
|
53
56
|
}) {
|
|
54
57
|
return u.createElement(
|
|
55
|
-
|
|
58
|
+
y.Provider,
|
|
56
59
|
{ value: t },
|
|
57
60
|
e
|
|
58
61
|
);
|
|
59
62
|
}
|
|
60
|
-
function
|
|
61
|
-
return A(
|
|
63
|
+
function S() {
|
|
64
|
+
return A(y);
|
|
62
65
|
}
|
|
63
|
-
function
|
|
64
|
-
return
|
|
66
|
+
function P(t, e) {
|
|
67
|
+
return R(t, u.createElement(e));
|
|
65
68
|
}
|
|
66
|
-
function
|
|
67
|
-
const e =
|
|
69
|
+
function D(t) {
|
|
70
|
+
const e = h(t)[0];
|
|
68
71
|
return (e == null ? void 0 : e.kind) === "catchAll" && e.optional;
|
|
69
72
|
}
|
|
70
73
|
function g(t) {
|
|
71
|
-
const e =
|
|
72
|
-
return e ?
|
|
74
|
+
const e = h(t)[0];
|
|
75
|
+
return e ? F(e) : "";
|
|
73
76
|
}
|
|
74
|
-
function
|
|
75
|
-
return
|
|
77
|
+
function c(t, e) {
|
|
78
|
+
return f(t, e, !0);
|
|
76
79
|
}
|
|
77
|
-
function
|
|
78
|
-
const
|
|
79
|
-
if (!
|
|
80
|
+
function f(t, e, r = !1) {
|
|
81
|
+
const n = t.page;
|
|
82
|
+
if (!n)
|
|
80
83
|
throw new Error(`Route node "${t.fullPath}" has no page loader`);
|
|
81
|
-
const a =
|
|
82
|
-
async () => ({ default: (await
|
|
84
|
+
const a = C(
|
|
85
|
+
async () => ({ default: (await n()).default }),
|
|
83
86
|
`page:${t.fullPath || e}`,
|
|
84
87
|
e
|
|
85
|
-
), o =
|
|
88
|
+
), o = h(t.segment)[0], l = (o == null ? void 0 : o.kind) === "catchAll" ? u.createElement(I, {
|
|
86
89
|
name: o.name,
|
|
87
90
|
children: a
|
|
88
91
|
}) : a;
|
|
89
|
-
return
|
|
92
|
+
return r ? { index: !0, element: l } : { path: g(t.segment), element: l };
|
|
90
93
|
}
|
|
91
94
|
function G(t) {
|
|
92
95
|
const e = t.notFound;
|
|
93
96
|
if (!e)
|
|
94
97
|
throw new Error(`Route node "${t.fullPath}" has no not-found loader`);
|
|
95
|
-
const
|
|
98
|
+
const r = t.fullPath ? `/${t.fullPath}` : "/";
|
|
96
99
|
return {
|
|
97
100
|
path: "*",
|
|
98
|
-
element:
|
|
101
|
+
element: C(
|
|
99
102
|
async () => ({ default: (await e()).default }),
|
|
100
103
|
`notfound:${t.fullPath}`,
|
|
101
|
-
|
|
104
|
+
r
|
|
102
105
|
)
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
|
-
function
|
|
108
|
+
function E(t) {
|
|
106
109
|
return t.notFound ? [G(t)] : [];
|
|
107
110
|
}
|
|
108
|
-
function O(t, e,
|
|
111
|
+
function O(t, e, r, n) {
|
|
109
112
|
return {
|
|
110
113
|
...e ? { path: e } : {},
|
|
111
|
-
element:
|
|
112
|
-
children:
|
|
114
|
+
element: P(t, r),
|
|
115
|
+
children: n.length > 0 ? n : void 0
|
|
113
116
|
};
|
|
114
117
|
}
|
|
115
|
-
function
|
|
116
|
-
const
|
|
117
|
-
return [...t.children.entries()].sort(([
|
|
118
|
-
const o = g(
|
|
119
|
-
|
|
120
|
-
}),
|
|
118
|
+
function w(t, e) {
|
|
119
|
+
const r = [];
|
|
120
|
+
return [...t.children.entries()].sort(([n], [a]) => n.localeCompare(a)).forEach(([n, a]) => {
|
|
121
|
+
const o = g(n), l = o ? e ? `${e}/${o}` : `/${o}` : e;
|
|
122
|
+
r.push(...x(a, !1, l));
|
|
123
|
+
}), r;
|
|
121
124
|
}
|
|
122
125
|
function L(t, e) {
|
|
123
|
-
const
|
|
124
|
-
return t.page &&
|
|
126
|
+
const r = [];
|
|
127
|
+
return t.page && r.push(c(t, e || "/")), r.push(...w(t, e)), r.push(...E(t)), r;
|
|
125
128
|
}
|
|
126
|
-
function j(t, e,
|
|
127
|
-
if (
|
|
129
|
+
function j(t, e, r, n, a, o) {
|
|
130
|
+
if (D(t.segment)) {
|
|
128
131
|
const l = [...a, ...o];
|
|
129
132
|
return [
|
|
130
|
-
|
|
133
|
+
c(t, e),
|
|
131
134
|
{
|
|
132
|
-
path:
|
|
133
|
-
element:
|
|
135
|
+
path: n,
|
|
136
|
+
element: f(t, r).element,
|
|
134
137
|
children: l.length > 0 ? l : void 0
|
|
135
138
|
}
|
|
136
139
|
];
|
|
137
140
|
}
|
|
138
141
|
return a.length > 0 || o.length > 0 ? [{
|
|
139
|
-
path:
|
|
142
|
+
path: n,
|
|
140
143
|
children: [
|
|
141
|
-
|
|
144
|
+
c(t, r),
|
|
142
145
|
...a,
|
|
143
146
|
...o
|
|
144
147
|
]
|
|
145
148
|
}] : [{
|
|
146
|
-
path:
|
|
147
|
-
element:
|
|
149
|
+
path: n,
|
|
150
|
+
element: f(t, r).element
|
|
148
151
|
}];
|
|
149
152
|
}
|
|
150
|
-
function q(t, e,
|
|
153
|
+
function q(t, e, r, n) {
|
|
151
154
|
const a = [
|
|
152
|
-
...t.page ? [
|
|
153
|
-
...
|
|
154
|
-
...
|
|
155
|
+
...t.page ? [c(t, e)] : [],
|
|
156
|
+
...r,
|
|
157
|
+
...n
|
|
155
158
|
];
|
|
156
159
|
return [{
|
|
157
160
|
children: a.length > 0 ? a : void 0
|
|
@@ -161,62 +164,64 @@ function B(t) {
|
|
|
161
164
|
const e = L(t, "");
|
|
162
165
|
return t.layout ? [{
|
|
163
166
|
path: "/",
|
|
164
|
-
element:
|
|
167
|
+
element: P("/", t.layout),
|
|
165
168
|
children: e
|
|
166
169
|
}] : t.page ? e.length > 1 ? [{ path: "/", children: e }] : [{
|
|
167
170
|
path: "/",
|
|
168
|
-
element:
|
|
171
|
+
element: f(t, "/", !1).element
|
|
169
172
|
}] : t.notFound ? [{ path: "/", children: e }] : e;
|
|
170
173
|
}
|
|
171
|
-
function
|
|
174
|
+
function x(t, e = !1, r = "") {
|
|
172
175
|
if (e)
|
|
173
176
|
return B(t);
|
|
174
|
-
const
|
|
177
|
+
const n = g(t.segment), a = !n, o = a ? r : r + "/" + n, l = w(t, o), s = E(t);
|
|
175
178
|
return t.layout ? [O(
|
|
176
179
|
o,
|
|
177
|
-
a ? "" :
|
|
180
|
+
a ? "" : n,
|
|
178
181
|
t.layout,
|
|
179
182
|
L(t, o)
|
|
180
183
|
)] : t.page && !a ? j(
|
|
181
184
|
t,
|
|
182
|
-
n,
|
|
183
|
-
o,
|
|
184
185
|
r,
|
|
186
|
+
o,
|
|
187
|
+
n,
|
|
185
188
|
l,
|
|
186
|
-
|
|
187
|
-
) : t.page || t.notFound || !a ? a ? q(t, o, l,
|
|
188
|
-
path:
|
|
189
|
+
s
|
|
190
|
+
) : t.page || t.notFound || !a ? a ? q(t, o, l, s) : [{
|
|
191
|
+
path: n,
|
|
189
192
|
children: [
|
|
190
|
-
...t.page ? [
|
|
193
|
+
...t.page ? [c(t, o)] : [],
|
|
191
194
|
...l,
|
|
192
|
-
...
|
|
195
|
+
...s
|
|
193
196
|
]
|
|
194
197
|
}] : l;
|
|
195
198
|
}
|
|
196
|
-
function
|
|
199
|
+
function Z(t, e, r, n) {
|
|
197
200
|
return () => {
|
|
198
|
-
const a =
|
|
199
|
-
return
|
|
201
|
+
const a = b(t, e, r, n);
|
|
202
|
+
return x(a, !0);
|
|
200
203
|
};
|
|
201
204
|
}
|
|
202
|
-
function
|
|
203
|
-
const t = k(), e =
|
|
205
|
+
function _() {
|
|
206
|
+
const t = k(), e = S();
|
|
204
207
|
return typeof e == "string" && t["*"] !== void 0 ? { ...t, [e]: t["*"] } : t;
|
|
205
208
|
}
|
|
206
209
|
export {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
I as CatchAllParamProvider,
|
|
211
|
+
et as assertNoDuplicateRoutes,
|
|
212
|
+
nt as assertNoRouteConflicts,
|
|
213
|
+
b as buildRouteTree,
|
|
214
|
+
Y as clearLazyCache,
|
|
215
|
+
X as clearMiddlewares,
|
|
212
216
|
U as configureRouter,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
C as createLazyElement,
|
|
218
|
+
Z as createRouteGenerator,
|
|
219
|
+
rt as extractRoutePath,
|
|
220
|
+
at as normalizeSegment,
|
|
221
|
+
h as parseRouteSegments,
|
|
222
|
+
W as registerMiddleware,
|
|
223
|
+
V as resetRouterConfig,
|
|
224
|
+
F as routeSegmentToPath,
|
|
225
|
+
x as treeToRoutes,
|
|
226
|
+
_ as useParams
|
|
222
227
|
};
|
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("node:fs"),f=require("node:path"),x=require("./tree-hc1dSMdb.cjs");function S(r){const a=r.map(x.routeSegmentToPath).filter(Boolean);return a.length>0?`/${a.join("/")}`:"/"}function T(r){const a=[["pagesDir",r.pagesDir],["pageFile",r.pageFile],["layoutFile",r.layoutFile],["notFoundFile",r.notFoundFile]];for(const[o,e]of a)if(!e.trim())throw new Error(`nextViteRouter option "${o}" must not be empty.`);const s=a.slice(1),i=s.find(([,o],e)=>s.slice(e+1).some(([,n])=>n===o));if(i)throw new Error(`nextViteRouter file options must be distinct; "${i[0]}" is duplicated.`)}function k(r){return r.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/|\/$/g,"")}function G(r,a,s){const i=a.pageFile??"page.tsx",o=new Map;for(const e of R(r,i,s)){const n=x.extractRoutePath(e,a),l=x.parseRouteSegments(n),g=l.filter(u=>u.kind==="dynamic"||u.kind==="catchAll").map(u=>({name:u.name,optional:u.kind==="catchAll"&&u.optional})),p=S(l);o.set(p,{path:p,params:g});const m=l[l.length-1];if((m==null?void 0:m.kind)==="catchAll"&&m.optional){const u=S(l.slice(0,-1));o.has(u)||o.set(u,{path:u,params:[]})}}return[...o.values()].sort((e,n)=>e.path.localeCompare(n.path))}function R(r,a,s){const i=[];function o(e){for(const n of b.readdirSync(e,{withFileTypes:!0})){const l=f.join(e,n.name);if(n.isDirectory())o(l);else if(n.isFile()&&n.name===a){const g=f.relative(r,l).replace(/\\/g,"/");i.push(`/${s}/${g}`)}}}return b.existsSync(r)&&o(r),i}function O(r){const a=r.map(({path:i})=>` | ${JSON.stringify(i)}`).join(`
|
|
2
|
+
`),s=r.map(({path:i,params:o})=>{const e=o.length>0?[...o.map(({name:n,optional:l})=>` ${n}${l?"?":""}: string;`)].join(`
|
|
3
|
+
`):" [key: string]: never;";return` ${JSON.stringify(i)}: {
|
|
4
|
+
${e}
|
|
5
|
+
};`}).join(`
|
|
6
|
+
`);return`declare module 'virtual:next-vite-router' {
|
|
7
|
+
import type { ReactElement } from 'react';
|
|
8
|
+
import type { RouteObject } from 'react-router-dom';
|
|
9
|
+
|
|
10
|
+
export type RoutePath =
|
|
11
|
+
${a||' | "/"'};
|
|
12
|
+
|
|
13
|
+
export type RouteParams<P extends RoutePath> = P extends keyof RoutePathParams
|
|
14
|
+
? RoutePathParams[P]
|
|
15
|
+
: never;
|
|
16
|
+
|
|
17
|
+
export interface RoutePathParams {
|
|
18
|
+
${s}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const generateRoutes: () => RouteObject[];
|
|
22
|
+
export function Router(): ReactElement | null;
|
|
23
|
+
export function useParams<T extends Record<string, string | undefined> = Record<string, string | undefined>>(): T;
|
|
24
|
+
export { Link, useRoutes } from 'react-router-dom';
|
|
25
|
+
}
|
|
26
|
+
`}function j(r={}){const{pagesDir:a="src/app",pageFile:s="page.tsx",layoutFile:i="layout.tsx",notFoundFile:o="not-found.tsx"}=r;T({pagesDir:a,pageFile:s,layoutFile:i,notFoundFile:o});const e=k(a),n={pagesDir:e,pageFile:s,layoutFile:i,notFoundFile:o},l="virtual:next-vite-router",g="\0"+l;let p="",m="",u,P,h;function v(){const t=O(G(p,n,e));try{b.mkdirSync(f.dirname(m),{recursive:!0}),b.writeFileSync(m,t,"utf-8")}catch(d){const c=`next-vite-router could not write route types to ${m}: ${d instanceof Error?d.message:String(d)}`;u?u.warn(c):console.warn(c)}}return{name:"next-vite-router",configResolved(t){p=f.resolve(t.root,a),m=f.join(f.dirname(p),"virtual-next-vite-router.d.ts"),u=t.logger,x.assertNoRouteConflicts(R(p,s,e),R(p,o,e),n),v()},configureServer(t){if(P===t)return;h==null||h(),P=t;const d=$=>{if(f.relative(p,$).startsWith("..")||![s,i,o].includes(f.basename($)))return;try{x.assertNoRouteConflicts(R(p,s,e),R(p,o,e),n)}catch(F){t.config.logger.error(F instanceof Error?F.message:String(F));return}v();const w=t.moduleGraph.getModuleById(g);w&&(t.moduleGraph.invalidateModule(w),c&&clearTimeout(c),c=setTimeout(()=>{c=void 0,t.ws.send({type:"full-reload",path:"*"})},0))};let c;const y=()=>{c&&(clearTimeout(c),c=void 0),t.watcher.off("add",d),t.watcher.off("unlink",d),t.watcher.off("close",y),P===t&&(P=void 0,h=void 0)};t.watcher.on("add",d),t.watcher.on("unlink",d),t.watcher.once("close",y),h=y},resolveId(t){if(t===l)return g},load(t){if(t===g){const d=`/${e}/**/${s}`,c=`/${e}/**/${i}`,y=`/${e}/**/${o}`;return`
|
|
27
|
+
import { buildRouteTree, treeToRoutes, normalizeSegment, createLazyElement, useParams } from 'next-vite-router';
|
|
28
|
+
import { Link, useRoutes } from 'react-router-dom';
|
|
29
|
+
|
|
30
|
+
const pagesGlob = import.meta.glob(${JSON.stringify(d)});
|
|
31
|
+
const layoutsGlob = import.meta.glob(${JSON.stringify(c)}, { eager: true });
|
|
32
|
+
const notFoundsGlob = import.meta.glob(${JSON.stringify(y)});
|
|
33
|
+
|
|
34
|
+
// Keep the raw root-relative glob keys. extractRoutePath (via buildRouteTree)
|
|
35
|
+
// is the single place that strips the pagesDir prefix; stripping it here as
|
|
36
|
+
// well would double-remove it and let the prefix regex match a same-named
|
|
37
|
+
// nested folder (e.g. pagesDir "app" turning "app/docs/app" into "/").
|
|
38
|
+
const pages = pagesGlob;
|
|
39
|
+
const layouts = layoutsGlob;
|
|
40
|
+
const notFounds = notFoundsGlob;
|
|
41
|
+
|
|
42
|
+
export function generateRoutes() {
|
|
43
|
+
const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(n)});
|
|
44
|
+
const routes = treeToRoutes(tree, true);
|
|
45
|
+
return routes;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function Router() {
|
|
49
|
+
routes ??= generateRoutes();
|
|
50
|
+
return useRoutes(routes);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let routes;
|
|
54
|
+
|
|
55
|
+
if (import.meta.hot) {
|
|
56
|
+
import.meta.hot.accept(() => {
|
|
57
|
+
routes = undefined;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { Link, useRoutes };
|
|
62
|
+
export { useParams };
|
|
63
|
+
`}}}}exports.nextViteRouter=j;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Plugin as Plugin_2 } from 'vite';
|
|
2
|
+
|
|
3
|
+
export declare function nextViteRouter(options?: NextViteRouterPluginOptions): Plugin_2;
|
|
4
|
+
|
|
5
|
+
export declare type NextViteRouterPluginOptions = {
|
|
6
|
+
pagesDir?: string;
|
|
7
|
+
pageFile?: string;
|
|
8
|
+
layoutFile?: string;
|
|
9
|
+
notFoundFile?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { }
|
package/dist/plugin.js
CHANGED
|
@@ -1,77 +1,73 @@
|
|
|
1
1
|
import P from "node:fs";
|
|
2
|
-
import
|
|
3
|
-
import { c as
|
|
4
|
-
function
|
|
5
|
-
const a =
|
|
2
|
+
import f from "node:path";
|
|
3
|
+
import { c as w, e as T, p as k, r as G } from "./tree-DfnssFxU.js";
|
|
4
|
+
function S(r) {
|
|
5
|
+
const a = r.map(G).filter(Boolean);
|
|
6
6
|
return a.length > 0 ? `/${a.join("/")}` : "/";
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function O(r) {
|
|
9
9
|
const a = [
|
|
10
|
-
["pagesDir",
|
|
11
|
-
["pageFile",
|
|
12
|
-
["layoutFile",
|
|
13
|
-
["notFoundFile",
|
|
10
|
+
["pagesDir", r.pagesDir],
|
|
11
|
+
["pageFile", r.pageFile],
|
|
12
|
+
["layoutFile", r.layoutFile],
|
|
13
|
+
["notFoundFile", r.notFoundFile]
|
|
14
14
|
];
|
|
15
|
-
for (const [
|
|
16
|
-
if (!
|
|
17
|
-
throw new Error(`nextViteRouter option "${
|
|
18
|
-
const
|
|
19
|
-
([,
|
|
15
|
+
for (const [o, e] of a)
|
|
16
|
+
if (!e.trim())
|
|
17
|
+
throw new Error(`nextViteRouter option "${o}" must not be empty.`);
|
|
18
|
+
const s = a.slice(1), i = s.find(
|
|
19
|
+
([, o], e) => s.slice(e + 1).some(([, n]) => n === o)
|
|
20
20
|
);
|
|
21
21
|
if (i)
|
|
22
22
|
throw new Error(
|
|
23
23
|
`nextViteRouter file options must be distinct; "${i[0]}" is duplicated.`
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
return
|
|
26
|
+
function j(r) {
|
|
27
|
+
return r.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/|\/$/g, "");
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
r.set(m, { path: m, params: R });
|
|
44
|
-
const f = s[s.length - 1];
|
|
45
|
-
if ((f == null ? void 0 : f.kind) === "catchAll" && f.optional) {
|
|
46
|
-
const c = d.slice(0, -1).join(l.sep), t = j(
|
|
47
|
-
S(c.split(l.sep).join("/"))
|
|
48
|
-
);
|
|
49
|
-
r.has(t) || r.set(t, { path: t, params: [] });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
29
|
+
function D(r, a, s) {
|
|
30
|
+
const i = a.pageFile ?? "page.tsx", o = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const e of R(r, i, s)) {
|
|
32
|
+
const n = T(e, a), l = k(n), g = l.filter(
|
|
33
|
+
(u) => u.kind === "dynamic" || u.kind === "catchAll"
|
|
34
|
+
).map((u) => ({
|
|
35
|
+
name: u.name,
|
|
36
|
+
optional: u.kind === "catchAll" && u.optional
|
|
37
|
+
})), p = S(l);
|
|
38
|
+
o.set(p, { path: p, params: g });
|
|
39
|
+
const m = l[l.length - 1];
|
|
40
|
+
if ((m == null ? void 0 : m.kind) === "catchAll" && m.optional) {
|
|
41
|
+
const u = S(l.slice(0, -1));
|
|
42
|
+
o.has(u) || o.set(u, { path: u, params: [] });
|
|
52
43
|
}
|
|
53
44
|
}
|
|
54
|
-
return
|
|
45
|
+
return [...o.values()].sort((e, n) => e.path.localeCompare(n.path));
|
|
55
46
|
}
|
|
56
|
-
function
|
|
57
|
-
const
|
|
58
|
-
function
|
|
59
|
-
for (const
|
|
60
|
-
const
|
|
61
|
-
|
|
47
|
+
function R(r, a, s) {
|
|
48
|
+
const i = [];
|
|
49
|
+
function o(e) {
|
|
50
|
+
for (const n of P.readdirSync(e, { withFileTypes: !0 })) {
|
|
51
|
+
const l = f.join(e, n.name);
|
|
52
|
+
if (n.isDirectory())
|
|
53
|
+
o(l);
|
|
54
|
+
else if (n.isFile() && n.name === a) {
|
|
55
|
+
const g = f.relative(r, l).replace(/\\/g, "/");
|
|
56
|
+
i.push(`/${s}/${g}`);
|
|
57
|
+
}
|
|
62
58
|
}
|
|
63
59
|
}
|
|
64
|
-
return P.existsSync(
|
|
60
|
+
return P.existsSync(r) && o(r), i;
|
|
65
61
|
}
|
|
66
|
-
function
|
|
67
|
-
const a =
|
|
68
|
-
`),
|
|
69
|
-
const
|
|
70
|
-
...
|
|
62
|
+
function N(r) {
|
|
63
|
+
const a = r.map(({ path: i }) => ` | ${JSON.stringify(i)}`).join(`
|
|
64
|
+
`), s = r.map(({ path: i, params: o }) => {
|
|
65
|
+
const e = o.length > 0 ? [
|
|
66
|
+
...o.map(({ name: n, optional: l }) => ` ${n}${l ? "?" : ""}: string;`)
|
|
71
67
|
].join(`
|
|
72
68
|
`) : " [key: string]: never;";
|
|
73
69
|
return ` ${JSON.stringify(i)}: {
|
|
74
|
-
${
|
|
70
|
+
${e}
|
|
75
71
|
};`;
|
|
76
72
|
}).join(`
|
|
77
73
|
`);
|
|
@@ -87,7 +83,7 @@ ${a || ' | "/"'};
|
|
|
87
83
|
: never;
|
|
88
84
|
|
|
89
85
|
export interface RoutePathParams {
|
|
90
|
-
${
|
|
86
|
+
${s}
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
export const generateRoutes: () => RouteObject[];
|
|
@@ -97,89 +93,90 @@ ${r}
|
|
|
97
93
|
}
|
|
98
94
|
`;
|
|
99
95
|
}
|
|
100
|
-
function
|
|
96
|
+
function L(r = {}) {
|
|
101
97
|
const {
|
|
102
98
|
pagesDir: a = "src/app",
|
|
103
|
-
pageFile:
|
|
99
|
+
pageFile: s = "page.tsx",
|
|
104
100
|
layoutFile: i = "layout.tsx",
|
|
105
|
-
notFoundFile:
|
|
106
|
-
} =
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
let
|
|
110
|
-
function
|
|
111
|
-
const t =
|
|
112
|
-
|
|
101
|
+
notFoundFile: o = "not-found.tsx"
|
|
102
|
+
} = r;
|
|
103
|
+
O({ pagesDir: a, pageFile: s, layoutFile: i, notFoundFile: o });
|
|
104
|
+
const e = j(a), n = { pagesDir: e, pageFile: s, layoutFile: i, notFoundFile: o }, l = "virtual:next-vite-router", g = "\0" + l;
|
|
105
|
+
let p = "", m = "", u, x, h;
|
|
106
|
+
function $() {
|
|
107
|
+
const t = N(D(p, n, e));
|
|
108
|
+
try {
|
|
109
|
+
P.mkdirSync(f.dirname(m), { recursive: !0 }), P.writeFileSync(m, t, "utf-8");
|
|
110
|
+
} catch (d) {
|
|
111
|
+
const c = `next-vite-router could not write route types to ${m}: ${d instanceof Error ? d.message : String(d)}`;
|
|
112
|
+
u ? u.warn(c) : console.warn(c);
|
|
113
|
+
}
|
|
113
114
|
}
|
|
114
115
|
return {
|
|
115
116
|
name: "next-vite-router",
|
|
116
117
|
configResolved(t) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
),
|
|
118
|
+
p = f.resolve(t.root, a), m = f.join(f.dirname(p), "virtual-next-vite-router.d.ts"), u = t.logger, w(
|
|
119
|
+
R(p, s, e),
|
|
120
|
+
R(p, o, e),
|
|
121
|
+
n
|
|
122
|
+
), $();
|
|
122
123
|
},
|
|
123
124
|
configureServer(t) {
|
|
124
|
-
if (
|
|
125
|
+
if (x === t)
|
|
125
126
|
return;
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
127
|
+
h == null || h(), x = t;
|
|
128
|
+
const d = (b) => {
|
|
129
|
+
if (f.relative(p, b).startsWith("..") || ![s, i, o].includes(f.basename(b)))
|
|
129
130
|
return;
|
|
130
131
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
w(
|
|
133
|
+
R(p, s, e),
|
|
134
|
+
R(p, o, e),
|
|
135
|
+
n
|
|
135
136
|
);
|
|
136
|
-
} catch (
|
|
137
|
+
} catch (F) {
|
|
137
138
|
t.config.logger.error(
|
|
138
|
-
|
|
139
|
+
F instanceof Error ? F.message : String(F)
|
|
139
140
|
);
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
$();
|
|
144
|
+
const v = t.moduleGraph.getModuleById(g);
|
|
145
|
+
v && (t.moduleGraph.invalidateModule(v), c && clearTimeout(c), c = setTimeout(() => {
|
|
146
|
+
c = void 0, t.ws.send({ type: "full-reload", path: "*" });
|
|
146
147
|
}, 0));
|
|
147
148
|
};
|
|
148
|
-
let
|
|
149
|
-
const
|
|
150
|
-
|
|
149
|
+
let c;
|
|
150
|
+
const y = () => {
|
|
151
|
+
c && (clearTimeout(c), c = void 0), t.watcher.off("add", d), t.watcher.off("unlink", d), t.watcher.off("close", y), x === t && (x = void 0, h = void 0);
|
|
151
152
|
};
|
|
152
|
-
t.watcher.on("add",
|
|
153
|
+
t.watcher.on("add", d), t.watcher.on("unlink", d), t.watcher.once("close", y), h = y;
|
|
153
154
|
},
|
|
154
155
|
resolveId(t) {
|
|
155
|
-
if (t ===
|
|
156
|
-
return
|
|
156
|
+
if (t === l)
|
|
157
|
+
return g;
|
|
157
158
|
},
|
|
158
159
|
load(t) {
|
|
159
|
-
if (t ===
|
|
160
|
-
const
|
|
160
|
+
if (t === g) {
|
|
161
|
+
const d = `/${e}/**/${s}`, c = `/${e}/**/${i}`, y = `/${e}/**/${o}`;
|
|
161
162
|
return `
|
|
162
163
|
import { buildRouteTree, treeToRoutes, normalizeSegment, createLazyElement, useParams } from 'next-vite-router';
|
|
163
164
|
import { Link, useRoutes } from 'react-router-dom';
|
|
164
165
|
|
|
165
|
-
const pagesGlob = import.meta.glob(${JSON.stringify(
|
|
166
|
-
const layoutsGlob = import.meta.glob(${JSON.stringify(
|
|
167
|
-
const notFoundsGlob = import.meta.glob(${JSON.stringify(
|
|
168
|
-
|
|
169
|
-
const transformPath = (path) => path.replace(${JSON.stringify(x)}, '');
|
|
166
|
+
const pagesGlob = import.meta.glob(${JSON.stringify(d)});
|
|
167
|
+
const layoutsGlob = import.meta.glob(${JSON.stringify(c)}, { eager: true });
|
|
168
|
+
const notFoundsGlob = import.meta.glob(${JSON.stringify(y)});
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const notFounds =
|
|
178
|
-
Object.entries(notFoundsGlob).map(([key, value]) => [transformPath(key), value])
|
|
179
|
-
);
|
|
170
|
+
// Keep the raw root-relative glob keys. extractRoutePath (via buildRouteTree)
|
|
171
|
+
// is the single place that strips the pagesDir prefix; stripping it here as
|
|
172
|
+
// well would double-remove it and let the prefix regex match a same-named
|
|
173
|
+
// nested folder (e.g. pagesDir "app" turning "app/docs/app" into "/").
|
|
174
|
+
const pages = pagesGlob;
|
|
175
|
+
const layouts = layoutsGlob;
|
|
176
|
+
const notFounds = notFoundsGlob;
|
|
180
177
|
|
|
181
178
|
export function generateRoutes() {
|
|
182
|
-
const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(
|
|
179
|
+
const tree = buildRouteTree(pages, layouts, notFounds, ${JSON.stringify(n)});
|
|
183
180
|
const routes = treeToRoutes(tree, true);
|
|
184
181
|
return routes;
|
|
185
182
|
}
|
|
@@ -205,5 +202,5 @@ export { useParams };
|
|
|
205
202
|
};
|
|
206
203
|
}
|
|
207
204
|
export {
|
|
208
|
-
|
|
205
|
+
L as nextViteRouter
|
|
209
206
|
};
|
|
@@ -27,9 +27,9 @@ function m(t) {
|
|
|
27
27
|
return o;
|
|
28
28
|
}
|
|
29
29
|
function f(t, { pagesDir: s, pageFile: o = "page.tsx", layoutFile: c = "layout.tsx", notFoundFile: a = "not-found.tsx" } = {}) {
|
|
30
|
-
const n = t.replace(/\\/g, "/"), e = s == null ? void 0 : s.replace(/\\/g, "/").replace(/^\/|\/$/g, ""), r = e == null ? void 0 : e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = [o, c, a].map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
30
|
+
const n = t.replace(/\\/g, "/"), e = s == null ? void 0 : s.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/|\/$/g, ""), r = e == null ? void 0 : e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), i = [o, c, a].map((l) => l.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
31
31
|
return n.replace(
|
|
32
|
-
e ? new RegExp(
|
|
32
|
+
e ? new RegExp(`^.*?(?:^|/)${r}/`) : /^.*?(?:^|\/)(?:app|pages)\//,
|
|
33
33
|
""
|
|
34
34
|
).replace(/\\/g, "/").replace(new RegExp(`/?(?:${i})$`), "");
|
|
35
35
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";function w(t){return/^\([^)]+\)$/.test(t)?"":/^\[\[\.\.\.(.+)\]\]$/.test(t)||/^\[\.\.\.(.+)\]$/.test(t)?"*":/^\[([^\]]+)\]$/.test(t)?t.replace(/^\[([^\]]+)\]$/,":$1"):t}const R=/^[A-Za-z_][A-Za-z0-9_]*$/;function $(t){return t.kind==="group"?"":t.kind==="dynamic"?`:${t.name}`:t.kind==="catchAll"?"*":t.name}function d(t){const s=t?t.split("/").filter(Boolean):[],o=[],c=new Set;for(const a of s){const n=a.match(/^\(([^)]+)\)$/),e=a.match(/^\[\[\.\.\.(.+)\]\]$/),r=a.match(/^\[\.\.\.(.+)\]$/),i=a.match(/^\[([^\]]+)\]$/),l=e?{name:e[1],optional:!0,kind:"catchAll"}:r?{name:r[1],optional:!1,kind:"catchAll"}:i?{name:i[1],optional:!1,kind:"dynamic"}:void 0;if(n)o.push({kind:"group",name:n[1]});else if(l){if(!R.test(l.name))throw new Error(`Invalid route parameter name "${l.name}" in segment "${a}". Parameter names must start with a letter or underscore and contain only letters, numbers, and underscores.`);if(c.has(l.name))throw new Error(`Duplicate route parameter "${l.name}" in route "${t||"/"}".`);c.add(l.name),o.push(l)}else o.push({kind:"static",name:a})}return o}function u(t,{pagesDir:s,pageFile:o="page.tsx",layoutFile:c="layout.tsx",notFoundFile:a="not-found.tsx"}={}){const n=t.replace(/\\/g,"/"),e=s==null?void 0:s.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/|\/$/g,""),r=e==null?void 0:e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=[o,c,a].map(l=>l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|");return n.replace(e?new RegExp(`^.*?(?:^|/)${r}/`):/^.*?(?:^|\/)(?:app|pages)\//,"").replace(/\\/g,"/").replace(new RegExp(`/?(?:${i})$`),"")}function g(t){return t.kind==="group"?"":t.kind==="catchAll"?"*":t.kind==="dynamic"?":param":$(t)}function P(t,s){const o=u(t,s),c=d(o),a=c.map(g).filter(Boolean),n=[a.length>0?`/${a.join("/")}`:"/"],e=c[c.length-1];if((e==null?void 0:e.kind)==="catchAll"&&e.optional){const r=a.slice(0,-1);n.push(r.length>0?`/${r.join("/")}`:"/")}return n}function j(t){return/(^|\/)(:param|\*)($|\/)/.test(t)?"pattern":"literal"}function E(t,s,o){const c=t.flatMap(n=>{const e=u(n,o),r=d(e),i=r[r.length-1];if((i==null?void 0:i.kind)!=="catchAll")return[];const l=r.map(g).filter(Boolean),h=l.length>0?`/${l.join("/")}`:"/",m=l.slice(0,-1),A=m.length>0?`/${m.join("/")}`:"/";return[{filePath:n,paths:new Set([h,A])}]}),a=new Map;for(const n of s)for(const e of P(n,o))for(const r of c)if(r.paths.has(e)){const i=`${e}\0${r.filePath}\0${n}`;a.set(i,{routePath:e,pageFile:r.filePath,notFoundFile:n})}if(a.size>0)throw new Error([...a.values()].sort((n,e)=>n.routePath.localeCompare(e.routePath)).map(({routePath:n,pageFile:e,notFoundFile:r})=>`Conflicting fallback routes "${n}" detected:
|
|
2
|
+
catch-all page: ${e}
|
|
3
|
+
not-found file: ${r}
|
|
4
|
+
A not-found route and a catch-all page cannot coexist at the same route level.`).join(`
|
|
5
|
+
|
|
6
|
+
`))}function p(t,s){const o=new Map;for(const a of t)for(const n of P(a,s)){const e=o.get(n)??[];e.push({kind:j(n),filePath:a}),o.set(n,e)}const c=[...o.entries()].filter(([,a])=>a.length>1).sort(([a],[n])=>a.localeCompare(n));if(c.length>0)throw new Error(c.map(([a,n])=>`${n[0].kind==="pattern"?"Ambiguous route pattern":"Duplicate route"} "${a}" detected:
|
|
7
|
+
${n.sort((e,r)=>e.filePath.localeCompare(r.filePath)).map(e=>` ${e.filePath}`).join(`
|
|
8
|
+
`)}`).join(`
|
|
9
|
+
|
|
10
|
+
`))}function k(t,s,o){p(t,o),p(s,o),E(t,s,o)}function f(t,s,o,c,a){const n=u(s,a),e=n?n.split("/"):[];let r=t,i="";e.forEach((l,h)=>{i=i?`${i}/${l}`:l,r.children.has(l)||r.children.set(l,{segment:l,fullPath:i,children:new Map}),r=r.children.get(l),h===e.length-1&&(r[c]=o)}),e.length===0&&(t[c]=o)}function b(t,s,o,c){k(Object.keys(t),Object.keys(o),c);const a={segment:"",fullPath:"",children:new Map};return Object.entries(s).forEach(([n,e])=>{f(a,n,e.default,"layout",c)}),Object.entries(t).forEach(([n,e])=>{f(a,n,e,"page",c)}),Object.entries(o).forEach(([n,e])=>{f(a,n,e,"notFound",c)}),a}exports.assertNoDuplicateRoutes=p;exports.assertNoRouteConflicts=k;exports.buildRouteTree=b;exports.extractRoutePath=u;exports.normalizeSegment=w;exports.parseRouteSegments=d;exports.routeSegmentToPath=$;
|
package/package.json
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-vite-router",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Next.js-like file-based routing for React + Vite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"bin": {
|
|
10
|
-
"
|
|
10
|
+
"next-vite-router": "./dist/cli.cjs"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
|
-
"import":
|
|
15
|
-
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
16
22
|
},
|
|
17
23
|
"./plugin": {
|
|
18
|
-
"import":
|
|
19
|
-
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./dist/plugin.d.ts",
|
|
26
|
+
"default": "./dist/plugin.js"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/plugin.d.cts",
|
|
30
|
+
"default": "./dist/plugin.cjs"
|
|
31
|
+
}
|
|
20
32
|
}
|
|
21
33
|
},
|
|
22
34
|
"files": [
|
|
@@ -36,7 +48,7 @@
|
|
|
36
48
|
"author": "Rlzee",
|
|
37
49
|
"repository": {
|
|
38
50
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/Rlzee/next-vite-router"
|
|
51
|
+
"url": "git+https://github.com/Rlzee/next-vite-router.git"
|
|
40
52
|
},
|
|
41
53
|
"homepage": "https://github.com/Rlzee/next-vite-router#readme",
|
|
42
54
|
"license": "MIT",
|
|
@@ -62,7 +74,8 @@
|
|
|
62
74
|
},
|
|
63
75
|
"scripts": {
|
|
64
76
|
"dev": "vite build --watch",
|
|
65
|
-
"build": "vite build && vite build -c vite.config.cli.ts",
|
|
77
|
+
"build": "vite build && vite build -c vite.config.cli.ts && node -e \"import fs from 'node:fs'; for (const f of ['index','plugin']) fs.copyFileSync('dist/'+f+'.d.ts','dist/'+f+'.d.cts')\"",
|
|
78
|
+
"test": "pnpm run test:params && pnpm run test:generator && pnpm run test:routes && pnpm run test:local && pnpm run test:compatibility",
|
|
66
79
|
"test:local": "node test/test-package.js",
|
|
67
80
|
"test:routes": "node test/test-route-types.js",
|
|
68
81
|
"test:generator": "node --test test/routes.test.js",
|