routerino 2.1.0 → 2.2.0
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 +609 -152
- package/dist/routerino.js +246 -135
- package/dist/routerino.umd.cjs +1 -1
- package/package.json +1 -1
- package/routerino-forge.js +479 -75
- package/types/routerino.d.ts +10 -2
package/README.md
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
> A lightweight, SEO-optimized React router for modern websites and applications
|
|
4
4
|
|
|
5
|
+
For teams who want SPA simplicity with search-friendly static HTML, Open Graph previews, and **no framework lock-in.**
|
|
6
|
+
|
|
7
|
+
<!-- [**Live Example**](https://www.papoir.com) | [**Starter Template**](https://github.com/nerds-with-keyboards/routerino-starter) -->
|
|
8
|
+
|
|
5
9
|
Routerino is a zero-dependency router for React designed for optimal SEO performance in client-side rendered applications. Built for modern web architectures like JAMStack applications and Vite-powered React sites, it provides route & meta tag management, sitemap generation, and static site generation or [prerender](https://github.com/prerender/prerender) support to ensure your React applications are fully discoverable by search engines.
|
|
6
10
|
|
|
7
11
|
## Why Routerino?
|
|
8
12
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
13
|
+
- SEO-First Design: Automatic meta tag management, sitemap generation, and prerender support ensure maximum search engine visibility
|
|
14
|
+
- Zero Added Dependencies: Keeps bundle size minimal and reduces supply-chain vulnerabilities
|
|
15
|
+
- Simple API: No special `Link` components required - use standard HTML anchors and navigate programmatically with standard browser APIs
|
|
16
|
+
- Static Site Generation: Build-tool agnostic static HTML generation for improved performance and SEO
|
|
17
|
+
- Prerender Ready: Works with prerender servers (such as prerender/prerender) via dedicated meta tags for correct crawler status codes
|
|
18
|
+
- Single File Core: The entire routing logic fits in one file, making it easy to understand and customize
|
|
15
19
|
|
|
16
20
|
## Table of Contents
|
|
17
21
|
|
|
@@ -19,13 +23,12 @@ Routerino is a zero-dependency router for React designed for optimal SEO perform
|
|
|
19
23
|
- [Installation](#installation)
|
|
20
24
|
- [Usage](#usage)
|
|
21
25
|
- [Props](#props-arguments)
|
|
22
|
-
- [
|
|
26
|
+
- [useRouterino Hook](#using-the-userouterino-hook)
|
|
23
27
|
- [updateHeadTag](#updateheadtag)
|
|
28
|
+
- [TypeScript Support](#typescript-support)
|
|
24
29
|
- [Best Practices](#routerino-best-practices)
|
|
25
30
|
- [Generating a Sitemap](#generating-a-sitemap-from-routes)
|
|
26
31
|
- [Static Site Generation](#static-site-generation)
|
|
27
|
-
- [Deployment Guides](#deployment-guides)
|
|
28
|
-
- [Prerender Server (Docker)](#prerender-server-docker)
|
|
29
32
|
- [How-to Guides & Examples](#how-to-guides--example-code)
|
|
30
33
|
- [Starting a New Project](#starting-a-new-react-project-with-routerino)
|
|
31
34
|
- [Full React Example](#full-react-example)
|
|
@@ -39,29 +42,29 @@ Routerino is a zero-dependency router for React designed for optimal SEO perform
|
|
|
39
42
|
## Quick Start
|
|
40
43
|
|
|
41
44
|
```jsx
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
45
|
+
// export your routes for SSG, not required for CSR-only
|
|
46
|
+
export const routes = [
|
|
47
|
+
{
|
|
48
|
+
path: "/",
|
|
49
|
+
element: <p>This is the home page!</p>,
|
|
50
|
+
title: "My Home Page!",
|
|
51
|
+
description: "Welcome to my home page!",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: "/blog/my-first-post/",
|
|
55
|
+
element: (
|
|
56
|
+
<article>
|
|
57
|
+
<h1>My First Post</h1>
|
|
58
|
+
<p>Lorem ipsum...</p>
|
|
59
|
+
</article>
|
|
60
|
+
),
|
|
61
|
+
title: "My First Post",
|
|
62
|
+
description: "The first post on my new home page!",
|
|
63
|
+
tags: [{ property: "og:type", content: "article" }],
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
<Routerino title="Example.com" routes={routes} />;
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
This simple configuration automatically handles routing, meta tags, and SEO optimization for your React application.
|
|
@@ -81,6 +84,7 @@ This simple configuration automatically handles routing, meta tags, and SEO opti
|
|
|
81
84
|
- Generate static HTML files for each route with proper meta tags
|
|
82
85
|
- Implement SEO best practices out-of-the-box
|
|
83
86
|
- Optimize for Googlebot with pre-rendering support
|
|
87
|
+
- Automatic image optimization with blur placeholders
|
|
84
88
|
|
|
85
89
|
- Enhanced User Experience
|
|
86
90
|
- Support for sharing and social preview metadata
|
|
@@ -88,46 +92,115 @@ This simple configuration automatically handles routing, meta tags, and SEO opti
|
|
|
88
92
|
|
|
89
93
|
## Installation
|
|
90
94
|
|
|
91
|
-
Ensure that you have React and React DOM installed in your project as peer dependencies. To add as a dev dependency:
|
|
92
|
-
|
|
93
95
|
```sh
|
|
94
|
-
npm i routerino
|
|
96
|
+
npm i routerino
|
|
95
97
|
```
|
|
96
98
|
|
|
99
|
+
Note: Routerino requires React, React DOM, and PropTypes as peer dependencies. These are typically already installed in React projects.
|
|
100
|
+
|
|
97
101
|
### Compatibility
|
|
98
102
|
|
|
99
103
|
Routerino supports:
|
|
100
104
|
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
105
|
+
- React 18 and 19: Both versions are tested and supported. React 17 works for CSR-only.
|
|
106
|
+
- Node.js 18+: Tested on Node.js 18, 20, 22, and 24. Could be used on earlier versions if we skip tests.
|
|
107
|
+
- Preact: Compatible via `@preact/compat`. See [using Preact](#using-preact) below.
|
|
104
108
|
|
|
105
109
|
## Usage
|
|
106
110
|
|
|
107
111
|
Here's a short example of using Routerino in your React application:
|
|
108
112
|
|
|
109
113
|
```jsx
|
|
114
|
+
export const routes = [
|
|
115
|
+
{
|
|
116
|
+
path: "/",
|
|
117
|
+
element: <p>This is the home page!</p>,
|
|
118
|
+
title: "My Home Page!",
|
|
119
|
+
description: "Welcome to my home page!",
|
|
120
|
+
},
|
|
121
|
+
];
|
|
110
122
|
<Routerino
|
|
111
123
|
title="Example.com"
|
|
112
|
-
routes={
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
routes={routes}
|
|
125
|
+
debug={window.location.hostname === "localhost"}
|
|
126
|
+
/>;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
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). Routerino handles same-origin anchor clicks. Cross-origin links and non-HTTP schemes (e.g., mailto:, tel:) are handled by the browser as usual.
|
|
130
|
+
|
|
131
|
+
### Programmatic Navigation
|
|
132
|
+
|
|
133
|
+
<details>
|
|
134
|
+
<summary style="cursor:pointer;font-style:italic">Navigate programmatically using standard browser APIs (expand for details)</summary>
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
// Using History API
|
|
138
|
+
window.history.pushState({}, "", "/about/");
|
|
139
|
+
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
140
|
+
|
|
141
|
+
// Working with URL and search params
|
|
142
|
+
const url = new URL(window.location);
|
|
143
|
+
url.searchParams.set("page", "2");
|
|
144
|
+
window.history.pushState({}, "", url.toString());
|
|
145
|
+
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
122
146
|
```
|
|
123
147
|
|
|
124
|
-
|
|
148
|
+
</details>
|
|
125
149
|
|
|
126
150
|
See [props](#props-arguments) for full explanations and [example code](#how-to-guides--example-code) for more complete code samples.
|
|
127
151
|
|
|
152
|
+
### Using Preact
|
|
153
|
+
|
|
154
|
+
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.
|
|
155
|
+
|
|
156
|
+
#### Setup Instructions
|
|
157
|
+
|
|
158
|
+
1. Install Preact and the compatibility layer:
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
npm i preact @preact/compat
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
2. Configure your bundler to alias React to @preact/compat:
|
|
165
|
+
|
|
166
|
+
**Vite Configuration:**
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
// vite.config.js
|
|
170
|
+
import { defineConfig } from "vite";
|
|
171
|
+
import preact from "@preact/preset-vite";
|
|
172
|
+
|
|
173
|
+
export default defineConfig({
|
|
174
|
+
plugins: [preact()],
|
|
175
|
+
resolve: {
|
|
176
|
+
alias: {
|
|
177
|
+
react: "@preact/compat",
|
|
178
|
+
"react-dom": "@preact/compat",
|
|
179
|
+
"react/jsx-runtime": "@preact/compat/jsx-runtime",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Webpack Configuration:**
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
// webpack.config.js
|
|
189
|
+
module.exports = {
|
|
190
|
+
resolve: {
|
|
191
|
+
alias: {
|
|
192
|
+
react: "preact/compat",
|
|
193
|
+
"react-dom": "preact/compat",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
3. Use Routerino exactly as you would in a React project - the API is identical!
|
|
200
|
+
|
|
128
201
|
### Props (arguments)
|
|
129
202
|
|
|
130
|
-
|
|
203
|
+
The table below shows all available props with their default values. See the [usage](#usage) section for examples.
|
|
131
204
|
|
|
132
205
|
#### Routerino props
|
|
133
206
|
|
|
@@ -143,13 +216,11 @@ All of these are optional, so it's easy to get started with nothing but a bare-b
|
|
|
143
216
|
| [errorTemplate](#errortemplate-element) | React.ReactNode | Error page template | `<DefaultErrorTemplate />` |
|
|
144
217
|
| [errorTitle](#errortitle-string) | string | Error page title | `"Page error [500]"` |
|
|
145
218
|
| [useTrailingSlash](#usetrailingslash-bool) | boolean | Use trailing slashes in URLs | `true` |
|
|
146
|
-
| [usePrerenderTags](#useprerendertags-bool) | boolean | Use pre-render meta tags | `
|
|
219
|
+
| [usePrerenderTags](#useprerendertags-bool) | boolean | Use pre-render meta tags | `false` |
|
|
147
220
|
| [baseUrl](#baseurl-string) | string | Base URL for canonical tags | `null` (uses window.location) |
|
|
148
221
|
| [imageUrl](#imageurl-string) | string | Default image URL for sharing | `null` |
|
|
149
222
|
| [touchIconUrl](#touchiconurl-string) | string | Image URL for PWA homescreen icon | `null` |
|
|
150
223
|
| [debug](#debug-boolean) | boolean | Enable debug mode | `false` |
|
|
151
|
-
| [titlePrefix](#titleprefix-string) | string | Deprecated: Title prefix | `""` |
|
|
152
|
-
| [titlePostfix](#titlepostfix-string) | string | Deprecated: Title postfix | `""` |
|
|
153
224
|
|
|
154
225
|
##### `title`: string;
|
|
155
226
|
|
|
@@ -220,30 +291,18 @@ Default: `true`
|
|
|
220
291
|
|
|
221
292
|
##### `usePrerenderTags`: bool;
|
|
222
293
|
|
|
223
|
-
Include meta tags to enable proper error codes like 404 when serving pages to a search crawler.
|
|
294
|
+
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.
|
|
224
295
|
|
|
225
|
-
Default: `
|
|
296
|
+
Default: `false`
|
|
226
297
|
|
|
227
298
|
##### `baseUrl`: string;
|
|
228
299
|
|
|
229
300
|
The base URL to use for canonical tags and og:url meta tags. If not provided, uses `window.location.origin`. This is useful when you want to specify the production URL regardless of the current environment.
|
|
230
301
|
|
|
231
|
-
|
|
302
|
+
**Important:** The baseUrl must NOT end with a trailing slash (`/`). Correct example: `"https://example.com"`
|
|
232
303
|
|
|
233
304
|
Default: `null` (uses window.location.origin)
|
|
234
305
|
|
|
235
|
-
##### `titlePrefix`: string;
|
|
236
|
-
|
|
237
|
-
Deprecated: use `title` instead. A string to preprend to every title. Should include the brand name, a separator, and spacing, such as `Example.com | `<- Note the extra end space.
|
|
238
|
-
|
|
239
|
-
Default: `""` (empty string)
|
|
240
|
-
|
|
241
|
-
##### `titlePostfix`: string;
|
|
242
|
-
|
|
243
|
-
Deprecated: use `title` instead. A string to append to every title. Should include the brand name, a separator, and spacing, such as the following example. Note the extra starting space ->` - Example.com`.
|
|
244
|
-
|
|
245
|
-
Default: `""` (empty string)
|
|
246
|
-
|
|
247
306
|
##### `imageUrl`: string;
|
|
248
307
|
|
|
249
308
|
A string containing the path of the default (site-wide) image to use for sharing previews.
|
|
@@ -258,7 +317,21 @@ Default: `null`
|
|
|
258
317
|
|
|
259
318
|
##### `debug`: boolean;
|
|
260
319
|
|
|
261
|
-
Enable debug mode for additional logging and information.
|
|
320
|
+
Enable debug mode for additional logging and information. When enabled, Routerino logs detailed information to the console including:
|
|
321
|
+
|
|
322
|
+
- Route changes and pattern matching
|
|
323
|
+
- Meta tag updates
|
|
324
|
+
- Error boundaries and component failures
|
|
325
|
+
- Performance timing information
|
|
326
|
+
|
|
327
|
+
Example debug output:
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
[Routerino] Route changed to: /products/laptop/
|
|
331
|
+
[Routerino] Matched pattern: /products/:id/
|
|
332
|
+
[Routerino] Route params: { id: "laptop" }
|
|
333
|
+
[Routerino] Updated meta tag: og:title = "Laptop Pro - $1299"
|
|
334
|
+
```
|
|
262
335
|
|
|
263
336
|
Default: `false`
|
|
264
337
|
|
|
@@ -268,7 +341,7 @@ There is a default RouteConfig that will be loaded if you don't specify any rout
|
|
|
268
341
|
|
|
269
342
|
##### path: string;
|
|
270
343
|
|
|
271
|
-
The path of the desired route. **Must start with a forward slash (`/`)**. For example: `"/foo/"`, or `"/about/"`.
|
|
344
|
+
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.
|
|
272
345
|
|
|
273
346
|
##### element: React.ReactNode;
|
|
274
347
|
|
|
@@ -286,14 +359,6 @@ The page's description, which will show up on search results pages.
|
|
|
286
359
|
|
|
287
360
|
Any desired head tags for that route. See [HeadTag props](#headtag-props) for details.
|
|
288
361
|
|
|
289
|
-
##### titlePrefix?: string;
|
|
290
|
-
|
|
291
|
-
Deprecated: a title prefix for this route to override the default. Use title and separator instead.
|
|
292
|
-
|
|
293
|
-
##### titlePostfix?: string;
|
|
294
|
-
|
|
295
|
-
Deprecated: a title postfix for this route to override the default. Use title and separator instead.
|
|
296
|
-
|
|
297
362
|
##### imageUrl?: string;
|
|
298
363
|
|
|
299
364
|
An image URL to set for the page's og:image tag.
|
|
@@ -334,14 +399,39 @@ An array of HeadTag objects that can be added to the route to manage meta tags,
|
|
|
334
399
|
|
|
335
400
|
- `target` (string): The "target" attribute of the tag. Defines where to open the linked resource.
|
|
336
401
|
|
|
337
|
-
###
|
|
402
|
+
### Using the `useRouterino` Hook
|
|
403
|
+
|
|
404
|
+
The `useRouterino` hook provides access to router state from any child component. This is the primary way to access route information and update head tags dynamically.
|
|
405
|
+
|
|
406
|
+
```jsx
|
|
407
|
+
import { useRouterino } from "routerino";
|
|
408
|
+
|
|
409
|
+
function MyComponent() {
|
|
410
|
+
const { currentRoute, params, routePattern, updateHeadTag } = useRouterino();
|
|
338
411
|
|
|
339
|
-
|
|
412
|
+
// Access current route information
|
|
413
|
+
console.log("Current path:", currentRoute); // e.g., "/products/laptop/"
|
|
414
|
+
console.log("Route pattern:", routePattern); // e.g., "/products/:id/"
|
|
415
|
+
console.log("Route params:", params); // e.g., { id: "laptop" }
|
|
340
416
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
417
|
+
// Update meta tags dynamically
|
|
418
|
+
useEffect(() => {
|
|
419
|
+
updateHeadTag({
|
|
420
|
+
name: "description",
|
|
421
|
+
content: `Product page for ${params.id}`,
|
|
422
|
+
});
|
|
423
|
+
}, [params.id]);
|
|
424
|
+
|
|
425
|
+
return <div>Product: {params.id}</div>;
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
#### Hook Return Values
|
|
430
|
+
|
|
431
|
+
- **`currentRoute`**: The current URL path (e.g., `/foo/bar/`)
|
|
432
|
+
- **`routePattern`**: The matched route pattern with parameters (e.g., `/foo/:id/`)
|
|
433
|
+
- **`params`**: Object containing route parameters (e.g., `{id: "bar"}`)
|
|
434
|
+
- **`updateHeadTag`**: Function to dynamically update head tags (see [updateHeadTag](#updateheadtag) section)
|
|
345
435
|
|
|
346
436
|
### `updateHeadTag`
|
|
347
437
|
|
|
@@ -349,11 +439,42 @@ The `updateHeadTag` function is responsible for creating or updating the specifi
|
|
|
349
439
|
|
|
350
440
|
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.
|
|
351
441
|
|
|
352
|
-
|
|
442
|
+
#### Props
|
|
353
443
|
|
|
354
444
|
See [HeadTag props](#headtag-props) for arguments and some common tag attributes.
|
|
355
445
|
|
|
356
|
-
|
|
446
|
+
## TypeScript Support
|
|
447
|
+
|
|
448
|
+
Routerino includes TypeScript definitions out of the box. The types are automatically available when you import Routerino.
|
|
449
|
+
|
|
450
|
+
### Basic Usage
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// Both import styles are supported
|
|
454
|
+
import Routerino from 'routerino'; // Default import
|
|
455
|
+
// or
|
|
456
|
+
import { Routerino } from 'routerino'; // Named import (recommended)
|
|
457
|
+
|
|
458
|
+
import type { RouteConfig } from 'routerino';
|
|
459
|
+
|
|
460
|
+
export const routes: RouteConfig[] = [
|
|
461
|
+
{
|
|
462
|
+
path: '/',
|
|
463
|
+
element: <HomePage />,
|
|
464
|
+
title: 'Home',
|
|
465
|
+
description: 'Welcome to our site'
|
|
466
|
+
}
|
|
467
|
+
];
|
|
468
|
+
|
|
469
|
+
// TypeScript will validate all props
|
|
470
|
+
<Routerino
|
|
471
|
+
routes={routes}
|
|
472
|
+
baseUrl="https://example.com"
|
|
473
|
+
title="My Site"
|
|
474
|
+
/>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Examples
|
|
357
478
|
|
|
358
479
|
Setting a page description:
|
|
359
480
|
|
|
@@ -379,32 +500,144 @@ To optimize your site for SEO and social previews when using Routerino, consider
|
|
|
379
500
|
|
|
380
501
|
### Page Titles
|
|
381
502
|
|
|
382
|
-
- Keep page titles unique for each route. Avoid including the site
|
|
503
|
+
- Keep page titles unique for each route. Avoid including the site name like "Foo.com" in individual page titles, Routerino adds that automatically.
|
|
383
504
|
- Aim for concise, descriptive titles that accurately represent the page content.
|
|
384
|
-
-
|
|
505
|
+
- 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).
|
|
506
|
+
|
|
507
|
+
### URL Structure & Canonicalization
|
|
508
|
+
|
|
509
|
+
#### Canonical URLs (Don't worry, this is handled for you!)
|
|
510
|
+
|
|
511
|
+
**What is canonicalization?**
|
|
385
512
|
|
|
386
|
-
|
|
513
|
+
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.
|
|
387
514
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
-
|
|
515
|
+
**How Routerino handles this automatically**
|
|
516
|
+
|
|
517
|
+
- Sets `<link rel="canonical">` tags on every page pointing to the preferred URL version
|
|
518
|
+
- Uses the `useTrailingSlash` prop (default: `true`) to determine the canonical format
|
|
519
|
+
- Generates proper `og:url` meta tags for social sharing
|
|
520
|
+
- For SSG: Creates both file versions (`/about.html` and `/about/index.html`) with canonical tags
|
|
521
|
+
- For Prerender: Includes meta tags that instruct the prerender server to return 301 redirects
|
|
522
|
+
- Ensures sitemap.xml only contains canonical URLs
|
|
523
|
+
|
|
524
|
+
**Best practices that Routerino implements**
|
|
525
|
+
|
|
526
|
+
- Consistency: Sitemap, canonical, and redirects all agree
|
|
527
|
+
- Dual file generation (SSG): Creates both `/about.html` and `/about/index.html` so both URLs work
|
|
528
|
+
- Prerender support (SPA): Includes meta tags that tell prerender services to serve proper status codes
|
|
529
|
+
- Absolute URLs: When `baseUrl` is provided, canonical tags use the provided base instead of defaulting to the current domain
|
|
530
|
+
|
|
531
|
+
**Example of what's generated**
|
|
532
|
+
|
|
533
|
+
With Static Site Generation (SSG):
|
|
534
|
+
|
|
535
|
+
```html
|
|
536
|
+
<!-- Both /about.html and /about/index.html contain: -->
|
|
537
|
+
<link rel="canonical" href="https://example.com/about/" />
|
|
538
|
+
<meta property="og:url" content="https://example.com/about/" />
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
With Prerender (SPA):
|
|
542
|
+
|
|
543
|
+
```html
|
|
544
|
+
<!-- For canonical URL (/about/) -->
|
|
545
|
+
<link rel="canonical" href="https://example.com/about/" />
|
|
546
|
+
<meta property="og:url" content="https://example.com/about/" />
|
|
547
|
+
|
|
548
|
+
<!-- For non-canonical URL (/about) -->
|
|
549
|
+
<meta name="prerender-status-code" content="301" />
|
|
550
|
+
<meta name="prerender-header" content="Location: https://example.com/about/" />
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
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.
|
|
391
554
|
|
|
392
555
|
### Sitemap Generation
|
|
393
556
|
|
|
394
557
|
- Automate the creation of `sitemap.xml` and `robots.txt` during your build process with Routerino Forge.
|
|
395
558
|
- The Vite plugin automatically generates these files when building static sites (see [Static Site Generation](#static-site-generation)).
|
|
396
559
|
|
|
397
|
-
### Social Previews
|
|
560
|
+
### Social Previews & Open Graph
|
|
561
|
+
|
|
562
|
+
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:
|
|
563
|
+
|
|
564
|
+
#### Image Best Practices
|
|
565
|
+
|
|
566
|
+
- Size: Use 1200×630 pixels (1.91:1 ratio) for maximum compatibility
|
|
567
|
+
- Content: Avoid text in images - use metadata for text instead (per Apple's guidelines)
|
|
568
|
+
- Add dimensions for faster first-share rendering:
|
|
569
|
+
```js
|
|
570
|
+
// In your route's component or after data loading
|
|
571
|
+
updateHeadTag({ property: "og:image:width", content: "1200" });
|
|
572
|
+
updateHeadTag({ property: "og:image:height", content: "630" });
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
#### Title & Branding
|
|
576
|
+
|
|
577
|
+
- Don't duplicate branding in `og:title` - Routerino uses your page title directly
|
|
578
|
+
- For site-wide branding, add `og:site_name` instead:
|
|
579
|
+
```js
|
|
580
|
+
updateHeadTag({ property: "og:site_name", content: "Your Brand" });
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
#### Platform-Specific Enhancements
|
|
584
|
+
|
|
585
|
+
- Apple/iMessage: Set `touchIconUrl` prop for iMessage link previews
|
|
586
|
+
- Video content: Add direct playable assets when possible:
|
|
587
|
+
```js
|
|
588
|
+
updateHeadTag({
|
|
589
|
+
property: "og:video",
|
|
590
|
+
content: "https://example.com/video.mp4",
|
|
591
|
+
});
|
|
592
|
+
updateHeadTag({ property: "og:video:type", content: "video/mp4" });
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
#### Testing Your Previews
|
|
596
|
+
|
|
597
|
+
Test how your links appear on different platforms:
|
|
598
|
+
|
|
599
|
+
- [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) - Use "Scrape Again" after changes
|
|
600
|
+
- [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/)
|
|
601
|
+
- [Twitter Card Validator](https://cards-dev.twitter.com/validator)
|
|
602
|
+
|
|
603
|
+
**Tip**: Social platforms cache previews aggressively. After updating tags, use each platform's debugger to force a refresh.
|
|
604
|
+
|
|
605
|
+
#### Twitter Card Tags (Handled Automatically)
|
|
398
606
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
607
|
+
Routerino automatically includes Twitter card meta tags to ensure rich previews when your links are shared on Twitter/X:
|
|
608
|
+
|
|
609
|
+
```html
|
|
610
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
**What this does:**
|
|
614
|
+
|
|
615
|
+
- Without Twitter cards: Links appear as plain URLs with no preview
|
|
616
|
+
- With Twitter cards: Links show rich previews with title, description, and image
|
|
617
|
+
|
|
618
|
+
**How it works:**
|
|
619
|
+
|
|
620
|
+
- Routerino always sets `summary_large_image` for maximum engagement
|
|
621
|
+
- If you provide an `imageUrl`, Twitter displays a large prominent image
|
|
622
|
+
- If no image is provided, Twitter gracefully falls back to a text-only card
|
|
623
|
+
- This is better than no card at all (which would show just the bare URL)
|
|
624
|
+
|
|
625
|
+
**The complete picture:**
|
|
626
|
+
|
|
627
|
+
```html
|
|
628
|
+
<!-- What Routerino generates for social sharing -->
|
|
629
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
630
|
+
<meta property="og:title" content="Your Page Title" />
|
|
631
|
+
<meta property="og:description" content="Your page description" />
|
|
632
|
+
<meta property="og:image" content="https://example.com/preview.jpg" />
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
This creates an engaging Twitter preview with a large image, title, and description - much more clickable than a plain URL.
|
|
403
636
|
|
|
404
637
|
### Meta Descriptions
|
|
405
638
|
|
|
406
639
|
- Provide unique, informative descriptions for each route.
|
|
407
|
-
-
|
|
640
|
+
- Descriptions may be used for snippets so keep them short and to the point.
|
|
408
641
|
- Descriptions longer than ~150 characters may be truncated in search results.
|
|
409
642
|
|
|
410
643
|
### Additional SEO Considerations
|
|
@@ -419,10 +652,10 @@ By following these practices, you'll improve your site's SEO performance and soc
|
|
|
419
652
|
|
|
420
653
|
When using Routerino Forge for static site generation, `sitemap.xml` and `robots.txt` files are automatically generated during the build process:
|
|
421
654
|
|
|
422
|
-
-
|
|
423
|
-
-
|
|
655
|
+
- sitemap.xml: Contains all static routes (dynamic routes with parameters like `:id` are excluded)
|
|
656
|
+
- robots.txt: Created with a reference to the sitemap (if it doesn't already exist)
|
|
424
657
|
|
|
425
|
-
These files are generated automatically when you build with the Routerino Forge Vite plugin - no additional configuration needed
|
|
658
|
+
These files are generated automatically when you build with the Routerino Forge Vite plugin - no additional configuration needed.
|
|
426
659
|
|
|
427
660
|
### Sample Build Output:
|
|
428
661
|
|
|
@@ -450,7 +683,7 @@ export default defineConfig({
|
|
|
450
683
|
plugins: [
|
|
451
684
|
react(),
|
|
452
685
|
routerinoForge({
|
|
453
|
-
baseUrl: "https://example.com", // Your production URL
|
|
686
|
+
baseUrl: "https://example.com", // Your production URL (no trailing slash)
|
|
454
687
|
// Optional settings (these are the defaults):
|
|
455
688
|
// routes: "./src/routes.jsx", // Your routes file
|
|
456
689
|
// outputDir: "dist",
|
|
@@ -458,6 +691,8 @@ export default defineConfig({
|
|
|
458
691
|
// prerenderStatusCode: true,
|
|
459
692
|
// useTrailingSlash: true, // Set to false for /about instead of /about/
|
|
460
693
|
// verbose: false,
|
|
694
|
+
// ssgCacheDir: "node_modules/.cache/routerino-forge", // SSG cache directory
|
|
695
|
+
// optimizeImages: true, // Enable image optimization (see below)
|
|
461
696
|
}),
|
|
462
697
|
],
|
|
463
698
|
});
|
|
@@ -466,7 +701,7 @@ export default defineConfig({
|
|
|
466
701
|
**Requirements:**
|
|
467
702
|
|
|
468
703
|
- Your `index.html` must have `<div id="root"></div>` (standard for all React apps)
|
|
469
|
-
- Routes must be exported
|
|
704
|
+
- **IMPORTANT**: Routes must be exported (not defined inline) for SSG to work
|
|
470
705
|
|
|
471
706
|
**Features:**
|
|
472
707
|
|
|
@@ -476,24 +711,139 @@ export default defineConfig({
|
|
|
476
711
|
- `/about/` → `about/index.html`
|
|
477
712
|
- Canonical URLs and redirects based on `useTrailingSlash` setting
|
|
478
713
|
- Prerender compatible 301 redirects for non-canonical versions
|
|
714
|
+
- **Static host ready**: Output format aligns perfectly with Vercel, Netlify, and Cloudflare Pages conventions
|
|
715
|
+
- Routes generate `/path/index.html` for clean URLs (and `/path.html` for compatibility with no-slash URLs)
|
|
716
|
+
- `404.html` at root for custom error pages
|
|
717
|
+
- No server configuration needed - just deploy!
|
|
479
718
|
- Automatic canonical URL and og:url meta tags
|
|
480
719
|
- Injects rendered HTML into your root div
|
|
481
720
|
- Generates sitemap.xml and robots.txt
|
|
482
721
|
- Creates a 404.html page
|
|
483
722
|
- Skips dynamic routes (with `:param` syntax)
|
|
484
723
|
- SEO optimized: Complete HTML with meta tags
|
|
724
|
+
- Image optimization: Automatic blur placeholders (LQIP)
|
|
485
725
|
- Easy configuration: Works out of the box with Vite and minimal setup
|
|
486
726
|
|
|
727
|
+
#### Image Optimization
|
|
728
|
+
|
|
729
|
+
Routerino Forge can automatically optimize images in your static builds for faster loading:
|
|
730
|
+
|
|
731
|
+
```js
|
|
732
|
+
routerinoForge({
|
|
733
|
+
optimizeImages: true, // Enable with defaults
|
|
734
|
+
// Or configure in detail:
|
|
735
|
+
optimizeImages: {
|
|
736
|
+
enabled: true,
|
|
737
|
+
placeholderSize: 20, // Size of blur placeholder (20x20 pixels)
|
|
738
|
+
blur: 4, // Blur radius for placeholder
|
|
739
|
+
maxSize: 10485760, // Maximum image size to process (10MB)
|
|
740
|
+
minSize: 1024, // Minimum image size to process (1KB)
|
|
741
|
+
cacheDir: "node_modules/.cache/routerino-forge", // Cache directory
|
|
742
|
+
},
|
|
743
|
+
});
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**What it does:**
|
|
747
|
+
|
|
748
|
+
- Generates tiny blur placeholders for images (base64 encoded)
|
|
749
|
+
- Caches processed images to speed up subsequent builds
|
|
750
|
+
- Preserves original images while enhancing loading performance
|
|
751
|
+
- Skips external images (http/https), data URIs, and SVGs
|
|
752
|
+
|
|
753
|
+
**Note:** Image optimization requires `ffmpeg` to be installed. Without it, images work normally but without blur placeholders. Install with `brew install ffmpeg` (Mac), `apt install ffmpeg` (Ubuntu), or `choco install ffmpeg` (Windows).
|
|
754
|
+
|
|
755
|
+
##### CI/CD Setup for Image Optimization
|
|
756
|
+
|
|
757
|
+
To enable image optimization in your CI/CD pipeline, you need to install ffmpeg. Here are examples for the most common setups:
|
|
758
|
+
|
|
759
|
+
###### GitHub Actions
|
|
760
|
+
|
|
761
|
+
Add the `setup-ffmpeg` action to your workflow:
|
|
762
|
+
|
|
763
|
+
```yaml
|
|
764
|
+
name: Build and Deploy
|
|
765
|
+
|
|
766
|
+
on:
|
|
767
|
+
push:
|
|
768
|
+
branches: [main]
|
|
769
|
+
|
|
770
|
+
jobs:
|
|
771
|
+
build:
|
|
772
|
+
runs-on: ubuntu-latest
|
|
773
|
+
|
|
774
|
+
steps:
|
|
775
|
+
- uses: actions/checkout@v4
|
|
776
|
+
|
|
777
|
+
- uses: actions/setup-node@v4
|
|
778
|
+
with:
|
|
779
|
+
node-version: "20"
|
|
780
|
+
cache: "npm"
|
|
781
|
+
|
|
782
|
+
# Install ffmpeg for image optimization
|
|
783
|
+
- name: Setup FFmpeg
|
|
784
|
+
uses: FedericoCarboni/setup-ffmpeg@v3
|
|
785
|
+
with:
|
|
786
|
+
ffmpeg-version: release
|
|
787
|
+
|
|
788
|
+
- run: npm ci
|
|
789
|
+
- run: npm run build
|
|
790
|
+
|
|
791
|
+
# Deploy to GitHub Pages (optional)
|
|
792
|
+
- uses: peaceiris/actions-gh-pages@v3
|
|
793
|
+
if: github.ref == 'refs/heads/main'
|
|
794
|
+
with:
|
|
795
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
796
|
+
publish_dir: ./dist
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
###### Docker
|
|
800
|
+
|
|
801
|
+
For containerized deployments, install ffmpeg in your Dockerfile:
|
|
802
|
+
|
|
803
|
+
```dockerfile
|
|
804
|
+
FROM node:20-alpine
|
|
805
|
+
|
|
806
|
+
# Install ffmpeg
|
|
807
|
+
RUN apk add --no-cache ffmpeg
|
|
808
|
+
|
|
809
|
+
WORKDIR /app
|
|
810
|
+
|
|
811
|
+
# Copy package files
|
|
812
|
+
COPY package*.json ./
|
|
813
|
+
RUN npm ci
|
|
814
|
+
|
|
815
|
+
# Copy source and build
|
|
816
|
+
COPY . .
|
|
817
|
+
RUN npm run build
|
|
818
|
+
|
|
819
|
+
# Production stage with nginx
|
|
820
|
+
FROM nginx:alpine
|
|
821
|
+
COPY --from=0 /app/dist /usr/share/nginx/html
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
###### Netlify
|
|
825
|
+
|
|
826
|
+
Netlify builds run on Ubuntu images, so you can install ffmpeg using apt-get in your build command.
|
|
827
|
+
|
|
828
|
+
In your netlify.toml:
|
|
829
|
+
|
|
830
|
+
```
|
|
831
|
+
[build]
|
|
832
|
+
command = "apt-get update && apt-get install -y ffmpeg && npm ci && npm run build"
|
|
833
|
+
publish = "dist"
|
|
834
|
+
```
|
|
835
|
+
|
|
487
836
|
#### Routes Configuration
|
|
488
837
|
|
|
489
|
-
|
|
838
|
+
**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.
|
|
839
|
+
|
|
840
|
+
Define routes with an `element` property containing JSX elements:
|
|
490
841
|
|
|
491
842
|
```jsx
|
|
492
|
-
// src/routes.jsx
|
|
493
843
|
export const routes = [
|
|
494
844
|
{
|
|
495
845
|
path: "/",
|
|
496
|
-
element: <HomePage featured="Latest News" />, // Props preserved
|
|
846
|
+
element: <HomePage featured="Latest News" />, // Props preserved
|
|
497
847
|
title: "Home - My Site",
|
|
498
848
|
description: "Welcome to our site",
|
|
499
849
|
imageUrl: "/images/home-og.jpg", // Optional social image
|
|
@@ -520,14 +870,97 @@ export const notFoundTemplate = (
|
|
|
520
870
|
);
|
|
521
871
|
```
|
|
522
872
|
|
|
873
|
+
#### Generating Routes from Data (e.g., Product Listings)
|
|
874
|
+
|
|
875
|
+
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:
|
|
876
|
+
|
|
877
|
+
```jsx
|
|
878
|
+
// src/routes.jsx
|
|
879
|
+
import { ProductPage } from "./components/ProductPage";
|
|
880
|
+
import { BlogPost } from "./components/BlogPost";
|
|
881
|
+
|
|
882
|
+
// This could be fetched from an API at build time
|
|
883
|
+
const products = [
|
|
884
|
+
{
|
|
885
|
+
id: "laptop-pro",
|
|
886
|
+
name: "Laptop Pro",
|
|
887
|
+
price: 1299,
|
|
888
|
+
description: "High-performance laptop",
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
id: "wireless-mouse",
|
|
892
|
+
name: "Wireless Mouse",
|
|
893
|
+
price: 49,
|
|
894
|
+
description: "Ergonomic wireless mouse",
|
|
895
|
+
},
|
|
896
|
+
{ id: "usb-hub", name: "USB Hub", price: 29, description: "7-port USB hub" },
|
|
897
|
+
];
|
|
898
|
+
|
|
899
|
+
// Generate a route for each product
|
|
900
|
+
const productRoutes = products.map((product) => ({
|
|
901
|
+
path: `/products/${product.id}/`,
|
|
902
|
+
element: <ProductPage product={product} />,
|
|
903
|
+
title: `${product.name} - $${product.price}`,
|
|
904
|
+
description: product.description,
|
|
905
|
+
tags: [
|
|
906
|
+
{ property: "og:type", content: "product" },
|
|
907
|
+
{ property: "product:price:amount", content: product.price.toString() },
|
|
908
|
+
{ property: "product:price:currency", content: "USD" },
|
|
909
|
+
],
|
|
910
|
+
}));
|
|
911
|
+
|
|
912
|
+
// You can also fetch data asynchronously at build time
|
|
913
|
+
const blogPosts = await fetch("https://api.example.com/posts")
|
|
914
|
+
.then((res) => res.json())
|
|
915
|
+
.catch(() => []); // Fallback to empty array if API fails
|
|
916
|
+
|
|
917
|
+
const blogRoutes = blogPosts.map((post) => ({
|
|
918
|
+
path: `/blog/${post.slug}/`,
|
|
919
|
+
element: <BlogPost post={post} />,
|
|
920
|
+
title: post.title,
|
|
921
|
+
description: post.excerpt,
|
|
922
|
+
imageUrl: post.featuredImage,
|
|
923
|
+
tags: [
|
|
924
|
+
{ property: "og:type", content: "article" },
|
|
925
|
+
{ property: "article:published_time", content: post.publishedAt },
|
|
926
|
+
{ property: "article:author", content: post.author },
|
|
927
|
+
],
|
|
928
|
+
}));
|
|
929
|
+
|
|
930
|
+
// Combine all routes
|
|
931
|
+
export const routes = [
|
|
932
|
+
{
|
|
933
|
+
path: "/",
|
|
934
|
+
element: <HomePage />,
|
|
935
|
+
title: "Home",
|
|
936
|
+
description: "Welcome to our store",
|
|
937
|
+
},
|
|
938
|
+
...productRoutes, // All products get their own static pages
|
|
939
|
+
...blogRoutes, // All blog posts get their own static pages
|
|
940
|
+
{
|
|
941
|
+
path: "/products/",
|
|
942
|
+
element: <ProductListing products={products} />,
|
|
943
|
+
title: "All Products",
|
|
944
|
+
description: "Browse our product catalog",
|
|
945
|
+
},
|
|
946
|
+
];
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
**Benefits of this approach:**
|
|
950
|
+
|
|
951
|
+
- Each product/post gets its own static HTML page with proper SEO meta tags
|
|
952
|
+
- All generated routes are automatically included in `sitemap.xml`
|
|
953
|
+
- Search engines can discover and index every product/post
|
|
954
|
+
- Fast page loads since HTML is pre-rendered at build time
|
|
955
|
+
- Type-safe if using TypeScript with your data structures
|
|
956
|
+
|
|
523
957
|
### What Gets Generated
|
|
524
958
|
|
|
525
959
|
The static build process will:
|
|
526
960
|
|
|
527
|
-
- Generate
|
|
961
|
+
- Generate HTML files for each static route (e.g., `/about/` → `about/index.html` & `about.html`)
|
|
528
962
|
- Skip dynamic routes with parameters (e.g., `/user/:id`)
|
|
529
|
-
- Apply route-specific meta tags (title, description, og:image
|
|
530
|
-
- Add proper `data-route` attributes for client-side hydration
|
|
963
|
+
- Apply route-specific meta tags (title, description, og:image)
|
|
531
964
|
- Generate `sitemap.xml` with all static routes (Vite plugin only)
|
|
532
965
|
- Preserve your existing HTML structure and assets
|
|
533
966
|
|
|
@@ -597,15 +1030,15 @@ npm install
|
|
|
597
1030
|
|
|
598
1031
|
This command will read the `package.json` file in your project and install all the necessary dependencies.
|
|
599
1032
|
|
|
600
|
-
5. Now, add Routerino to your project as a
|
|
1033
|
+
5. Now, add Routerino to your project as a dependency:
|
|
601
1034
|
|
|
602
1035
|
```
|
|
603
1036
|
|
|
604
|
-
npm install routerino
|
|
1037
|
+
npm install routerino
|
|
605
1038
|
|
|
606
1039
|
```
|
|
607
1040
|
|
|
608
|
-
This command will install the latest version of Routerino and save it to your `package.json` file under the `
|
|
1041
|
+
This command will install the latest version of Routerino and save it to your `package.json` file under the `dependencies` section.
|
|
609
1042
|
|
|
610
1043
|
With these steps, you'll have a new React project set up with Vite as the build tool and Routerino installed as a development dependency. You can now start building your application with React & Routerino.
|
|
611
1044
|
|
|
@@ -615,9 +1048,38 @@ This example includes the full React configuration. It might take the place of `
|
|
|
615
1048
|
|
|
616
1049
|
```jsx
|
|
617
1050
|
import React from "react";
|
|
618
|
-
import {
|
|
1051
|
+
import { createRoot } from "react-dom/client";
|
|
619
1052
|
import Routerino from "routerino";
|
|
620
1053
|
|
|
1054
|
+
export const routes = [
|
|
1055
|
+
{
|
|
1056
|
+
path: "/",
|
|
1057
|
+
element: <p>Welcome to Home</p>,
|
|
1058
|
+
title: "Home",
|
|
1059
|
+
description: "Welcome to my website!",
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
path: "/about/",
|
|
1063
|
+
element: <p>About us...</p>,
|
|
1064
|
+
title: "About",
|
|
1065
|
+
description: "Learn more about us.",
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
path: "/contact/",
|
|
1069
|
+
element: (
|
|
1070
|
+
<div>
|
|
1071
|
+
<h1>Contact Us</h1>
|
|
1072
|
+
<p>
|
|
1073
|
+
Please <a href="mailto:user@example.com">send us an email</a> at
|
|
1074
|
+
user@example.com
|
|
1075
|
+
</p>
|
|
1076
|
+
</div>
|
|
1077
|
+
),
|
|
1078
|
+
title: "Contact",
|
|
1079
|
+
description: "Get in touch with us.",
|
|
1080
|
+
},
|
|
1081
|
+
];
|
|
1082
|
+
|
|
621
1083
|
const App = () => (
|
|
622
1084
|
<main>
|
|
623
1085
|
<nav>
|
|
@@ -628,34 +1090,7 @@ const App = () => (
|
|
|
628
1090
|
title="Example.com"
|
|
629
1091
|
notFoundTitle="Sorry, but this page does not exist."
|
|
630
1092
|
errorTitle="Yikes! Something went wrong."
|
|
631
|
-
routes={
|
|
632
|
-
{
|
|
633
|
-
path: "/",
|
|
634
|
-
element: <p>Welcome to Home</p>,
|
|
635
|
-
title: "Home",
|
|
636
|
-
description: "Welcome to my website!",
|
|
637
|
-
},
|
|
638
|
-
{
|
|
639
|
-
path: "/about/",
|
|
640
|
-
element: <p>About us...</p>,
|
|
641
|
-
title: "About",
|
|
642
|
-
description: "Learn more about us.",
|
|
643
|
-
},
|
|
644
|
-
{
|
|
645
|
-
path: "/contact/",
|
|
646
|
-
element: (
|
|
647
|
-
<div>
|
|
648
|
-
<h1>Contact Us</h1>
|
|
649
|
-
<p>
|
|
650
|
-
Please <a href="mailto:user@example.com">send us an email</a> at
|
|
651
|
-
user@example.com
|
|
652
|
-
</p>
|
|
653
|
-
</div>
|
|
654
|
-
),
|
|
655
|
-
title: "Contact",
|
|
656
|
-
description: "Get in touch with us.",
|
|
657
|
-
},
|
|
658
|
-
]}
|
|
1093
|
+
routes={routes}
|
|
659
1094
|
/>
|
|
660
1095
|
|
|
661
1096
|
<footer>
|
|
@@ -667,7 +1102,7 @@ const App = () => (
|
|
|
667
1102
|
</main>
|
|
668
1103
|
);
|
|
669
1104
|
|
|
670
|
-
|
|
1105
|
+
createRoot(document.getElementById("root")).render(<App />);
|
|
671
1106
|
```
|
|
672
1107
|
|
|
673
1108
|
## ErrorBoundary Component
|
|
@@ -686,7 +1121,7 @@ import { ErrorBoundary } from "routerino";
|
|
|
686
1121
|
<ErrorBoundary
|
|
687
1122
|
fallback={<div>Something went wrong. Please try again.</div>}
|
|
688
1123
|
errorTitleString="Error | My Application"
|
|
689
|
-
|
|
1124
|
+
debug={window.location.hostname === "localhost"} // Auto-enable on localhost
|
|
690
1125
|
>
|
|
691
1126
|
<MyComponent />
|
|
692
1127
|
</ErrorBoundary>
|
|
@@ -694,20 +1129,42 @@ import { ErrorBoundary } from "routerino";
|
|
|
694
1129
|
|
|
695
1130
|
### Props
|
|
696
1131
|
|
|
697
|
-
| Prop | Type | Required | Description
|
|
698
|
-
| ------------------ | ----------- | -------- |
|
|
699
|
-
| `children` | `ReactNode` | No | The child components to render when there's no error
|
|
700
|
-
| `fallback` | `ReactNode` | No | The UI to display when an error is caught
|
|
701
|
-
| `errorTitleString` | `string` | Yes | The document title to set when an error occurs
|
|
702
|
-
| `usePrerenderTags` | `boolean` | No | Whether to set prerender meta
|
|
1132
|
+
| Prop | Type | Required | Description |
|
|
1133
|
+
| ------------------ | ----------- | -------- | ----------------------------------------------------------------- |
|
|
1134
|
+
| `children` | `ReactNode` | No | The child components to render when there's no error |
|
|
1135
|
+
| `fallback` | `ReactNode` | No | The UI to display when an error is caught |
|
|
1136
|
+
| `errorTitleString` | `string` | Yes | The document title to set when an error occurs |
|
|
1137
|
+
| `usePrerenderTags` | `boolean` | No | Whether to set prerender meta tags (status code 500) |
|
|
1138
|
+
| `routePath` | `string` | No | The current route path for better error context (used internally) |
|
|
1139
|
+
| `debug` | `boolean` | No | Enable detailed console logging of errors (default: `false`) |
|
|
1140
|
+
|
|
1141
|
+
### Debug Logging
|
|
1142
|
+
|
|
1143
|
+
When `debug` is set to `true`, the ErrorBoundary provides detailed console output:
|
|
1144
|
+
|
|
1145
|
+
- Groups error information for better readability
|
|
1146
|
+
- Logs the component stack trace showing exactly where the error occurred
|
|
1147
|
+
- Shows the failed route path (if available)
|
|
1148
|
+
- Includes timestamp of when the error occurred
|
|
1149
|
+
|
|
1150
|
+
**Recommended debug pattern:**
|
|
1151
|
+
|
|
1152
|
+
```jsx
|
|
1153
|
+
// Auto-enable debug mode on localhost
|
|
1154
|
+
debug={window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1"}
|
|
1155
|
+
|
|
1156
|
+
// Or use environment variable
|
|
1157
|
+
debug={process.env.NODE_ENV === "development"}
|
|
1158
|
+
```
|
|
703
1159
|
|
|
704
1160
|
### Features
|
|
705
1161
|
|
|
706
1162
|
- Catches JavaScript errors in child component tree
|
|
707
1163
|
- Displays fallback UI instead of white screen
|
|
708
1164
|
- Sets document title on error
|
|
709
|
-
-
|
|
1165
|
+
- Provides detailed debug logging when enabled
|
|
710
1166
|
- Optionally sets prerender status code for SEO
|
|
1167
|
+
- Used internally by Routerino to protect route components
|
|
711
1168
|
|
|
712
1169
|
This is the same error boundary used internally by Routerino to protect your route components from crashing the entire application.
|
|
713
1170
|
|
|
@@ -734,10 +1191,10 @@ your-project/
|
|
|
734
1191
|
|
|
735
1192
|
```jsx
|
|
736
1193
|
// Before (importing from the package)
|
|
737
|
-
import
|
|
1194
|
+
import Routerino from "routerino";
|
|
738
1195
|
|
|
739
1196
|
// After (importing from the vendored file)
|
|
740
|
-
import
|
|
1197
|
+
import Routerino from "./vendor/routerino";
|
|
741
1198
|
```
|
|
742
1199
|
|
|
743
1200
|
4. You're all set! Routerino is now vendored in your project, and you can use it as before.
|