next-vite-router 1.0.2 → 1.0.4
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 +57 -31
- package/dist/index.js +53 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Next Vite Router is an npm package that provides Next.js-style, file-based routing for React applications built with Vite. It generates React Router route objects from a filesystem layout (pages, layouts, not-found), and it exposes a Vite plugin that injects a virtual module to generate routes at build/dev time.
|
|
4
4
|
|
|
5
|
-
This README focuses on how consumers install and use the package (no publishing instructions).
|
|
6
|
-
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
Install with your package manager of choice:
|
|
@@ -37,28 +35,75 @@ export default defineConfig({
|
|
|
37
35
|
});
|
|
38
36
|
```
|
|
39
37
|
|
|
40
|
-
Example usage inside your app (
|
|
38
|
+
Example usage inside your app. **Important: generate routes once at module level** (not inside the component) to avoid infinite re-renders.
|
|
39
|
+
|
|
40
|
+
File: `src/App.tsx`
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
|
-
import
|
|
44
|
-
import {
|
|
45
|
-
import { generateRoutes, useRoutes } from 'virtual:next-vite-router';
|
|
43
|
+
import { useRoutes } from 'react-router-dom';
|
|
44
|
+
import { generateRoutes } from 'virtual:next-vite-router';
|
|
46
45
|
|
|
47
46
|
const routes = generateRoutes();
|
|
48
47
|
|
|
49
|
-
function App() {
|
|
48
|
+
export default function App() {
|
|
50
49
|
const element = useRoutes(routes);
|
|
51
|
-
return
|
|
50
|
+
return element;
|
|
52
51
|
}
|
|
52
|
+
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
File: `src/main.tsx`
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { StrictMode } from 'react';
|
|
58
|
+
import { createRoot } from 'react-dom/client';
|
|
59
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
60
|
+
import App from './App';
|
|
61
|
+
|
|
62
|
+
createRoot(document.getElementById('root')!).render(
|
|
63
|
+
<StrictMode>
|
|
64
|
+
<BrowserRouter>
|
|
65
|
+
<App />
|
|
66
|
+
</BrowserRouter>
|
|
67
|
+
</StrictMode>
|
|
68
|
+
);
|
|
55
69
|
```
|
|
56
70
|
|
|
57
|
-
|
|
71
|
+
**Key points:**
|
|
58
72
|
|
|
59
|
-
-
|
|
73
|
+
- Call `generateRoutes()` once at module level, not inside the component (prevents infinite re-renders).
|
|
74
|
+
- Wrap your app with `BrowserRouter` at the entry point (`main.tsx`), not inside `App`.
|
|
75
|
+
- `pagesDir` (default: `src/app`) is the directory where you organize your **route files** (`page.tsx`, `layout.tsx`, `not-found.tsx`). It has nothing to do with the `App.tsx` component.
|
|
60
76
|
- The virtual module is `virtual:next-vite-router` (the plugin resolves it internally).
|
|
61
77
|
|
|
78
|
+
**Example file structure:**
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
src/
|
|
82
|
+
├── App.tsx ← Your main app component
|
|
83
|
+
├── main.tsx ← Entry point (with BrowserRouter)
|
|
84
|
+
└── app/ ← pagesDir (routes are organized here)
|
|
85
|
+
├── page.tsx ← Home page
|
|
86
|
+
├── layout.tsx ← Root layout
|
|
87
|
+
└── dashboard/
|
|
88
|
+
├── page.tsx ← /dashboard page
|
|
89
|
+
└── layout.tsx ← Dashboard layout
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
TypeScript note:
|
|
93
|
+
|
|
94
|
+
If you're using TypeScript in a consuming project, add a declaration file so the virtual module is recognized by the compiler. Create a file such as `src/virtual.d.ts` (or any `*.d.ts` included by your `tsconfig.json`) with the following content:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
declare module 'virtual:next-vite-router' {
|
|
98
|
+
import type { RouteObject } from 'react-router-dom';
|
|
99
|
+
|
|
100
|
+
export const generateRoutes: () => RouteObject[];
|
|
101
|
+
export { useRoutes } from 'react-router-dom';
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This ensures TypeScript knows the shape of the virtual module provided by the Vite plugin and avoids `Cannot find module 'virtual:next-vite-router'` errors in editors and builds.
|
|
106
|
+
|
|
62
107
|
## Programmatic route generation
|
|
63
108
|
|
|
64
109
|
If you prefer to generate routes manually (for custom setups), the package exports helpers you can use with `import.meta.glob`.
|
|
@@ -153,25 +198,6 @@ The plugin takes an options object. Defaults are:
|
|
|
153
198
|
|
|
154
199
|
Pass a custom `pagesDir` if your project uses `src/pages` or another convention.
|
|
155
200
|
|
|
156
|
-
## Examples & Demos
|
|
157
|
-
|
|
158
|
-
If you want, I can add a small demo app showing:
|
|
159
|
-
|
|
160
|
-
- A minimal `src/pages` layout with nested layouts
|
|
161
|
-
- How `generateRoutes()` maps files to React Router routes
|
|
162
|
-
- A Vite dev server example showing HMR for page/layout changes
|
|
163
|
-
|
|
164
|
-
Tell me which example you'd prefer and I will scaffold it.
|
|
165
|
-
|
|
166
|
-
## Contributing
|
|
167
|
-
|
|
168
|
-
Contributions welcome. Suggested workflow:
|
|
169
|
-
|
|
170
|
-
1. Fork the repo
|
|
171
|
-
2. Create a branch
|
|
172
|
-
3. Run `pnpm install` and `pnpm run dev` to test locally
|
|
173
|
-
4. Open a PR with description and tests/examples if applicable
|
|
174
|
-
|
|
175
201
|
## License
|
|
176
202
|
|
|
177
|
-
MIT
|
|
203
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import i, {
|
|
2
|
-
import { nextViteRouter as
|
|
1
|
+
import i, { Suspense as g, lazy as z } from "react";
|
|
2
|
+
import { nextViteRouter as D } from "./plugin.js";
|
|
3
3
|
function f(e) {
|
|
4
4
|
return /^\([^)]+\)$/.test(e) ? "" : /^\[\.\.\.(.+)\]$/.test(e) ? "*" : /^\[([^\]]+)\]$/.test(e) ? e.replace(/^\[([^\]]+)\]$/, ":$1") : e;
|
|
5
5
|
}
|
|
@@ -7,78 +7,83 @@ function F(e) {
|
|
|
7
7
|
return e.replace("../../app/", "").replace(/\/?(page|layout|not-found)\.tsx$/, "");
|
|
8
8
|
}
|
|
9
9
|
let m = {};
|
|
10
|
-
function
|
|
10
|
+
function k(e) {
|
|
11
11
|
m = { ...m, ...e };
|
|
12
12
|
}
|
|
13
13
|
function C() {
|
|
14
14
|
return m;
|
|
15
15
|
}
|
|
16
16
|
let d = [];
|
|
17
|
-
function
|
|
17
|
+
function S(e, a) {
|
|
18
18
|
d.push({ pattern: e, middleware: a });
|
|
19
19
|
}
|
|
20
20
|
function T() {
|
|
21
21
|
d = [];
|
|
22
22
|
}
|
|
23
|
-
function
|
|
23
|
+
function E(e, a) {
|
|
24
24
|
let r = a;
|
|
25
25
|
for (const n of d)
|
|
26
26
|
n.pattern.test(e) && (r = n.middleware(r));
|
|
27
27
|
return r;
|
|
28
28
|
}
|
|
29
|
-
const x = () => i.createElement("div"),
|
|
30
|
-
function
|
|
29
|
+
const x = () => i.createElement("div"), y = /* @__PURE__ */ new Map();
|
|
30
|
+
function R(e, a, r) {
|
|
31
31
|
const n = C();
|
|
32
32
|
if (n.enableLazyLoading === !1) {
|
|
33
|
-
const u = i.lazy(e), c = i.createElement(
|
|
34
|
-
|
|
33
|
+
const u = i.lazy(e), c = i.createElement(
|
|
34
|
+
g,
|
|
35
|
+
{ fallback: null },
|
|
36
|
+
// No loading fallback when disabled
|
|
37
|
+
i.createElement(u)
|
|
38
|
+
);
|
|
39
|
+
return r ? E(r, c) : c;
|
|
35
40
|
}
|
|
36
|
-
let t =
|
|
37
|
-
t || (t = z(e),
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
{ fallback: i.createElement(
|
|
41
|
+
let t = y.get(a);
|
|
42
|
+
t || (t = z(e), y.set(a, t));
|
|
43
|
+
const l = n.loadingFallback || x, o = i.createElement(
|
|
44
|
+
g,
|
|
45
|
+
{ fallback: i.createElement(l) },
|
|
41
46
|
i.createElement(t)
|
|
42
47
|
);
|
|
43
|
-
return r ?
|
|
48
|
+
return r ? E(r, o) : o;
|
|
44
49
|
}
|
|
45
50
|
function p(e, a, r, n) {
|
|
46
|
-
const t = F(a),
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
u = u ? `${u}/${c}` : c,
|
|
51
|
+
const t = F(a), l = t ? t.split("/") : [];
|
|
52
|
+
let o = e, u = "";
|
|
53
|
+
l.forEach((c, w) => {
|
|
54
|
+
u = u ? `${u}/${c}` : c, o.children.has(c) || o.children.set(c, {
|
|
50
55
|
segment: c,
|
|
51
56
|
fullPath: u,
|
|
52
57
|
children: /* @__PURE__ */ new Map()
|
|
53
|
-
}),
|
|
54
|
-
}),
|
|
58
|
+
}), o = o.children.get(c), w === l.length - 1 && (o[n] = r);
|
|
59
|
+
}), l.length === 0 && (e[n] = r);
|
|
55
60
|
}
|
|
56
|
-
function
|
|
61
|
+
function L(e, a, r) {
|
|
57
62
|
const n = {
|
|
58
63
|
segment: "",
|
|
59
64
|
fullPath: "",
|
|
60
65
|
children: /* @__PURE__ */ new Map()
|
|
61
66
|
};
|
|
62
|
-
return Object.entries(a).forEach(([t,
|
|
63
|
-
p(n, t,
|
|
64
|
-
}), Object.entries(e).forEach(([t,
|
|
65
|
-
p(n, t,
|
|
66
|
-
}), Object.entries(r).forEach(([t,
|
|
67
|
-
p(n, t,
|
|
67
|
+
return Object.entries(a).forEach(([t, l]) => {
|
|
68
|
+
p(n, t, l.default, "layout");
|
|
69
|
+
}), Object.entries(e).forEach(([t, l]) => {
|
|
70
|
+
p(n, t, l, "page");
|
|
71
|
+
}), Object.entries(r).forEach(([t, l]) => {
|
|
72
|
+
p(n, t, l, "notFound");
|
|
68
73
|
}), n;
|
|
69
74
|
}
|
|
70
75
|
function h(e, a, r = !1) {
|
|
71
|
-
const n =
|
|
76
|
+
const n = R(
|
|
72
77
|
async () => ({ default: (await e.page()).default }),
|
|
73
78
|
`page:${e.fullPath || a}`,
|
|
74
79
|
a
|
|
75
80
|
);
|
|
76
81
|
return r ? { index: !0, element: n } : { path: f(e.segment), element: n };
|
|
77
82
|
}
|
|
78
|
-
function
|
|
83
|
+
function $(e) {
|
|
79
84
|
return {
|
|
80
85
|
path: "*",
|
|
81
|
-
element:
|
|
86
|
+
element: R(
|
|
82
87
|
async () => ({ default: (await e.notFound()).default }),
|
|
83
88
|
`notfound:${e.fullPath}`
|
|
84
89
|
)
|
|
@@ -87,15 +92,15 @@ function y(e) {
|
|
|
87
92
|
function s(e, a) {
|
|
88
93
|
const r = [];
|
|
89
94
|
return e.children.forEach((n, t) => {
|
|
90
|
-
const
|
|
91
|
-
r.push(...
|
|
95
|
+
const l = f(t), o = l ? a ? `${a}/${l}` : `/${l}` : a;
|
|
96
|
+
r.push(...b(n, !1, o));
|
|
92
97
|
}), r;
|
|
93
98
|
}
|
|
94
|
-
function
|
|
99
|
+
function b(e, a = !1, r = "") {
|
|
95
100
|
const n = [];
|
|
96
101
|
if (a && e.layout) {
|
|
97
102
|
const t = [];
|
|
98
|
-
return e.page && t.push(h(e, "/", !0)), t.push(...s(e, "")), e.notFound && t.push(
|
|
103
|
+
return e.page && t.push(h(e, "/", !0)), t.push(...s(e, "")), e.notFound && t.push($(e)), n.push({
|
|
99
104
|
path: "/",
|
|
100
105
|
element: i.createElement(e.layout),
|
|
101
106
|
children: t
|
|
@@ -105,41 +110,41 @@ function R(e, a = !1, r = "") {
|
|
|
105
110
|
const t = f(e.segment);
|
|
106
111
|
if (!t)
|
|
107
112
|
return s(e, r);
|
|
108
|
-
const
|
|
109
|
-
return e.page &&
|
|
113
|
+
const l = r + "/" + t, o = [];
|
|
114
|
+
return e.page && o.push(h(e, l, !0)), o.push(...s(e, l)), e.notFound && o.push($(e)), n.push({
|
|
110
115
|
path: t,
|
|
111
116
|
element: i.createElement(e.layout),
|
|
112
|
-
children:
|
|
117
|
+
children: o.length > 0 ? o : void 0
|
|
113
118
|
}), n;
|
|
114
119
|
}
|
|
115
120
|
if (e.page) {
|
|
116
121
|
const t = f(e.segment);
|
|
117
122
|
if (!t)
|
|
118
123
|
return s(e, r);
|
|
119
|
-
const
|
|
124
|
+
const l = r + "/" + t, o = s(e, l), u = h(e, l, !1);
|
|
120
125
|
return n.push({
|
|
121
126
|
path: u.path,
|
|
122
127
|
element: u.element,
|
|
123
|
-
children:
|
|
128
|
+
children: o.length > 0 ? o : void 0
|
|
124
129
|
}), n;
|
|
125
130
|
}
|
|
126
131
|
return s(e, r);
|
|
127
132
|
}
|
|
128
133
|
function j(e, a, r) {
|
|
129
134
|
return () => {
|
|
130
|
-
const n =
|
|
131
|
-
return
|
|
135
|
+
const n = L(e, a, r);
|
|
136
|
+
return b(n, !0);
|
|
132
137
|
};
|
|
133
138
|
}
|
|
134
139
|
export {
|
|
135
|
-
|
|
140
|
+
L as buildRouteTree,
|
|
136
141
|
T as clearMiddlewares,
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
k as configureRouter,
|
|
143
|
+
R as createLazyElement,
|
|
139
144
|
j as createRouteGenerator,
|
|
140
145
|
F as extractRoutePath,
|
|
141
|
-
|
|
146
|
+
D as nextViteRouter,
|
|
142
147
|
f as normalizeSegment,
|
|
143
|
-
|
|
144
|
-
|
|
148
|
+
S as registerMiddleware,
|
|
149
|
+
b as treeToRoutes
|
|
145
150
|
};
|