routerino 2.6.1 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -1197
- package/docs/README.md +8 -0
- package/docs/accessibility.md +87 -0
- package/docs/additional-resources.md +6 -0
- package/docs/getting-started.md +134 -0
- package/docs/image-optimization.md +30 -0
- package/docs/seo-guide.md +137 -0
- package/docs/vendoring.md +30 -0
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -1,50 +1,26 @@
|
|
|
1
|
-
# Routerino
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Why
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- Static Site Generation: Build-tool agnostic static HTML generation for improved performance and SEO
|
|
15
|
-
- Prerender Ready: Works with prerender servers (such as prerender/prerender) via dedicated meta tags for correct crawler status codes
|
|
16
|
-
- Single File Core: The entire routing logic fits in one file, making it easy to understand and customize
|
|
17
|
-
|
|
18
|
-
## Table of Contents
|
|
19
|
-
|
|
20
|
-
- [Features](#features)
|
|
21
|
-
- [Installation](#installation)
|
|
22
|
-
- [Usage](#usage)
|
|
23
|
-
- [Props](#props-arguments)
|
|
24
|
-
- [useRouterino Hook](#using-the-userouterino-hook)
|
|
25
|
-
- [updateHeadTag](#updateheadtag)
|
|
26
|
-
- [Image Component](#image-component)
|
|
27
|
-
- [Optimization](#optimization)
|
|
28
|
-
- [Image Props](#image-props)
|
|
29
|
-
- [Image Usage Examples](#image-usage-examples)
|
|
30
|
-
- [TypeScript Support](#typescript-support)
|
|
31
|
-
- [Best Practices](#routerino-best-practices)
|
|
32
|
-
- [Generating a Sitemap](#generating-a-sitemap-from-routes)
|
|
33
|
-
- [Static Site Generation](#static-site-generation)
|
|
34
|
-
- [How-to Guides & Examples](#how-to-guides--example-code)
|
|
35
|
-
- [Starting a New Project](#starting-a-new-react-project-with-routerino)
|
|
36
|
-
- [Full React Example](#full-react-example)
|
|
37
|
-
- [Basic Example](#basic-example)
|
|
38
|
-
- [ErrorBoundary Component](#errorboundary-component)
|
|
39
|
-
- [Vendoring Routerino](#vendoring-routerino)
|
|
40
|
-
- [Additional Resources](#additional-resources)
|
|
41
|
-
- [Contributions](#contributions)
|
|
42
|
-
- [License](#license)
|
|
1
|
+
# Routerino — The React router that Google can read.
|
|
2
|
+
|
|
3
|
+
> React routing with built-in SEO. No framework, no lock-in.
|
|
4
|
+
|
|
5
|
+
**Live demos:** [raymondsseptic.com](https://raymondsseptic.com) · [kissimmeekastawayvilla.com](https://kissimmeekastawayvilla.com) · [nerdswithkeyboards.com](https://nerdswithkeyboards.com)· [logbook-ed.com](https://logbook-ed.com)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
React SPAs are fast for users but invisible to search engines. The standard answer — Next.js or Remix — forces a full framework adoption, new conventions, and vendor lock-in for what should be a solved problem: **generating static HTML with proper meta tags at build time.**
|
|
12
|
+
|
|
13
|
+
Routerino gives you that. Zero added dependencies, standard `<a>` tags, and a Vite plugin that generates complete static HTML including meta tags, Open Graph tags, canonical URLs, sitemap.xml, and robots.txt. You keep your SPA developer experience. Google gets readable pages.
|
|
43
14
|
|
|
44
15
|
## Quick Start
|
|
45
16
|
|
|
17
|
+
```sh
|
|
18
|
+
npm i routerino
|
|
19
|
+
```
|
|
20
|
+
|
|
46
21
|
```jsx
|
|
47
|
-
|
|
22
|
+
import Routerino from "routerino";
|
|
23
|
+
|
|
48
24
|
export const routes = [
|
|
49
25
|
{
|
|
50
26
|
path: "/",
|
|
@@ -69,29 +45,18 @@ export const routes = [
|
|
|
69
45
|
<Routerino title="Example.com" routes={routes} />;
|
|
70
46
|
```
|
|
71
47
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
## Features
|
|
75
|
-
|
|
76
|
-
- Routing
|
|
77
|
-
- Easy integration of simple routing for your React app (supports React 18 and 19)
|
|
78
|
-
- Zero dependencies for lighter, more maintainable projects
|
|
79
|
-
- No special link components required, works great for Markdown-based pages and semantic HTML
|
|
80
|
-
|
|
81
|
-
- SEO Optimization
|
|
82
|
-
- Configure title, description, and image for each route
|
|
83
|
-
- Set `<head>` tags for any route (either directly in your routes config, or dynamically after rendering)
|
|
84
|
-
- Set a site-wide name to be included with page titles
|
|
85
|
-
- Automatically generate and maintain an up-to-date `sitemap.xml` from your routes
|
|
86
|
-
- Generate static HTML files for each route with proper meta tags
|
|
87
|
-
- Implement SEO best practices out-of-the-box
|
|
88
|
-
- Optimize for Googlebot with pre-rendering support
|
|
89
|
-
- Delegate image optimization to `vite-plugin-image-optimizer`
|
|
48
|
+
## What It Does
|
|
90
49
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
50
|
+
| Feature | Routerino | React Router | Next.js | Gatsby | Remix |
|
|
51
|
+
| ---------------------- | ----------------------- | -------------------- | -------------------- | -------------------- | -------------------- |
|
|
52
|
+
| SSG (static HTML) | ✅ Built-in Vite plugin | ❌ | ✅ Built-in | ✅ Core feature | ✅ Built-in |
|
|
53
|
+
| Meta tags / Open Graph | ✅ Per-route, automatic | ❌ | ✅ Metadata API | ✅ Via plugin | ✅ meta export |
|
|
54
|
+
| Sitemap generation | ✅ Automatic | ❌ | ❌ Manual | ✅ Via plugin | ❌ Manual |
|
|
55
|
+
| Canonical URLs | ✅ Automatic | ❌ | ❌ Manual | ❌ Manual | ❌ Manual |
|
|
56
|
+
| Standard `<a>` tags | ✅ No `<Link>` needed | ❌ Must use `<Link>` | ❌ Must use `<Link>` | ❌ Must use `<Link>` | ❌ Must use `<Link>` |
|
|
57
|
+
| Runtime dependencies | 0 (peer: react) | 3+ | 50+ | 100+ | 20+ |
|
|
58
|
+
| Prerender support | ✅ Built-in | ❌ | ✅ ISR | ✅ SSG | ✅ Built-in |
|
|
59
|
+
| Library, not framework | ✅ | ✅ | ❌ | ❌ | ❌ |
|
|
95
60
|
|
|
96
61
|
## Installation
|
|
97
62
|
|
|
@@ -99,683 +64,94 @@ This simple configuration automatically handles routing, meta tags, and SEO opti
|
|
|
99
64
|
npm i routerino
|
|
100
65
|
```
|
|
101
66
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
### Compatibility
|
|
105
|
-
|
|
106
|
-
Routerino supports:
|
|
107
|
-
|
|
108
|
-
- React 18 and 19: Both versions are tested and supported. React 17 works for CSR-only.
|
|
109
|
-
- Node.js 18+: Tested on Node.js 18, 20, 22, and 24. Could be used on earlier versions if we skip tests.
|
|
110
|
-
- Preact: Compatible via `@preact/compat`. See [using Preact](#using-preact) below.
|
|
67
|
+
Routerino requires React, React DOM, and PropTypes as peer dependencies (typically already installed). Supports React 18/19 and Node.js 18+.
|
|
111
68
|
|
|
112
69
|
## Usage
|
|
113
70
|
|
|
114
|
-
|
|
71
|
+
### Route Configuration
|
|
72
|
+
|
|
73
|
+
Routes are plain objects. At minimum, each needs a `path` and `element`:
|
|
115
74
|
|
|
116
75
|
```jsx
|
|
117
76
|
export const routes = [
|
|
118
77
|
{
|
|
119
78
|
path: "/",
|
|
120
|
-
element: <
|
|
121
|
-
title: "
|
|
122
|
-
description: "Welcome to
|
|
79
|
+
element: <HomePage />,
|
|
80
|
+
title: "Home",
|
|
81
|
+
description: "Welcome to our site",
|
|
123
82
|
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Links are just standard HTML anchor tags. No need to use special `<Link>` components—you can use whatever components or design system you like. For example: <a href="/some-page/">a link</a> is perfectly valid. This is very handy for markdown-based content. With standard link support in Routerino, you won't need to [transform your markdown content with custom React components](https://github.com/remarkjs/react-markdown?tab=readme-ov-file#appendix-b-components).
|
|
133
|
-
|
|
134
|
-
Routerino handles same-origin anchor clicks via SPA navigation. The browser handles the rest natively, including:
|
|
135
|
-
|
|
136
|
-
- **Cross-origin links** (different domain)
|
|
137
|
-
- **Non-HTTP schemes** (mailto:, tel:, javascript:, etc.)
|
|
138
|
-
- **Modified clicks** (Ctrl/Cmd+click, Shift+click, Alt+click, right-click)
|
|
139
|
-
- **`target="_blank"`** links
|
|
140
|
-
- **`download`** attribute links
|
|
141
|
-
- **`rel="external"`** links
|
|
142
|
-
- **File extension links** — PDFs, ZIPs, images, fonts, videos, JSON, XML, and 50+ other file types are recognized automatically
|
|
143
|
-
- **Custom patterns** — use the [`ignorePatterns`](#ignorepatterns-string) prop for additional exclusions (e.g., `/api/`, `/legacy/`)
|
|
144
|
-
|
|
145
|
-
### Programmatic Navigation
|
|
146
|
-
|
|
147
|
-
<details>
|
|
148
|
-
<summary style="cursor:pointer;font-style:italic">Navigate programmatically using standard browser APIs (expand for details)</summary>
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
// Using History API
|
|
152
|
-
window.history.pushState({}, "", "/about/");
|
|
153
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
154
|
-
|
|
155
|
-
// Working with URL and search params
|
|
156
|
-
const url = new URL(window.location);
|
|
157
|
-
url.searchParams.set("page", "2");
|
|
158
|
-
window.history.pushState({}, "", url.toString());
|
|
159
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
</details>
|
|
163
|
-
|
|
164
|
-
See [props](#props-arguments) for full explanations and [example code](#how-to-guides--example-code) for more complete code samples.
|
|
165
|
-
|
|
166
|
-
### Using Preact
|
|
167
|
-
|
|
168
|
-
Routerino is fully compatible with Preact via the `@preact/compat` compatibility layer. This allows you to use Routerino in Preact projects with the same API.
|
|
169
|
-
|
|
170
|
-
#### Setup Instructions
|
|
171
|
-
|
|
172
|
-
1. Install Preact and the compatibility layer:
|
|
173
|
-
|
|
174
|
-
```sh
|
|
175
|
-
npm i preact @preact/compat
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
2. Configure your bundler to alias React to @preact/compat:
|
|
179
|
-
|
|
180
|
-
**Vite Configuration:**
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
// vite.config.js
|
|
184
|
-
import { defineConfig } from "vite";
|
|
185
|
-
import preact from "@preact/preset-vite";
|
|
186
|
-
|
|
187
|
-
export default defineConfig({
|
|
188
|
-
plugins: [preact()],
|
|
189
|
-
resolve: {
|
|
190
|
-
alias: {
|
|
191
|
-
react: "@preact/compat",
|
|
192
|
-
"react-dom": "@preact/compat",
|
|
193
|
-
"react/jsx-runtime": "@preact/compat/jsx-runtime",
|
|
194
|
-
},
|
|
83
|
+
{
|
|
84
|
+
path: "/about/",
|
|
85
|
+
element: <AboutPage />,
|
|
86
|
+
title: "About Us",
|
|
87
|
+
description: "Learn more about our team",
|
|
88
|
+
imageUrl: "/images/about-og.jpg",
|
|
195
89
|
},
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
**Webpack Configuration:**
|
|
200
|
-
|
|
201
|
-
```js
|
|
202
|
-
// webpack.config.js
|
|
203
|
-
module.exports = {
|
|
204
|
-
resolve: {
|
|
205
|
-
alias: {
|
|
206
|
-
react: "preact/compat",
|
|
207
|
-
"react-dom": "preact/compat",
|
|
208
|
-
},
|
|
90
|
+
{
|
|
91
|
+
path: "/products/:id/", // dynamic route — not statically generated
|
|
92
|
+
element: <ProductPage />,
|
|
209
93
|
},
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
3. Use Routerino exactly as you would in a React project - the API is identical!
|
|
214
|
-
|
|
215
|
-
### Props (arguments)
|
|
216
|
-
|
|
217
|
-
The table below shows all available props with their default values. See the [usage](#usage) section for examples.
|
|
218
|
-
|
|
219
|
-
#### Routerino props
|
|
220
|
-
|
|
221
|
-
All of these are optional, so it's easy to get started with nothing but a bare-bones `<Routerino />` element, to get started with a working sample page. The main props you'll need are `routes` and `title`. See [RouteConfig props](#routeconfig-props) for the route format.
|
|
222
|
-
|
|
223
|
-
| Prop | Type | Description | Default |
|
|
224
|
-
| ---------------------------------------------- | --------------- | --------------------------------- | ----------------------------- |
|
|
225
|
-
| [title](#title-string) | string | The site title | `""` |
|
|
226
|
-
| [routes](#routes-array-of-routeconfig-objects) | RouteConfig[] | Array of route configurations | `[Default Route Object]` |
|
|
227
|
-
| [separator](#separator-string) | string | Title separator | `" \| "` |
|
|
228
|
-
| [notFoundTemplate](#notfoundtemplate-element) | React.ReactNode | 404 page template | `<DefaultNotFoundTemplate />` |
|
|
229
|
-
| [notFoundTitle](#notfoundtitle-string) | string | 404 page title | `"Page not found [404]"` |
|
|
230
|
-
| [errorTemplate](#errortemplate-element) | React.ReactNode | Error page template | `<DefaultErrorTemplate />` |
|
|
231
|
-
| [errorTitle](#errortitle-string) | string | Error page title | `"Page error [500]"` |
|
|
232
|
-
| [useTrailingSlash](#usetrailingslash-bool) | boolean | Use trailing slashes in URLs | `true` |
|
|
233
|
-
| [usePrerenderTags](#useprerendertags-bool) | boolean | Use pre-render meta tags | `false` |
|
|
234
|
-
| [baseUrl](#baseurl-string) | string | Base URL for canonical tags | `null` (uses window.location) |
|
|
235
|
-
| [imageUrl](#imageurl-string) | string | Default image URL for sharing | `null` |
|
|
236
|
-
| [touchIconUrl](#touchiconurl-string) | string | Image URL for PWA homescreen icon | `null` |
|
|
237
|
-
| [debug](#debug-boolean) | boolean | Enable debug mode | `false` |
|
|
238
|
-
| [ignorePatterns](#ignorepatterns-string) | string[] | URL patterns to skip SPA routing | `[]` |
|
|
239
|
-
|
|
240
|
-
##### `title`: string;
|
|
241
|
-
|
|
242
|
-
The site title, such as "Foo.com". This will be appended to your page's title with a default separator. For example: "Page Title | Foo.com"
|
|
243
|
-
|
|
244
|
-
##### `routes`: array of `RouteConfig` objects;
|
|
245
|
-
|
|
246
|
-
See [RouteConfig props](#routeconfig-props) for more details. At a minimum a path and React element are required for each route.
|
|
247
|
-
|
|
248
|
-
- path: string;
|
|
249
|
-
- element: React.ReactNode;
|
|
250
|
-
- title?: string;
|
|
251
|
-
- description?: string;
|
|
252
|
-
- tags?: HeadTag[];
|
|
253
|
-
- imageUrl?: string;
|
|
254
|
-
|
|
255
|
-
##### `separator`: string;
|
|
256
|
-
|
|
257
|
-
A string to separate the page title from the site title. The default is `" | "` (a pipe character w/space around). Set this to customize the separator.
|
|
258
|
-
|
|
259
|
-
##### `notFoundTemplate`: element;
|
|
260
|
-
|
|
261
|
-
Any React element for the default (or no) route match.
|
|
262
|
-
|
|
263
|
-
Default:
|
|
264
|
-
|
|
265
|
-
```jsx
|
|
266
|
-
<>
|
|
267
|
-
<p>No page found for this URL. [404]</p>
|
|
268
|
-
<p>
|
|
269
|
-
<a href="/">Home</a>
|
|
270
|
-
</p>
|
|
271
|
-
</>
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
##### `notFoundTitle`: string;
|
|
275
|
-
|
|
276
|
-
A title string for no route match.
|
|
277
|
-
|
|
278
|
-
Default: `"Page not found [404]"`
|
|
279
|
-
|
|
280
|
-
##### `errorTemplate`: element;
|
|
281
|
-
|
|
282
|
-
Any React element for uncaught exceptions.
|
|
283
|
-
|
|
284
|
-
Default:
|
|
285
|
-
|
|
286
|
-
```jsx
|
|
287
|
-
<>
|
|
288
|
-
<p>Page failed to load. [500]</p>
|
|
289
|
-
<p>
|
|
290
|
-
<a href="/">Home</a>
|
|
291
|
-
</p>
|
|
292
|
-
</>
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
##### `errorTitle`: string;
|
|
296
|
-
|
|
297
|
-
A title string for uncaught exceptions.
|
|
298
|
-
|
|
299
|
-
Default: `"Page error [500]"`
|
|
300
|
-
|
|
301
|
-
##### `useTrailingSlash`: bool;
|
|
302
|
-
|
|
303
|
-
Use trailing slashes as the canonical URL. See best practices section for an explanation.
|
|
304
|
-
|
|
305
|
-
Default: `true`
|
|
306
|
-
|
|
307
|
-
##### `usePrerenderTags`: bool;
|
|
308
|
-
|
|
309
|
-
Include prerender-specific meta tags to enable proper error codes like 404 when serving prerendered pages to a search crawler. This means that Routerino uses <meta name="prerender-status-code" content="..."> and <meta name="prerender-header" content="Location: ..."> to signal status codes and redirects to prerender servers.
|
|
310
|
-
|
|
311
|
-
Default: `false`
|
|
312
|
-
|
|
313
|
-
##### `baseUrl`: string;
|
|
314
|
-
|
|
315
|
-
The base URL to use for canonical tags and og:url meta tags. If not provided, uses `window.location.origin`.
|
|
316
|
-
|
|
317
|
-
This is useful when your site is accessible from multiple domains (for example, both example.com and example.net point to the same app). Set it to the preferred domain and all canonical and og:url tags will consistently point there. Also helpful for pinning to the production URL in development or staging environments.
|
|
318
|
-
|
|
319
|
-
**Important:** The baseUrl must NOT end with a trailing slash (`/`). Correct example: `"https://example.com"`
|
|
320
|
-
|
|
321
|
-
Default: `null` (uses window.location.origin)
|
|
322
|
-
|
|
323
|
-
##### `imageUrl`: string;
|
|
324
|
-
|
|
325
|
-
A string containing the path of the default (site-wide) image to use for sharing previews.
|
|
326
|
-
|
|
327
|
-
Default: `null`
|
|
328
|
-
|
|
329
|
-
##### `touchIconUrl`: string;
|
|
330
|
-
|
|
331
|
-
A string containing the path of the image to use for PWA homescreen icon.
|
|
332
|
-
|
|
333
|
-
Default: `null`
|
|
334
|
-
|
|
335
|
-
##### `debug`: boolean;
|
|
336
|
-
|
|
337
|
-
Enable debug mode for additional logging and information. When enabled, Routerino logs detailed information to the console including:
|
|
338
|
-
|
|
339
|
-
- Route changes and pattern matching
|
|
340
|
-
- Meta tag updates
|
|
341
|
-
- Error boundaries and component failures
|
|
342
|
-
- Performance timing information
|
|
343
|
-
|
|
344
|
-
Example debug output:
|
|
345
|
-
|
|
346
|
-
```
|
|
347
|
-
[Routerino] Route changed to: /products/laptop/
|
|
348
|
-
[Routerino] Matched pattern: /products/:id/
|
|
349
|
-
[Routerino] Route params: { id: "laptop" }
|
|
350
|
-
[Routerino] Updated meta tag: og:title = "Laptop Pro - $1299"
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
Default: `false`
|
|
354
|
-
|
|
355
|
-
##### `ignorePatterns`: string[];
|
|
356
|
-
|
|
357
|
-
An array of regex pattern strings to match against link hrefs. Any same-origin link matching one of these patterns will **not** be intercepted by the SPA router — the browser will handle the navigation natively instead.
|
|
358
|
-
|
|
359
|
-
Patterns are tested case-insensitively against the full resolved href (including origin).
|
|
360
|
-
|
|
361
|
-
```jsx
|
|
362
|
-
// Skip API endpoints and a legacy section
|
|
363
|
-
<Routerino routes={routes} ignorePatterns={["/api/", "/admin/legacy/"]} />
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
Routerino also has a built-in list of file extensions that are automatically skipped: `.pdf`, `.zip`, `.docx`, `.png`, `.jpg`, `.svg`, `.mp4`, `.json`, `.xml`, `.csv`, `.txt`, `.ico`, `.woff2`, `.woff`, `.ttf`, `.mp3`, `.wav`, `.epub`, `.map`, `.css`, `.js`, `.wasm`, and many more. The `ignorePatterns` prop is for additional custom patterns beyond these defaults.
|
|
367
|
-
|
|
368
|
-
Default: `[]`
|
|
369
|
-
|
|
370
|
-
#### RouteConfig props
|
|
371
|
-
|
|
372
|
-
There is a default RouteConfig that will be loaded if you don't specify any routes. The default route is a basic template that can confirm your app is working and routing is good to go.
|
|
373
|
-
|
|
374
|
-
##### path: string;
|
|
375
|
-
|
|
376
|
-
The path of the desired route. **Must start with a forward slash (`/`)**. For example: `"/foo/"`, or `"/about/"`. Supported dynamic segments use the :param syntax (e.g., /products/:id/). Wildcards, optional segments, and splats are not supported. Params are matched by position; decode values in your components if needed.
|
|
377
|
-
|
|
378
|
-
##### element: React.ReactNode;
|
|
379
|
-
|
|
380
|
-
The React element to be rendered at the desired route, for example: `<FooPage />`
|
|
381
|
-
|
|
382
|
-
##### title?: string;
|
|
383
|
-
|
|
384
|
-
The page's title, which should not include the site's title. For example: `"Contact Us"`
|
|
385
|
-
|
|
386
|
-
##### description?: string;
|
|
387
|
-
|
|
388
|
-
The page's description, which will show up on search results pages.
|
|
389
|
-
|
|
390
|
-
##### tags?: HeadTag[];
|
|
391
|
-
|
|
392
|
-
Any desired head tags for that route. See [HeadTag props](#headtag-props) for details.
|
|
393
|
-
|
|
394
|
-
##### imageUrl?: string;
|
|
395
|
-
|
|
396
|
-
An image URL to set for the page's og:image tag.
|
|
397
|
-
|
|
398
|
-
#### HeadTag props
|
|
399
|
-
|
|
400
|
-
An array of HeadTag objects that can be added to the route to manage meta tags, links, and other elements in the `<head>` section of the HTML document. These HeadTag objects are processed by the `updateHeadTag` function to update or create a `<head>` child tag (usually `<meta>` tags). The available props and most common tag attributes are listed below, but any arbitrary tag attributes are supported. See the [updateHeadTag section](#updateheadtag) for more details.
|
|
401
|
-
|
|
402
|
-
- `tag` (string, default: "meta"): The HTML element to update or create. By default, it is set to "meta", but you can specify other tags like "link" or "title".
|
|
403
|
-
|
|
404
|
-
- `soft` (boolean, default: false): When set to `true`, it prevents overwriting the value of an existing tag if it already exists. This is useful when you want to preserve existing tag attributes.
|
|
405
|
-
|
|
406
|
-
- `name` (string): The "name" attribute of the tag. Commonly used for meta tags to specify the name of the metadata.
|
|
407
|
-
|
|
408
|
-
- `property` (string): The "property" attribute of the tag. Used for Open Graph (OG) meta tags to define specific OG properties.
|
|
409
|
-
|
|
410
|
-
- `content` (string): The "content" attribute of the tag. Specifies the value or content of the metadata. Sometimes two distinct meta tags may share identical content, so it's not used for matching.
|
|
411
|
-
|
|
412
|
-
- `charset` (string): The "charset" attribute of the tag. Defines the character encoding for the document.
|
|
413
|
-
|
|
414
|
-
- `httpEquiv` (string): The "http-equiv" attribute of the tag. Used for defining HTTP headers for the document.
|
|
415
|
-
|
|
416
|
-
- `itemProp` (string): The "itemProp" attribute of the tag. Used for adding schema.org microdata to the tag.
|
|
417
|
-
|
|
418
|
-
- `rel` (string): The "rel" attribute of the tag. Specifies the relationship between the current document and the linked resource.
|
|
419
|
-
|
|
420
|
-
- `href` (string): The "href" attribute of the tag. Specifies the URL of the linked resource.
|
|
421
|
-
|
|
422
|
-
- `src` (string): The "src" attribute of the tag. Specifies the URL of an external resource, such as an image or script.
|
|
423
|
-
|
|
424
|
-
- `sizes` (string): The "sizes" attribute of the tag. Defines the sizes of the linked resource, commonly used for favicon links.
|
|
425
|
-
|
|
426
|
-
- `type` (string): The "type" attribute of the tag. Specifies the MIME type of the linked resource.
|
|
427
|
-
|
|
428
|
-
- `media` (string): The "media" attribute of the tag. Defines the media or device the linked resource is optimized for.
|
|
429
|
-
|
|
430
|
-
- `hrefLang` (string): The "hrefLang" attribute of the tag. Specifies the language of the linked resource.
|
|
431
|
-
|
|
432
|
-
- `target` (string): The "target" attribute of the tag. Defines where to open the linked resource.
|
|
433
|
-
|
|
434
|
-
- `innerHTML` (string): Inner HTML content for tags that require a closing tag, such as `<script>` and `<style>`. When provided, the tag is rendered as `<tag attrs>innerHTML</tag>` instead of a self-closing element. This enables structured data (JSON-LD), inline CSS, and other tag-body content.
|
|
435
|
-
|
|
436
|
-
##### Structured Data Example
|
|
437
|
-
|
|
438
|
-
```jsx
|
|
439
|
-
{
|
|
440
|
-
path: "/about/",
|
|
441
|
-
element: <AboutPage />,
|
|
442
|
-
tags: [{
|
|
443
|
-
tag: "script",
|
|
444
|
-
type: "application/ld+json",
|
|
445
|
-
innerHTML: JSON.stringify({
|
|
446
|
-
"@context": "https://schema.org",
|
|
447
|
-
"@type": "BreadcrumbList",
|
|
448
|
-
itemListElement: [
|
|
449
|
-
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
|
|
450
|
-
{ "@type": "ListItem", "position": 2, "name": "About", "item": "https://example.com/about/" },
|
|
451
|
-
],
|
|
452
|
-
}),
|
|
453
|
-
}],
|
|
454
|
-
}
|
|
94
|
+
];
|
|
455
95
|
```
|
|
456
96
|
|
|
457
|
-
|
|
97
|
+
Links are standard `<a>` tags. Routerino intercepts same-origin clicks for SPA navigation; the browser handles everything else (cross-origin links, `mailto:`, `target="_blank"`, file downloads, etc.) automatically.
|
|
458
98
|
|
|
459
|
-
###
|
|
99
|
+
### The `useRouterino` Hook
|
|
460
100
|
|
|
461
|
-
|
|
101
|
+
Access router state from any component:
|
|
462
102
|
|
|
463
103
|
```jsx
|
|
464
104
|
import { useRouterino } from "routerino";
|
|
465
105
|
|
|
466
|
-
function
|
|
106
|
+
function ProductPage() {
|
|
467
107
|
const { currentRoute, params, routePattern, updateHeadTag } = useRouterino();
|
|
468
108
|
|
|
469
|
-
// Access current route information
|
|
470
|
-
console.log("Current path:", currentRoute); // e.g., "/products/laptop/"
|
|
471
|
-
console.log("Route pattern:", routePattern); // e.g., "/products/:id/"
|
|
472
|
-
console.log("Route params:", params); // e.g., { id: "laptop" }
|
|
473
|
-
|
|
474
|
-
// Update meta tags dynamically
|
|
475
109
|
useEffect(() => {
|
|
476
|
-
updateHeadTag({
|
|
477
|
-
name: "description",
|
|
478
|
-
content: `Product page for ${params.id}`,
|
|
479
|
-
});
|
|
110
|
+
updateHeadTag({ name: "description", content: `Product: ${params.id}` });
|
|
480
111
|
}, [params.id]);
|
|
481
112
|
|
|
482
113
|
return <div>Product: {params.id}</div>;
|
|
483
114
|
}
|
|
484
115
|
```
|
|
485
116
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
- **`currentRoute`**: The current URL path (e.g., `/foo/bar/`)
|
|
489
|
-
- **`routePattern`**: The matched route pattern with parameters (e.g., `/foo/:id/`)
|
|
490
|
-
- **`params`**: Object containing route parameters (e.g., `{id: "bar"}`)
|
|
491
|
-
- **`updateHeadTag`**: Function to dynamically update head tags (see [updateHeadTag](#updateheadtag) section)
|
|
117
|
+
**Returns:** `currentRoute`, `params`, `routePattern`, `updateHeadTag`
|
|
492
118
|
|
|
493
119
|
### `updateHeadTag`
|
|
494
120
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
Please note that the `updateHeadTag` function requires at least one attribute to be provided. If no attributes are specified, an error message will be logged.
|
|
498
|
-
|
|
499
|
-
#### Props
|
|
500
|
-
|
|
501
|
-
See [HeadTag props](#headtag-props) for arguments and some common tag attributes.
|
|
502
|
-
|
|
503
|
-
## TypeScript Support
|
|
504
|
-
|
|
505
|
-
Routerino includes TypeScript definitions out of the box. The types are automatically available when you import Routerino.
|
|
506
|
-
|
|
507
|
-
### Basic Usage
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
// Both import styles are supported
|
|
511
|
-
import Routerino from 'routerino'; // Default import
|
|
512
|
-
// or
|
|
513
|
-
import { Routerino } from 'routerino'; // Named import (recommended)
|
|
514
|
-
|
|
515
|
-
import type { RouteConfig } from 'routerino';
|
|
516
|
-
|
|
517
|
-
export const routes: RouteConfig[] = [
|
|
518
|
-
{
|
|
519
|
-
path: '/',
|
|
520
|
-
element: <HomePage />,
|
|
521
|
-
title: 'Home',
|
|
522
|
-
description: 'Welcome to our site'
|
|
523
|
-
}
|
|
524
|
-
];
|
|
525
|
-
|
|
526
|
-
// TypeScript will validate all props
|
|
527
|
-
<Routerino
|
|
528
|
-
routes={routes}
|
|
529
|
-
baseUrl="https://example.com"
|
|
530
|
-
title="My Site"
|
|
531
|
-
/>
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
## Examples
|
|
535
|
-
|
|
536
|
-
Setting a page description:
|
|
121
|
+
Create or update head tags at any time. Matches existing tags by attribute to avoid duplicates:
|
|
537
122
|
|
|
538
123
|
```js
|
|
539
124
|
updateHeadTag({ name: "description", content: "Some description..." });
|
|
125
|
+
updateHeadTag({ tag: "link", rel: "apple-touch-icon", href: "/icon.png" });
|
|
126
|
+
updateHeadTag({ property: "og:site_name", content: "Your Brand" });
|
|
540
127
|
```
|
|
541
128
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
```js
|
|
545
|
-
updateHeadTag({
|
|
546
|
-
tag: "link",
|
|
547
|
-
rel: "apple-touch-icon",
|
|
548
|
-
href: "/example-icon.png",
|
|
549
|
-
});
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
While these two examples are automatically handled for you via the `description` and `touchIconUrl` properties in [RouteConfig props](#routeconfig-props), you might want to update them later or in specific scenarios.
|
|
553
|
-
|
|
554
|
-
## Routerino Best Practices
|
|
555
|
-
|
|
556
|
-
To optimize your site for SEO and social previews when using Routerino, consider the following best practices:
|
|
557
|
-
|
|
558
|
-
### Page Titles
|
|
559
|
-
|
|
560
|
-
- Keep page titles unique for each route. Avoid including the site name like "Foo.com" in individual page titles, Routerino adds that automatically.
|
|
561
|
-
- Aim for concise, descriptive titles that accurately represent the page content.
|
|
562
|
-
- We prefer to keep title length at a max of 50-60 characters, longer text will be ignored or cut off (especially for mobile users).
|
|
563
|
-
|
|
564
|
-
### URL Structure & Canonicalization
|
|
565
|
-
|
|
566
|
-
#### Canonical URLs (Don't worry, this is handled for you!)
|
|
567
|
-
|
|
568
|
-
**What is canonicalization?**
|
|
569
|
-
|
|
570
|
-
When multiple URLs show the same content (like `/about` vs `/about/`), search engines need to know which one is the "official" version to avoid duplicate content penalties. The canonical URL tells search engines which version to index and rank.
|
|
571
|
-
|
|
572
|
-
**How Routerino handles this automatically**
|
|
573
|
-
|
|
574
|
-
- Sets `<link rel="canonical">` tags on every page pointing to the preferred URL version
|
|
575
|
-
- Uses the `useTrailingSlash` prop (default: `true`) to determine the canonical format
|
|
576
|
-
- Generates proper `og:url` meta tags for social sharing
|
|
577
|
-
- For SSG: Creates both file versions (`/about.html` and `/about/index.html`) with canonical tags
|
|
578
|
-
- For Prerender: Includes meta tags that instruct the prerender server to return 301 redirects
|
|
579
|
-
- Ensures sitemap.xml only contains canonical URLs
|
|
580
|
-
|
|
581
|
-
**Best practices that Routerino implements**
|
|
582
|
-
|
|
583
|
-
- Consistency: Sitemap, canonical, and redirects all agree
|
|
584
|
-
- Dual file generation (SSG): Creates both `/about.html` and `/about/index.html` so both URLs work
|
|
585
|
-
- Prerender support (SPA): Includes meta tags that tell prerender services to serve proper status codes
|
|
586
|
-
- Absolute URLs: When `baseUrl` is provided, canonical tags use the provided base instead of defaulting to the current domain
|
|
587
|
-
|
|
588
|
-
**Example of what's generated**
|
|
589
|
-
|
|
590
|
-
With Static Site Generation (SSG):
|
|
591
|
-
|
|
592
|
-
```html
|
|
593
|
-
<!-- Both /about.html and /about/index.html contain: -->
|
|
594
|
-
<link rel="canonical" href="https://example.com/about/" />
|
|
595
|
-
<meta property="og:url" content="https://example.com/about/" />
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
With Prerender (SPA):
|
|
599
|
-
|
|
600
|
-
```html
|
|
601
|
-
<!-- For canonical URL (/about/) -->
|
|
602
|
-
<link rel="canonical" href="https://example.com/about/" />
|
|
603
|
-
<meta property="og:url" content="https://example.com/about/" />
|
|
604
|
-
|
|
605
|
-
<!-- For non-canonical URL (/about) -->
|
|
606
|
-
<meta name="prerender-status-code" content="301" />
|
|
607
|
-
<meta name="prerender-header" content="Location: https://example.com/about/" />
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
You can override the default with `useTrailingSlash={false}` if you prefer URLs without trailing slashes. Either way, Routerino ensures search engines see consistent, canonical URLs.
|
|
611
|
-
|
|
612
|
-
**Multi-domain deployments**: If your site is served from multiple domains, set `baseUrl` to the preferred domain to keep all canonical and og:url tags pointing to one place. For example, `<Routerino baseUrl="https://example.com" routes={routes} />` ensures search engines see one canonical domain even when the same page is reachable at example.net.
|
|
613
|
-
|
|
614
|
-
### Sitemap Generation
|
|
615
|
-
|
|
616
|
-
- Automate the creation of `sitemap.xml` and `robots.txt` during your build process with Routerino Forge.
|
|
617
|
-
- The Vite plugin automatically generates these files when building static sites (see [Static Site Generation](#static-site-generation)).
|
|
618
|
-
|
|
619
|
-
### Social Previews & Open Graph
|
|
620
|
-
|
|
621
|
-
Routerino automatically sets the core Open Graph tags (`og:title`, `og:description`, `og:url`, `og:image`) for every page. Here's how to optimize them:
|
|
622
|
-
|
|
623
|
-
#### Image Best Practices
|
|
624
|
-
|
|
625
|
-
- Size: Use 1200×630 pixels (1.91:1 ratio) for maximum compatibility
|
|
626
|
-
- Content: Avoid text in images - use metadata for text instead (per Apple's guidelines)
|
|
627
|
-
- Add dimensions for faster first-share rendering:
|
|
628
|
-
```js
|
|
629
|
-
// In your route's component or after data loading
|
|
630
|
-
updateHeadTag({ property: "og:image:width", content: "1200" });
|
|
631
|
-
updateHeadTag({ property: "og:image:height", content: "630" });
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
#### Title & Branding
|
|
635
|
-
|
|
636
|
-
- Don't duplicate branding in `og:title` - Routerino uses your page title directly
|
|
637
|
-
- For site-wide branding, add `og:site_name` instead:
|
|
638
|
-
```js
|
|
639
|
-
updateHeadTag({ property: "og:site_name", content: "Your Brand" });
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
#### Platform-Specific Enhancements
|
|
643
|
-
|
|
644
|
-
- Apple/iMessage: Set `touchIconUrl` prop for iMessage link previews
|
|
645
|
-
- Video content: Add direct playable assets when possible:
|
|
646
|
-
```js
|
|
647
|
-
updateHeadTag({
|
|
648
|
-
property: "og:video",
|
|
649
|
-
content: "https://example.com/video.mp4",
|
|
650
|
-
});
|
|
651
|
-
updateHeadTag({ property: "og:video:type", content: "video/mp4" });
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
#### Testing Your Previews
|
|
655
|
-
|
|
656
|
-
Test how your links appear on different platforms:
|
|
657
|
-
|
|
658
|
-
- [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) - Use "Scrape Again" after changes
|
|
659
|
-
- [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/)
|
|
660
|
-
- [Twitter Card Validator](https://cards-dev.twitter.com/validator)
|
|
661
|
-
|
|
662
|
-
**Tip**: Social platforms cache previews aggressively. After updating tags, use each platform's debugger to force a refresh.
|
|
663
|
-
|
|
664
|
-
#### Twitter Card Tags (Handled Automatically)
|
|
665
|
-
|
|
666
|
-
Routerino automatically includes Twitter card meta tags to ensure rich previews when your links are shared on Twitter/X:
|
|
667
|
-
|
|
668
|
-
```html
|
|
669
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
**What this does:**
|
|
673
|
-
|
|
674
|
-
- Without Twitter cards: Links appear as plain URLs with no preview
|
|
675
|
-
- With Twitter cards: Links show rich previews with title, description, and image
|
|
676
|
-
|
|
677
|
-
**How it works:**
|
|
678
|
-
|
|
679
|
-
- Routerino always sets `summary_large_image` for maximum engagement
|
|
680
|
-
- If you provide an `imageUrl`, Twitter displays a large prominent image
|
|
681
|
-
- If no image is provided, Twitter gracefully falls back to a text-only card
|
|
682
|
-
- This is better than no card at all (which would show just the bare URL)
|
|
683
|
-
|
|
684
|
-
**The complete picture:**
|
|
685
|
-
|
|
686
|
-
```html
|
|
687
|
-
<!-- What Routerino generates for social sharing -->
|
|
688
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
689
|
-
<meta property="og:title" content="Your Page Title" />
|
|
690
|
-
<meta property="og:description" content="Your page description" />
|
|
691
|
-
<meta property="og:image" content="https://example.com/preview.jpg" />
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
This creates an engaging Twitter preview with a large image, title, and description - much more clickable than a plain URL.
|
|
695
|
-
|
|
696
|
-
### Meta Descriptions
|
|
697
|
-
|
|
698
|
-
- Provide unique, informative descriptions for each route.
|
|
699
|
-
- Descriptions may be used for snippets so keep them short and to the point.
|
|
700
|
-
- Descriptions longer than ~150 characters may be truncated in search results.
|
|
701
|
-
|
|
702
|
-
### Additional SEO Considerations
|
|
703
|
-
|
|
704
|
-
- Use semantic HTML elements in your components for better content structure.
|
|
705
|
-
- Implement structured data (JSON-LD) where applicable to enhance rich snippets in search results. Use the `innerHTML` property on a `<script type="application/ld+json">` head tag (see the [Structured Data Example](#structured-data-example) above).
|
|
706
|
-
- Ensure your site is mobile-friendly and loads quickly for better search engine rankings.
|
|
707
|
-
|
|
708
|
-
By following these practices, you'll improve your site's SEO performance and social media presence when using Routerino.
|
|
709
|
-
|
|
710
|
-
### Hash Links
|
|
711
|
-
|
|
712
|
-
Routerino supports standard `<a href="/page#section">` links for SPA navigation. After React renders the new page, it finds the element with the matching `id` and scrolls it into view.
|
|
713
|
-
|
|
714
|
-
**Sticky headers**: If your site has a fixed header, use the CSS [`scroll-margin-top`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top) property to offset the scroll target so content isn't hidden behind the header:
|
|
715
|
-
|
|
716
|
-
```css
|
|
717
|
-
[id] {
|
|
718
|
-
scroll-margin-top: 80px; /* match your header height */
|
|
719
|
-
}
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
This works for SPA navigation, native browser hash navigation, and direct page loads — no extra props or router changes needed.
|
|
723
|
-
|
|
724
|
-
## Sitemap and robots.txt Generation
|
|
725
|
-
|
|
726
|
-
When using Routerino Forge for static site generation, `sitemap.xml` and `robots.txt` files are automatically generated during the build process:
|
|
727
|
-
|
|
728
|
-
- sitemap.xml: Contains all static routes (dynamic routes with parameters like `:id` are excluded)
|
|
729
|
-
- robots.txt: Created with a reference to the sitemap (if it doesn't already exist)
|
|
730
|
-
|
|
731
|
-
These files are generated automatically when you build with the Routerino Forge Vite plugin - no additional configuration needed.
|
|
732
|
-
|
|
733
|
-
### Sample Build Output:
|
|
129
|
+
Set `soft: true` to skip overwriting existing values. Use `innerHTML` for structured data and non-self-closing tags. See [docs/seo-guide.md](docs/seo-guide.md) for full details.
|
|
734
130
|
|
|
735
|
-
|
|
736
|
-
✓ Generated sitemap.xml with 42 URLs
|
|
737
|
-
✓ Generated robots.txt
|
|
738
|
-
✓ Generated 42 static pages + 404.html
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
## Image Optimization
|
|
742
|
-
|
|
743
|
-
Routerino delegates image optimization to [`vite-plugin-image-optimizer`](https://github.com/FatehAK/vite-plugin-image-optimizer). Install it and add it to your Vite config **before** `routerinoForge`:
|
|
744
|
-
|
|
745
|
-
```bash
|
|
746
|
-
npm install --save-dev vite-plugin-image-optimizer sharp
|
|
747
|
-
```
|
|
131
|
+
### Programmatic Navigation
|
|
748
132
|
|
|
749
133
|
```js
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
import react from "@vitejs/plugin-react";
|
|
753
|
-
import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
|
|
754
|
-
import { routerinoForge } from "routerino/forge";
|
|
755
|
-
|
|
756
|
-
export default defineConfig({
|
|
757
|
-
plugins: [
|
|
758
|
-
react(),
|
|
759
|
-
ViteImageOptimizer({
|
|
760
|
-
jpg: { quality: 80 },
|
|
761
|
-
jpeg: { quality: 80 },
|
|
762
|
-
png: { quality: 80 },
|
|
763
|
-
webp: { quality: 80 },
|
|
764
|
-
}),
|
|
765
|
-
routerinoForge({ baseUrl: "https://example.com" }),
|
|
766
|
-
],
|
|
767
|
-
});
|
|
134
|
+
window.history.pushState({}, "", "/about/");
|
|
135
|
+
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
768
136
|
```
|
|
769
137
|
|
|
770
|
-
|
|
138
|
+
### ErrorBoundary
|
|
771
139
|
|
|
772
|
-
|
|
140
|
+
```jsx
|
|
141
|
+
import { ErrorBoundary } from "routerino";
|
|
773
142
|
|
|
774
|
-
|
|
143
|
+
<ErrorBoundary
|
|
144
|
+
fallback={<div>Something went wrong.</div>}
|
|
145
|
+
errorTitleString="Error | My Site"
|
|
146
|
+
debug={window.location.hostname === "localhost"}
|
|
147
|
+
>
|
|
148
|
+
<MyComponent />
|
|
149
|
+
</ErrorBoundary>;
|
|
150
|
+
```
|
|
775
151
|
|
|
776
|
-
|
|
152
|
+
## Static Site Generation (Routerino Forge)
|
|
777
153
|
|
|
778
|
-
|
|
154
|
+
Add the Vite plugin, export your routes, and build:
|
|
779
155
|
|
|
780
156
|
```js
|
|
781
157
|
// vite.config.js
|
|
@@ -787,15 +163,7 @@ export default defineConfig({
|
|
|
787
163
|
plugins: [
|
|
788
164
|
react(),
|
|
789
165
|
routerinoForge({
|
|
790
|
-
baseUrl: "https://example.com", //
|
|
791
|
-
// Optional settings (these are the defaults):
|
|
792
|
-
// routes: "./src/routes.jsx", // Your routes file (and App.jsx for full layout)
|
|
793
|
-
// outputDir: "dist",
|
|
794
|
-
// generateSitemap: true,
|
|
795
|
-
// useTrailingSlash: true, // Set to false for /about instead of /about/
|
|
796
|
-
// verbose: false,
|
|
797
|
-
// ssgCacheDir: "node_modules/.cache/routerino-forge", // SSG cache directory
|
|
798
|
-
// verbose: false,
|
|
166
|
+
baseUrl: "https://example.com", // required — no trailing slash
|
|
799
167
|
}),
|
|
800
168
|
],
|
|
801
169
|
});
|
|
@@ -803,517 +171,116 @@ export default defineConfig({
|
|
|
803
171
|
|
|
804
172
|
**Requirements:**
|
|
805
173
|
|
|
806
|
-
-
|
|
807
|
-
-
|
|
808
|
-
|
|
809
|
-
**Features:**
|
|
810
|
-
|
|
811
|
-
- Renders your components to HTML at build time (SSG)
|
|
812
|
-
- Generates dual files for maximum URL compatibility:
|
|
813
|
-
- `/about` → `about.html`
|
|
814
|
-
- `/about/` → `about/index.html`
|
|
815
|
-
- Canonical URLs and redirects based on `useTrailingSlash` setting
|
|
816
|
-
- Prerender compatible 301 redirects for non-canonical versions
|
|
817
|
-
- **Static host ready**: Output format aligns perfectly with any static host such as Netlify and Cloudflare Pages
|
|
818
|
-
- Routes generate `/path/index.html` for clean URLs (and `/path.html` for compatibility with no-slash URLs)
|
|
819
|
-
- `404.html` at root for custom error pages
|
|
820
|
-
- No server configuration needed - just deploy!
|
|
821
|
-
- Automatic canonical URL and og:url meta tags
|
|
822
|
-
- Injects rendered HTML into your root div
|
|
823
|
-
- Generates sitemap.xml and robots.txt
|
|
824
|
-
- Creates a 404.html page
|
|
825
|
-
- Skips dynamic routes (with `:param` syntax)
|
|
826
|
-
- SEO optimized: Complete HTML with meta tags
|
|
827
|
-
- Image optimization: Automatic responsive variants + blur placeholders (LQIP) — now delegated to [`vite-plugin-image-optimizer`](https://github.com/FatehAK/vite-plugin-image-optimizer)
|
|
828
|
-
- Easy configuration: Works out of the box with Vite and minimal setup
|
|
829
|
-
|
|
830
|
-
#### Routes Configuration
|
|
831
|
-
|
|
832
|
-
**Critical for SSG**: Routes MUST be exported for the build plugin to discover them. The plugin needs to import your routes at build time, so inline route definitions won't work.
|
|
833
|
-
|
|
834
|
-
To include your full layout (headers, footers, etc.) in static generated HTML, export routes from the same file as your App component:
|
|
835
|
-
|
|
836
|
-
```jsx
|
|
837
|
-
// App.jsx - export routes from here for full layout SSG
|
|
838
|
-
export const routes = [
|
|
839
|
-
{ path: "/", element: <HomePage />, title: "Home" },
|
|
840
|
-
{ path: "/about/", element: <AboutPage />, title: "About" },
|
|
841
|
-
];
|
|
174
|
+
- `index.html` must have `<div id="root"></div>`
|
|
175
|
+
- Routes must be **exported** (not defined inline) for the plugin to find them
|
|
176
|
+
- Dynamic routes (with `:param`) are automatically skipped
|
|
842
177
|
|
|
843
|
-
|
|
844
|
-
return (
|
|
845
|
-
<main>
|
|
846
|
-
<Header />
|
|
847
|
-
<Routerino routes={routes} />
|
|
848
|
-
<Footer />
|
|
849
|
-
</main>
|
|
850
|
-
);
|
|
851
|
-
}
|
|
852
|
-
```
|
|
178
|
+
**What you get at build time:**
|
|
853
179
|
|
|
854
|
-
|
|
180
|
+
- Static HTML for every route with full meta tags
|
|
181
|
+
- Dual file generation (`/about.html` + `/about/index.html`) for URL compatibility
|
|
182
|
+
- Automatic `sitemap.xml` and `robots.txt`
|
|
183
|
+
- `404.html` at root for custom error pages
|
|
184
|
+
- Canonical URL and `og:url` meta tags on every page
|
|
855
185
|
|
|
856
|
-
|
|
186
|
+
### Generating Routes from Data
|
|
857
187
|
|
|
858
188
|
```jsx
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
element: <HomePage featured="Latest News" />, // Props preserved
|
|
863
|
-
title: "Home - My Site",
|
|
864
|
-
description: "Welcome to our site",
|
|
865
|
-
imageUrl: "/images/home-og.jpg", // Optional social image
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
path: "/about/",
|
|
869
|
-
element: <AboutPage />,
|
|
870
|
-
title: "About Us",
|
|
871
|
-
description: "Learn more about our team",
|
|
872
|
-
},
|
|
873
|
-
{
|
|
874
|
-
path: "/products/:id", // Dynamic route - won't be statically generated
|
|
875
|
-
element: <ProductDetail />,
|
|
876
|
-
title: "Product Detail",
|
|
877
|
-
},
|
|
878
|
-
];
|
|
879
|
-
|
|
880
|
-
// Optional: Custom 404 page
|
|
881
|
-
export const notFoundTemplate = (
|
|
882
|
-
<div>
|
|
883
|
-
<h1>404 - Page Not Found</h1>
|
|
884
|
-
<p>Sorry, the page you're looking for doesn't exist.</p>
|
|
885
|
-
</div>
|
|
189
|
+
// Build-time data fetching is fully supported
|
|
190
|
+
const blogPosts = await fetch("https://api.example.com/posts").then((r) =>
|
|
191
|
+
r.json()
|
|
886
192
|
);
|
|
887
|
-
```
|
|
888
|
-
|
|
889
|
-
#### Generating Routes from Data (e.g., Product Listings)
|
|
890
|
-
|
|
891
|
-
You can dynamically generate routes from data sources at build time. This is perfect for creating SEO-friendly static pages for products, blog posts, or any content from APIs or databases:
|
|
892
|
-
|
|
893
|
-
```jsx
|
|
894
|
-
// src/routes.jsx
|
|
895
|
-
import { ProductPage } from "./components/ProductPage";
|
|
896
|
-
import { BlogPost } from "./components/BlogPost";
|
|
897
|
-
|
|
898
|
-
// This could be fetched from an API at build time
|
|
899
|
-
const products = [
|
|
900
|
-
{
|
|
901
|
-
id: "laptop-pro",
|
|
902
|
-
name: "Laptop Pro",
|
|
903
|
-
price: 1299,
|
|
904
|
-
description: "High-performance laptop",
|
|
905
|
-
},
|
|
906
|
-
{
|
|
907
|
-
id: "wireless-mouse",
|
|
908
|
-
name: "Wireless Mouse",
|
|
909
|
-
price: 49,
|
|
910
|
-
description: "Ergonomic wireless mouse",
|
|
911
|
-
},
|
|
912
|
-
{ id: "usb-hub", name: "USB Hub", price: 29, description: "7-port USB hub" },
|
|
913
|
-
];
|
|
914
|
-
|
|
915
|
-
// Generate a route for each product
|
|
916
|
-
const productRoutes = products.map((product) => ({
|
|
917
|
-
path: `/products/${product.id}/`,
|
|
918
|
-
element: <ProductPage product={product} />,
|
|
919
|
-
title: `${product.name} - $${product.price}`,
|
|
920
|
-
description: product.description,
|
|
921
|
-
tags: [
|
|
922
|
-
{ property: "og:type", content: "product" },
|
|
923
|
-
{ property: "product:price:amount", content: product.price.toString() },
|
|
924
|
-
{ property: "product:price:currency", content: "USD" },
|
|
925
|
-
],
|
|
926
|
-
}));
|
|
927
|
-
|
|
928
|
-
// You can also fetch data asynchronously at build time
|
|
929
|
-
const blogPosts = await fetch("https://api.example.com/posts")
|
|
930
|
-
.then((res) => res.json())
|
|
931
|
-
.catch(() => []); // Fallback to empty array if API fails
|
|
932
|
-
|
|
933
|
-
const blogRoutes = blogPosts.map((post) => ({
|
|
934
|
-
path: `/blog/${post.slug}/`,
|
|
935
|
-
element: <BlogPost post={post} />,
|
|
936
|
-
title: post.title,
|
|
937
|
-
description: post.excerpt,
|
|
938
|
-
imageUrl: post.featuredImage,
|
|
939
|
-
tags: [
|
|
940
|
-
{ property: "og:type", content: "article" },
|
|
941
|
-
{ property: "article:published_time", content: post.publishedAt },
|
|
942
|
-
{ property: "article:author", content: post.author },
|
|
943
|
-
],
|
|
944
|
-
}));
|
|
945
193
|
|
|
946
|
-
// Combine all routes
|
|
947
194
|
export const routes = [
|
|
948
|
-
{
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
{
|
|
957
|
-
path: "/products/",
|
|
958
|
-
element: <ProductListing products={products} />,
|
|
959
|
-
title: "All Products",
|
|
960
|
-
description: "Browse our product catalog",
|
|
961
|
-
},
|
|
962
|
-
];
|
|
963
|
-
```
|
|
964
|
-
|
|
965
|
-
**Benefits of this approach:**
|
|
966
|
-
|
|
967
|
-
- Each product/post gets its own static HTML page with proper SEO meta tags
|
|
968
|
-
- All generated routes are automatically included in `sitemap.xml`
|
|
969
|
-
- Search engines can discover and index every product/post
|
|
970
|
-
- Fast page loads since HTML is pre-rendered at build time
|
|
971
|
-
- Type-safe if using TypeScript with your data structures
|
|
972
|
-
|
|
973
|
-
### What Gets Generated
|
|
974
|
-
|
|
975
|
-
The static build process will:
|
|
976
|
-
|
|
977
|
-
- Generate HTML files for each static route (e.g., `/about/` → `about/index.html` & `about.html`)
|
|
978
|
-
- Skip dynamic routes with parameters (e.g., `/user/:id`)
|
|
979
|
-
- Apply route-specific meta tags (title, description, og:image)
|
|
980
|
-
- Generate `sitemap.xml` with all static routes (Vite plugin only)
|
|
981
|
-
- Preserve your existing HTML structure and assets
|
|
982
|
-
|
|
983
|
-
### Example Output
|
|
984
|
-
|
|
985
|
-
For a route configuration like:
|
|
986
|
-
|
|
987
|
-
```javascript
|
|
988
|
-
{
|
|
989
|
-
path: '/about/',
|
|
990
|
-
title: 'About Us',
|
|
991
|
-
description: 'Learn more about our company',
|
|
992
|
-
imageUrl: 'https://example.com/about-og.jpg'
|
|
993
|
-
}
|
|
994
|
-
```
|
|
995
|
-
|
|
996
|
-
The generated `/about/index.html` will include:
|
|
997
|
-
|
|
998
|
-
```html
|
|
999
|
-
<title>About Us</title>
|
|
1000
|
-
<meta name="description" content="Learn more about our company" />
|
|
1001
|
-
<meta property="og:title" content="About Us" />
|
|
1002
|
-
<meta property="og:description" content="Learn more about our company" />
|
|
1003
|
-
<meta property="og:image" content="https://example.com/about-og.jpg" />
|
|
1004
|
-
<meta property="og:url" content="https://example.com/about/" />
|
|
1005
|
-
```
|
|
1006
|
-
|
|
1007
|
-
This provides excellent SEO while maintaining the benefits of a React SPA.
|
|
1008
|
-
|
|
1009
|
-
## How-to Guides & Example Code
|
|
1010
|
-
|
|
1011
|
-
1. [Starting a New React Project with Routerino](#starting-a-new-react-project-with-routerino)
|
|
1012
|
-
2. [Full React Example](#full-react-example)
|
|
1013
|
-
3. [Basic Example](#basic-example)
|
|
1014
|
-
|
|
1015
|
-
### Starting a New React Project with Routerino
|
|
1016
|
-
|
|
1017
|
-
If you're starting from scratch and wondering "How do I create a React project with Routerino?", here's a recommended approach:
|
|
1018
|
-
|
|
1019
|
-
1. First, ensure you have [Node.js](https://nodejs.org/) and npm (Node Package Manager) installed on your system. If you're just getting started, consider using a Node version manager like [Volta](https://volta.sh/), [fnm](https://github.com/Schniz/fnm), or [asdf](https://asdf-vm.com/) for easy installation and management of Node.js versions.
|
|
1020
|
-
|
|
1021
|
-
2. We recommend using [Vite](https://vitejs.dev/) for a fast and lean development experience. Vite is a modern build tool that focuses on speed and simplicity. To create a new React project with Vite, run the following command in your terminal:
|
|
1022
|
-
|
|
1023
|
-
```
|
|
1024
|
-
npm create vite@latest my-react-app -- --template react
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
This command will create a new directory called `my-react-app` with a basic React project structure.
|
|
1028
|
-
|
|
1029
|
-
3. Navigate to your new project directory:
|
|
1030
|
-
|
|
1031
|
-
```
|
|
1032
|
-
cd my-react-app
|
|
1033
|
-
```
|
|
1034
|
-
|
|
1035
|
-
4. Install the project dependencies using npm:
|
|
1036
|
-
|
|
1037
|
-
```
|
|
1038
|
-
npm install
|
|
1039
|
-
```
|
|
1040
|
-
|
|
1041
|
-
This command will read the `package.json` file in your project and install all the necessary dependencies.
|
|
1042
|
-
|
|
1043
|
-
5. Now, add Routerino to your project as a dependency:
|
|
1044
|
-
|
|
1045
|
-
```
|
|
1046
|
-
npm install routerino
|
|
1047
|
-
```
|
|
1048
|
-
|
|
1049
|
-
This command will install the latest version of Routerino and save it to your `package.json` file under the `dependencies` section.
|
|
1050
|
-
|
|
1051
|
-
With these steps, you'll have a new React project set up with Vite as the build tool and Routerino installed as a dependency. You can now start building your application with React & Routerino.
|
|
1052
|
-
|
|
1053
|
-
### Full React Example
|
|
1054
|
-
|
|
1055
|
-
This example includes the full React configuration. It might take the place of `src/main.jsx` or an `index.js` file.
|
|
1056
|
-
|
|
1057
|
-
```jsx
|
|
1058
|
-
import React from "react";
|
|
1059
|
-
import { createRoot } from "react-dom/client";
|
|
1060
|
-
import Routerino from "routerino";
|
|
1061
|
-
|
|
1062
|
-
export const routes = [
|
|
1063
|
-
{
|
|
1064
|
-
path: "/",
|
|
1065
|
-
element: <p>Welcome to Home</p>,
|
|
1066
|
-
title: "Home",
|
|
1067
|
-
description: "Welcome to my website!",
|
|
1068
|
-
},
|
|
1069
|
-
{
|
|
1070
|
-
path: "/about/",
|
|
1071
|
-
element: <p>About us...</p>,
|
|
1072
|
-
title: "About",
|
|
1073
|
-
description: "Learn more about us.",
|
|
1074
|
-
},
|
|
1075
|
-
{
|
|
1076
|
-
path: "/contact/",
|
|
1077
|
-
element: (
|
|
1078
|
-
<div>
|
|
1079
|
-
<h1>Contact Us</h1>
|
|
1080
|
-
<p>
|
|
1081
|
-
Please <a href="mailto:user@example.com">send us an email</a> at
|
|
1082
|
-
user@example.com
|
|
1083
|
-
</p>
|
|
1084
|
-
</div>
|
|
1085
|
-
),
|
|
1086
|
-
title: "Contact",
|
|
1087
|
-
description: "Get in touch with us.",
|
|
1088
|
-
},
|
|
195
|
+
{ path: "/", element: <HomePage />, title: "Home" },
|
|
196
|
+
...blogPosts.map((post) => ({
|
|
197
|
+
path: `/blog/${post.slug}/`,
|
|
198
|
+
element: <BlogPost post={post} />,
|
|
199
|
+
title: post.title,
|
|
200
|
+
description: post.excerpt,
|
|
201
|
+
imageUrl: post.featuredImage,
|
|
202
|
+
})),
|
|
1089
203
|
];
|
|
1090
|
-
|
|
1091
|
-
const App = () => (
|
|
1092
|
-
<main>
|
|
1093
|
-
<nav>
|
|
1094
|
-
<a href="/">Home</a>
|
|
1095
|
-
</nav>
|
|
1096
|
-
|
|
1097
|
-
<Routerino
|
|
1098
|
-
title="Example.com"
|
|
1099
|
-
notFoundTitle="Sorry, but this page does not exist."
|
|
1100
|
-
errorTitle="Yikes! Something went wrong."
|
|
1101
|
-
routes={routes}
|
|
1102
|
-
/>
|
|
1103
|
-
|
|
1104
|
-
<footer>
|
|
1105
|
-
<p>
|
|
1106
|
-
Learn more <a href="/about/">about us</a> or{" "}
|
|
1107
|
-
<a href="/contact/">contact us</a> today.
|
|
1108
|
-
</p>
|
|
1109
|
-
</footer>
|
|
1110
|
-
</main>
|
|
1111
|
-
);
|
|
1112
|
-
|
|
1113
|
-
createRoot(document.getElementById("root")).render(<App />);
|
|
1114
|
-
```
|
|
1115
|
-
|
|
1116
|
-
## ErrorBoundary Component
|
|
1117
|
-
|
|
1118
|
-
Routerino exports an `ErrorBoundary` component that you can use in your own applications to catch and handle React component errors gracefully. Fun fact: error boundary components are one of the last cases that still require using a React Class! Since this library aims to include everything you need to build a multiple page React SPA, and enable users to be able to know which component had an issue without confusing it with a Routerino bug.
|
|
1119
|
-
|
|
1120
|
-
### Import
|
|
1121
|
-
|
|
1122
|
-
```jsx
|
|
1123
|
-
import { ErrorBoundary } from "routerino";
|
|
1124
204
|
```
|
|
1125
205
|
|
|
1126
|
-
|
|
206
|
+
Each generated route gets its own static HTML page with proper meta tags and is automatically included in `sitemap.xml`.
|
|
1127
207
|
|
|
1128
|
-
|
|
1129
|
-
<ErrorBoundary
|
|
1130
|
-
fallback={<div>Something went wrong. Please try again.</div>}
|
|
1131
|
-
errorTitleString="Error | My Application"
|
|
1132
|
-
debug={window.location.hostname === "localhost"} // Auto-enable on localhost
|
|
1133
|
-
>
|
|
1134
|
-
<MyComponent />
|
|
1135
|
-
</ErrorBoundary>
|
|
1136
|
-
```
|
|
208
|
+
## Who Is This For?
|
|
1137
209
|
|
|
1138
|
-
|
|
210
|
+
Routerino is for React developers building content sites, marketing pages, or JAMstack apps who want full SEO (static HTML, meta tags, sitemaps) without adopting a framework like Next.js or Remix. If you're building a dashboard or an authenticated app, React Router is fine. If you need Google to index your pages, Routerino gives you that at build time with zero new dependencies.
|
|
1139
211
|
|
|
1140
|
-
|
|
1141
|
-
| ------------------ | ----------- | -------- | ----------------------------------------------------------------- |
|
|
1142
|
-
| `children` | `ReactNode` | No | The child components to render when there's no error |
|
|
1143
|
-
| `fallback` | `ReactNode` | No | The UI to display when an error is caught |
|
|
1144
|
-
| `errorTitleString` | `string` | Yes | The document title to set when an error occurs |
|
|
1145
|
-
| `usePrerenderTags` | `boolean` | No | Whether to set prerender meta tags (status code 500) |
|
|
1146
|
-
| `routePath` | `string` | No | The current route path for better error context (used internally) |
|
|
1147
|
-
| `debug` | `boolean` | No | Enable detailed console logging of errors (default: `false`) |
|
|
212
|
+
## TypeScript
|
|
1148
213
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
When `debug` is set to `true`, the ErrorBoundary provides detailed console output:
|
|
1152
|
-
|
|
1153
|
-
- Groups error information for better readability
|
|
1154
|
-
- Logs the component stack trace showing exactly where the error occurred
|
|
1155
|
-
- Shows the failed route path (if available)
|
|
1156
|
-
- Includes timestamp of when the error occurred
|
|
1157
|
-
|
|
1158
|
-
**Recommended debug pattern:**
|
|
1159
|
-
|
|
1160
|
-
```jsx
|
|
1161
|
-
// Auto-enable debug mode on localhost
|
|
1162
|
-
debug={window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1"}
|
|
1163
|
-
|
|
1164
|
-
// Or use environment variable
|
|
1165
|
-
debug={process.env.NODE_ENV === "development"}
|
|
1166
|
-
```
|
|
214
|
+
TypeScript definitions are included. Routes are typed as `RouteConfig[]`:
|
|
1167
215
|
|
|
1168
|
-
|
|
216
|
+
```tsx
|
|
217
|
+
import type { RouteConfig } from "routerino";
|
|
1169
218
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
- Sets document title on error
|
|
1173
|
-
- Provides detailed debug logging when enabled
|
|
1174
|
-
- Optionally sets prerender status code for SEO
|
|
1175
|
-
- Used internally by Routerino to protect route components
|
|
1176
|
-
|
|
1177
|
-
This is the same error boundary used internally by Routerino to protect your route components from crashing the entire application.
|
|
1178
|
-
|
|
1179
|
-
## Vendoring Routerino
|
|
1180
|
-
|
|
1181
|
-
If you prefer to include Routerino directly in your project instead of using it as a dependency, you can easily vendor the library. Vendoring allows you to have full control over the version of Routerino used in your project and eliminates the need to manage it as an external dependency.
|
|
1182
|
-
|
|
1183
|
-
To vendor Routerino, follow these steps:
|
|
1184
|
-
|
|
1185
|
-
1. Download the `routerino.jsx` file from the Routerino [repository](./routerino.jsx).
|
|
1186
|
-
|
|
1187
|
-
2. Place the `routerino.jsx` file in a suitable location within your project's source directory. For example, you could create a `vendor` folder and place the file there:
|
|
1188
|
-
|
|
1189
|
-
```md
|
|
1190
|
-
your-project/
|
|
1191
|
-
├── src/
|
|
1192
|
-
│ ├── vendor/
|
|
1193
|
-
│ │ └── routerino.jsx
|
|
1194
|
-
│ └── ...
|
|
1195
|
-
└── ...
|
|
1196
|
-
```
|
|
1197
|
-
|
|
1198
|
-
3. Update your import statements to reference the vendored `routerino.jsx` file instead of the npm package:
|
|
1199
|
-
|
|
1200
|
-
```jsx
|
|
1201
|
-
// Before (importing from the package)
|
|
1202
|
-
import Routerino from "routerino";
|
|
1203
|
-
|
|
1204
|
-
// After (importing from the vendored file)
|
|
1205
|
-
import Routerino from "./vendor/routerino";
|
|
1206
|
-
```
|
|
1207
|
-
|
|
1208
|
-
4. You're all set! Routerino is now vendored in your project, and you can use it as before.
|
|
1209
|
-
|
|
1210
|
-
5. If using the Routerino Forge plugin for SSG and to automatically generate a sitemap during the build process, be sure to copy it over as well.
|
|
1211
|
-
|
|
1212
|
-
By vendoring Routerino, you have full control over the code and can make any necessary modifications directly to the `routerino.jsx` file. However, keep in mind that you'll need to manually update the vendored file if you want to incorporate any future updates or bug fixes from the main Routerino repository.
|
|
1213
|
-
|
|
1214
|
-
## Accessibility & SEO Best Practices
|
|
1215
|
-
|
|
1216
|
-
To maximize your PageSpeed Insights and Lighthouse scores, we recommend setting up ESLint with accessibility rules. This helps catch common issues that hurt SEO and user experience.
|
|
1217
|
-
|
|
1218
|
-
### Setting up eslint-plugin-jsx-a11y
|
|
1219
|
-
|
|
1220
|
-
1. Install the plugin:
|
|
1221
|
-
|
|
1222
|
-
```bash
|
|
1223
|
-
npm install --save-dev eslint-plugin-jsx-a11y
|
|
1224
|
-
```
|
|
1225
|
-
|
|
1226
|
-
2. Add to your ESLint config:
|
|
1227
|
-
|
|
1228
|
-
```javascript
|
|
1229
|
-
// eslint.config.js (ESLint 9+ flat config)
|
|
1230
|
-
import jsxA11y from "eslint-plugin-jsx-a11y";
|
|
1231
|
-
|
|
1232
|
-
export default [
|
|
1233
|
-
{
|
|
1234
|
-
plugins: {
|
|
1235
|
-
"jsx-a11y": jsxA11y,
|
|
1236
|
-
},
|
|
1237
|
-
rules: {
|
|
1238
|
-
...jsxA11y.configs.recommended.rules,
|
|
1239
|
-
},
|
|
1240
|
-
},
|
|
219
|
+
export const routes: RouteConfig[] = [
|
|
220
|
+
{ path: "/", element: <HomePage />, title: "Home", description: "Welcome" },
|
|
1241
221
|
];
|
|
1242
222
|
```
|
|
1243
223
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
## Additional Resources
|
|
1306
|
-
|
|
1307
|
-
Here are some sources for further reading on SEO best-practices.
|
|
1308
|
-
|
|
1309
|
-
- [Optimize Largest Contentful Paint (LCP)](https://web.dev/articles/optimize-lcp) - Improve loading performance
|
|
1310
|
-
- [Apple's best practices for link previews](https://developer.apple.com/library/archive/technotes/tn2444/_index.html)
|
|
1311
|
-
- [Use Open Graph tags](https://ahrefs.com/blog/open-graph-meta-tags/)
|
|
1312
|
-
- [Use descriptive link text](https://developers.google.com/search/docs/fundamentals/seo-starter-guide?hl=en&ref_topic=9460495)
|
|
1313
|
-
|
|
1314
|
-
## Contributions
|
|
1315
|
-
|
|
1316
|
-
Contributions are always welcome. Please feel free to create an issue or submit a pull request. Just remember to keep it simple!
|
|
224
|
+
## Documentation
|
|
225
|
+
|
|
226
|
+
- [Getting Started](docs/getting-started.md) — Full React example, Preact setup
|
|
227
|
+
- [SEO Guide](docs/seo-guide.md) — Canonical URLs, social previews, JSON-LD, hash links
|
|
228
|
+
- [Image Optimization](docs/image-optimization.md) — Delegate to `vite-plugin-image-optimizer`
|
|
229
|
+
- [Accessibility](docs/accessibility.md) — ESLint a11y setup for Lighthouse scores
|
|
230
|
+
- [Vendoring](docs/vendoring.md) — Include Routerino directly in your project
|
|
231
|
+
- [Additional Resources](docs/additional-resources.md) — External SEO/performance links
|
|
232
|
+
|
|
233
|
+
## API Reference
|
|
234
|
+
|
|
235
|
+
### `<Routerino>` Props
|
|
236
|
+
|
|
237
|
+
| Prop | Type | Default | Description |
|
|
238
|
+
| ------------------ | --------------- | ------------------------ | ----------------------------------------------- |
|
|
239
|
+
| `title` | `string` | `""` | Site title appended to page titles |
|
|
240
|
+
| `routes` | `RouteConfig[]` | `[default]` | Array of route configurations |
|
|
241
|
+
| `separator` | `string` | `" \| "` | Title separator between page and site title |
|
|
242
|
+
| `notFoundTemplate` | `ReactNode` | Built-in 404 | 404 page template |
|
|
243
|
+
| `notFoundTitle` | `string` | `"Page not found [404]"` | 404 page title |
|
|
244
|
+
| `errorTemplate` | `ReactNode` | Built-in 500 | Error page template |
|
|
245
|
+
| `errorTitle` | `string` | `"Page error [500]"` | Error page title |
|
|
246
|
+
| `useTrailingSlash` | `boolean` | `true` | Use trailing slashes in canonical URLs |
|
|
247
|
+
| `usePrerenderTags` | `boolean` | `false` | Include prerender meta tags for crawlers |
|
|
248
|
+
| `baseUrl` | `string` | `null` | Base URL for canonical tags (no trailing slash) |
|
|
249
|
+
| `imageUrl` | `string` | `null` | Default site-wide social image URL |
|
|
250
|
+
| `touchIconUrl` | `string` | `null` | PWA homescreen icon URL |
|
|
251
|
+
| `debug` | `boolean` | `false` | Enable console logging |
|
|
252
|
+
| `ignorePatterns` | `string[]` | `[]` | URL patterns to skip SPA routing |
|
|
253
|
+
|
|
254
|
+
### `RouteConfig` Object
|
|
255
|
+
|
|
256
|
+
| Field | Type | Required | Description |
|
|
257
|
+
| ------------- | ----------- | -------- | --------------------------------------------------- |
|
|
258
|
+
| `path` | `string` | Yes | Route path. Must start with `/`. Supports `:param`. |
|
|
259
|
+
| `element` | `ReactNode` | Yes | Component to render at this route |
|
|
260
|
+
| `title` | `string` | No | Page title (site title appended automatically) |
|
|
261
|
+
| `description` | `string` | No | Meta description |
|
|
262
|
+
| `imageUrl` | `string` | No | Social preview image for this route |
|
|
263
|
+
| `tags` | `HeadTag[]` | No | Additional head tags (OG, JSON-LD, etc.) |
|
|
264
|
+
|
|
265
|
+
### `HeadTag` Object
|
|
266
|
+
|
|
267
|
+
Common attributes: `tag`, `name`, `property`, `content`, `rel`, `href`, `soft`, `innerHTML`. Supports all standard HTML attributes. See [updateHeadTag](#updateheadtag) for details.
|
|
268
|
+
|
|
269
|
+
### `routerinoForge` Options
|
|
270
|
+
|
|
271
|
+
| Option | Type | Default | Description |
|
|
272
|
+
| ------------------ | --------- | --------------------------------------- | ------------------------------------------------ |
|
|
273
|
+
| `baseUrl` | `string` | **required** | Production URL (no trailing slash) |
|
|
274
|
+
| `routes` | `string` | `"./src/routes.jsx"` | Path to routes file |
|
|
275
|
+
| `outputDir` | `string` | `"dist"` | Build output directory |
|
|
276
|
+
| `generateSitemap` | `boolean` | `true` | Generate sitemap.xml and robots.txt |
|
|
277
|
+
| `useTrailingSlash` | `boolean` | `true` | Set to `false` for `/about` instead of `/about/` |
|
|
278
|
+
| `verbose` | `boolean` | `false` | Enable detailed build logging |
|
|
279
|
+
| `ssgCacheDir` | `string` | `"node_modules/.cache/routerino-forge"` | SSG cache directory |
|
|
280
|
+
|
|
281
|
+
## Contributing
|
|
282
|
+
|
|
283
|
+
Contributions are welcome. Please create an issue or submit a pull request. Keep it simple!
|
|
1317
284
|
|
|
1318
285
|
## License
|
|
1319
286
|
|