olova 2.0.55 → 2.0.57
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 +28 -288
- package/dist/chunk-D7SIC5TC.js +367 -0
- package/dist/chunk-D7SIC5TC.js.map +1 -0
- package/dist/entry-server.cjs +120 -0
- package/dist/entry-server.cjs.map +1 -0
- package/dist/entry-server.js +115 -0
- package/dist/entry-server.js.map +1 -0
- package/dist/entry-worker.cjs +133 -0
- package/dist/entry-worker.cjs.map +1 -0
- package/dist/entry-worker.js +127 -0
- package/dist/entry-worker.js.map +1 -0
- package/dist/main.cjs +18 -0
- package/dist/main.cjs.map +1 -0
- package/dist/main.js +16 -0
- package/dist/main.js.map +1 -0
- package/dist/olova.cjs +1684 -0
- package/dist/olova.cjs.map +1 -0
- package/dist/olova.d.cts +72 -0
- package/dist/olova.d.ts +72 -0
- package/dist/olova.js +1325 -0
- package/dist/olova.js.map +1 -0
- package/dist/performance.cjs +386 -0
- package/dist/performance.cjs.map +1 -0
- package/dist/performance.js +3 -0
- package/dist/performance.js.map +1 -0
- package/dist/router.cjs +646 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +113 -0
- package/dist/router.d.ts +113 -0
- package/dist/router.js +632 -0
- package/dist/router.js.map +1 -0
- package/main.tsx +76 -0
- package/olova.ts +619 -0
- package/package.json +44 -61
- package/src/entry-server.tsx +165 -0
- package/src/entry-worker.tsx +201 -0
- package/src/generator/index.ts +409 -0
- package/src/hydration/flight.ts +320 -0
- package/src/hydration/index.ts +12 -0
- package/src/hydration/types.ts +225 -0
- package/src/logger.ts +182 -0
- package/src/main.tsx +24 -0
- package/src/performance.ts +488 -0
- package/src/plugin/index.ts +204 -0
- package/src/router/ErrorBoundary.tsx +145 -0
- package/src/router/Link.tsx +117 -0
- package/src/router/OlovaRouter.tsx +354 -0
- package/src/router/Outlet.tsx +8 -0
- package/src/router/context.ts +117 -0
- package/src/router/index.ts +29 -0
- package/src/router/matching.ts +63 -0
- package/src/router/router.tsx +23 -0
- package/src/router/search-params.ts +29 -0
- package/src/scanner/index.ts +116 -0
- package/src/types/index.ts +191 -0
- package/src/utils/export.ts +85 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/naming.ts +54 -0
- package/src/utils/path.ts +45 -0
- package/tsup.config.ts +35 -0
- package/CHANGELOG.md +0 -31
- package/LICENSE +0 -21
- package/dist/index.cjs +0 -883
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -138
- package/dist/index.d.ts +0 -138
- package/dist/index.js +0 -832
- package/dist/index.js.map +0 -1
- package/dist/plugin.cjs +0 -927
- package/dist/plugin.cjs.map +0 -1
- package/dist/plugin.d.cts +0 -18
- package/dist/plugin.d.ts +0 -18
- package/dist/plugin.js +0 -894
- package/dist/plugin.js.map +0 -1
- package/dist/ssg.cjs +0 -637
- package/dist/ssg.cjs.map +0 -1
- package/dist/ssg.d.cts +0 -191
- package/dist/ssg.d.ts +0 -191
- package/dist/ssg.js +0 -585
- package/dist/ssg.js.map +0 -1
- package/dist/types-BT6YsBGO.d.cts +0 -143
- package/dist/types-BT6YsBGO.d.ts +0 -143
package/README.md
CHANGED
|
@@ -1,321 +1,61 @@
|
|
|
1
|
-
#
|
|
1
|
+
# vite-plugin-olova
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Olova brings the intuitive file-based routing conventions from Next.js App Router to your Vite + React applications. Build modern web apps with nested layouts, dynamic routes, loading states, and error boundaries - all through your file structure.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- 📁 **File-based routing** - Create routes by adding files to your `app` directory
|
|
10
|
-
- 🏗️ **Nested layouts** - Share UI between routes with layout components
|
|
11
|
-
- 🔄 **Dynamic routes** - Support for `[slug]`, `[...catchAll]`, and route groups `(group)`
|
|
12
|
-
- ⏳ **Loading states** - Per-route loading UI with `loading.tsx`
|
|
13
|
-
- ❌ **Error boundaries** - Per-route error handling with `error.tsx`
|
|
14
|
-
- 🔗 **Client-side navigation** - Seamless SPA navigation with `Link` component
|
|
15
|
-
- 🪝 **React hooks** - `usePathname`, `useParams`, `useSearchParams`, `useRouter`
|
|
16
|
-
- ⚡ **Vite plugin** - Automatic route generation at build time
|
|
3
|
+
A Vite plugin for building SSR/SSG applications with React and the Olova framework.
|
|
17
4
|
|
|
18
5
|
## Installation
|
|
19
6
|
|
|
20
7
|
```bash
|
|
21
|
-
npm install olova
|
|
8
|
+
npm install vite-plugin-olova
|
|
22
9
|
```
|
|
23
10
|
|
|
24
|
-
##
|
|
11
|
+
## Usage
|
|
25
12
|
|
|
26
|
-
|
|
13
|
+
Add the plugin to your `vite.config.ts`:
|
|
27
14
|
|
|
28
|
-
```
|
|
29
|
-
// vite.config.ts
|
|
15
|
+
```typescript
|
|
30
16
|
import { defineConfig } from "vite";
|
|
31
17
|
import react from "@vitejs/plugin-react";
|
|
32
|
-
import { olova } from "olova
|
|
18
|
+
import { olova } from "vite-plugin-olova";
|
|
33
19
|
|
|
34
20
|
export default defineConfig({
|
|
35
21
|
plugins: [
|
|
36
22
|
react(),
|
|
37
23
|
olova({
|
|
38
|
-
|
|
24
|
+
staticPaths: ["/about", "/contact"], // Optional: additional paths to pre-render
|
|
39
25
|
}),
|
|
40
26
|
],
|
|
41
27
|
});
|
|
42
28
|
```
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
src/app/
|
|
48
|
-
├── layout.tsx # Root layout
|
|
49
|
-
├── page.tsx # Home page (/)
|
|
50
|
-
├── loading.tsx # Loading state
|
|
51
|
-
├── error.tsx # Error boundary
|
|
52
|
-
├── about/
|
|
53
|
-
│ └── page.tsx # About page (/about)
|
|
54
|
-
├── blog/
|
|
55
|
-
│ ├── layout.tsx # Blog layout
|
|
56
|
-
│ ├── page.tsx # Blog index (/blog)
|
|
57
|
-
│ └── [slug]/
|
|
58
|
-
│ └── page.tsx # Blog post (/blog/:slug)
|
|
59
|
-
└── (marketing)/
|
|
60
|
-
└── pricing/
|
|
61
|
-
└── page.tsx # Pricing (/pricing) - grouped route
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### 3. Set up the router
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
// src/main.tsx
|
|
68
|
-
import { StrictMode } from "react";
|
|
69
|
-
import { createRoot } from "react-dom/client";
|
|
70
|
-
import { OlovaRouter } from "olova";
|
|
71
|
-
import { routes } from "virtual:olova-routes";
|
|
72
|
-
|
|
73
|
-
createRoot(document.getElementById("root")!).render(
|
|
74
|
-
<StrictMode>
|
|
75
|
-
<OlovaRouter routes={routes} />
|
|
76
|
-
</StrictMode>
|
|
77
|
-
);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## File Conventions
|
|
81
|
-
|
|
82
|
-
| File | Purpose |
|
|
83
|
-
| --------------- | ------------------------------------------------------ |
|
|
84
|
-
| `page.tsx` | UI for the route (required for route to be accessible) |
|
|
85
|
-
| `layout.tsx` | Shared layout wrapping child routes |
|
|
86
|
-
| `loading.tsx` | Loading UI shown while page loads |
|
|
87
|
-
| `error.tsx` | Error UI shown when errors occur |
|
|
88
|
-
| `not-found.tsx` | 404 UI for the route |
|
|
89
|
-
|
|
90
|
-
## Route Patterns
|
|
91
|
-
|
|
92
|
-
### Static Routes
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
app/about/page.tsx → /about
|
|
96
|
-
app/contact/page.tsx → /contact
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Dynamic Routes
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
app/blog/[slug]/page.tsx → /blog/:slug
|
|
103
|
-
app/users/[id]/page.tsx → /users/:id
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Catch-all Routes
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
app/docs/[...slug]/page.tsx → /docs/*
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Route Groups
|
|
113
|
-
|
|
114
|
-
Route groups `(folder)` organize files without affecting the URL:
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
app/(marketing)/pricing/page.tsx → /pricing
|
|
118
|
-
app/(marketing)/about/page.tsx → /about
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## Components
|
|
122
|
-
|
|
123
|
-
### Link
|
|
124
|
-
|
|
125
|
-
Client-side navigation with prefetching:
|
|
126
|
-
|
|
127
|
-
```tsx
|
|
128
|
-
import { Link } from 'olova';
|
|
129
|
-
|
|
130
|
-
<Link href="/about">About</Link>
|
|
131
|
-
<Link href="/blog/my-post" replace>Blog Post</Link>
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### NavLink
|
|
135
|
-
|
|
136
|
-
Navigation link with active state:
|
|
137
|
-
|
|
138
|
-
```tsx
|
|
139
|
-
import { NavLink } from "olova";
|
|
140
|
-
|
|
141
|
-
<NavLink href="/dashboard" activeClassName="text-blue-500" exact>
|
|
142
|
-
Dashboard
|
|
143
|
-
</NavLink>;
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Hooks
|
|
147
|
-
|
|
148
|
-
### usePathname
|
|
149
|
-
|
|
150
|
-
Get the current pathname:
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
import { usePathname } from "olova";
|
|
154
|
-
|
|
155
|
-
function Component() {
|
|
156
|
-
const pathname = usePathname();
|
|
157
|
-
return <div>Current path: {pathname}</div>;
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### useParams
|
|
162
|
-
|
|
163
|
-
Access route parameters:
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
import { useParams } from "olova";
|
|
167
|
-
|
|
168
|
-
function BlogPost() {
|
|
169
|
-
const { slug } = useParams<{ slug: string }>();
|
|
170
|
-
return <div>Reading: {slug}</div>;
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### useSearchParams
|
|
175
|
-
|
|
176
|
-
Access URL search parameters:
|
|
177
|
-
|
|
178
|
-
```tsx
|
|
179
|
-
import { useSearchParams } from "olova";
|
|
180
|
-
|
|
181
|
-
function SearchPage() {
|
|
182
|
-
const searchParams = useSearchParams();
|
|
183
|
-
const query = searchParams.get("q");
|
|
184
|
-
return <div>Searching for: {query}</div>;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### useRouter
|
|
189
|
-
|
|
190
|
-
Programmatic navigation:
|
|
191
|
-
|
|
192
|
-
```tsx
|
|
193
|
-
import { useRouter } from "olova";
|
|
194
|
-
|
|
195
|
-
function Component() {
|
|
196
|
-
const router = useRouter();
|
|
197
|
-
|
|
198
|
-
return (
|
|
199
|
-
<button onClick={() => router.push("/dashboard")}>Go to Dashboard</button>
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Router methods:
|
|
205
|
-
|
|
206
|
-
- `push(url)` - Navigate to URL
|
|
207
|
-
- `replace(url)` - Navigate without adding to history
|
|
208
|
-
- `back()` - Go back
|
|
209
|
-
- `forward()` - Go forward
|
|
210
|
-
- `refresh()` - Refresh current route
|
|
211
|
-
- `prefetch(url)` - Prefetch a route
|
|
212
|
-
|
|
213
|
-
## Page Props
|
|
214
|
-
|
|
215
|
-
Pages receive `params` and `searchParams`:
|
|
216
|
-
|
|
217
|
-
```tsx
|
|
218
|
-
// app/blog/[slug]/page.tsx
|
|
219
|
-
interface PageProps {
|
|
220
|
-
params: { slug: string };
|
|
221
|
-
searchParams: Record<string, string>;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export default function BlogPost({ params, searchParams }: PageProps) {
|
|
225
|
-
return (
|
|
226
|
-
<article>
|
|
227
|
-
<h1>Post: {params.slug}</h1>
|
|
228
|
-
</article>
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## Layout Props
|
|
234
|
-
|
|
235
|
-
Layouts receive `children` and `params`:
|
|
236
|
-
|
|
237
|
-
```tsx
|
|
238
|
-
// app/blog/layout.tsx
|
|
239
|
-
interface LayoutProps {
|
|
240
|
-
children: React.ReactNode;
|
|
241
|
-
params: { slug?: string };
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export default function BlogLayout({ children }: LayoutProps) {
|
|
245
|
-
return (
|
|
246
|
-
<div className="blog-layout">
|
|
247
|
-
<nav>Blog Navigation</nav>
|
|
248
|
-
<main>{children}</main>
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## Error Handling
|
|
30
|
+
## How It Works
|
|
255
31
|
|
|
256
|
-
|
|
32
|
+
The plugin provides:
|
|
257
33
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
error: Error;
|
|
262
|
-
reset: () => void;
|
|
263
|
-
}
|
|
34
|
+
1. **`vite-plugin-olova`** - The main Vite plugin
|
|
35
|
+
2. **`vite-plugin-olova/entry-client`** - Client-side hydration entry
|
|
36
|
+
3. **`vite-plugin-olova/entry-server`** - Server-side rendering entry
|
|
264
37
|
|
|
265
|
-
|
|
266
|
-
return (
|
|
267
|
-
<div>
|
|
268
|
-
<h2>Something went wrong!</h2>
|
|
269
|
-
<p>{error.message}</p>
|
|
270
|
-
<button onClick={reset}>Try again</button>
|
|
271
|
-
</div>
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Loading States
|
|
277
|
-
|
|
278
|
-
Create `loading.tsx` for loading UI:
|
|
279
|
-
|
|
280
|
-
```tsx
|
|
281
|
-
// app/blog/loading.tsx
|
|
282
|
-
export default function BlogLoading() {
|
|
283
|
-
return (
|
|
284
|
-
<div className="animate-pulse">
|
|
285
|
-
<div className="h-8 bg-gray-200 rounded w-3/4 mb-4" />
|
|
286
|
-
<div className="h-4 bg-gray-200 rounded w-full mb-2" />
|
|
287
|
-
<div className="h-4 bg-gray-200 rounded w-5/6" />
|
|
288
|
-
</div>
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
## Plugin Options
|
|
38
|
+
The entry files use `virtual:olova-app` which resolves to your app's route configuration from `@/route.tree`.
|
|
294
39
|
|
|
295
|
-
|
|
296
|
-
olova({
|
|
297
|
-
// Directory containing routes (default: 'src/app')
|
|
298
|
-
appDir: "src/app",
|
|
40
|
+
## Features
|
|
299
41
|
|
|
300
|
-
|
|
301
|
-
|
|
42
|
+
- **SSR (Server-Side Rendering)**: Full server-side rendering support during development
|
|
43
|
+
- **SSG (Static Site Generation)**: Automatically generates static HTML files at build time
|
|
44
|
+
- **Route-based code splitting**: Lazy loading for optimal performance
|
|
45
|
+
- **Hydration**: Seamless client-side hydration
|
|
302
46
|
|
|
303
|
-
|
|
304
|
-
basePath: "",
|
|
47
|
+
## Options
|
|
305
48
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
```
|
|
49
|
+
| Option | Type | Description |
|
|
50
|
+
| ------------- | ---------- | ----------------------------------------------- |
|
|
51
|
+
| `staticPaths` | `string[]` | Additional paths to pre-render during SSG build |
|
|
310
52
|
|
|
311
|
-
##
|
|
53
|
+
## Peer Dependencies
|
|
312
54
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
import type { PageProps, LayoutProps, ErrorProps, LoadingProps } from "olova";
|
|
317
|
-
```
|
|
55
|
+
- `react` >= 18.0.0
|
|
56
|
+
- `react-dom` >= 18.0.0
|
|
57
|
+
- `vite` >= 5.0.0
|
|
318
58
|
|
|
319
59
|
## License
|
|
320
60
|
|
|
321
|
-
MIT
|
|
61
|
+
MIT
|