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/docs/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Routerino Documentation
|
|
2
|
+
|
|
3
|
+
- [Getting Started](./getting-started.md) — New project setup, full React example
|
|
4
|
+
- [SEO Guide](./seo-guide.md) — Page titles, canonical URLs, social previews, meta descriptions, hash links, structured data
|
|
5
|
+
- [Image Optimization](./image-optimization.md) — Delegating image optimization to `vite-plugin-image-optimizer`
|
|
6
|
+
- [Accessibility](./accessibility.md) — ESLint a11y setup, best practices for Lighthouse scores
|
|
7
|
+
- [Vendoring](./vendoring.md) — Including Routerino directly in your project
|
|
8
|
+
- [Additional Resources](./additional-resources.md) — External links for further reading
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Accessibility & Lighthouse Scores
|
|
2
|
+
|
|
3
|
+
To maximize your PageSpeed Insights and Lighthouse scores, set up ESLint with accessibility rules.
|
|
4
|
+
|
|
5
|
+
## Setting up eslint-plugin-jsx-a11y
|
|
6
|
+
|
|
7
|
+
1. Install the plugin:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install --save-dev eslint-plugin-jsx-a11y
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. Add to your ESLint config:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// eslint.config.js (ESLint 9+ flat config)
|
|
17
|
+
import jsxA11y from "eslint-plugin-jsx-a11y";
|
|
18
|
+
|
|
19
|
+
export default [
|
|
20
|
+
{
|
|
21
|
+
plugins: {
|
|
22
|
+
"jsx-a11y": jsxA11y,
|
|
23
|
+
},
|
|
24
|
+
rules: {
|
|
25
|
+
...jsxA11y.configs.recommended.rules,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
3. Add a lint run script:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"scripts": {
|
|
36
|
+
"lint": "eslint --ext .jsx,.js src/"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Key Rules
|
|
42
|
+
|
|
43
|
+
### Images: Include descriptive `alt` text
|
|
44
|
+
|
|
45
|
+
```jsx
|
|
46
|
+
// Bad - Missing alt text
|
|
47
|
+
<img src="/logo.png" />
|
|
48
|
+
|
|
49
|
+
// Good - Descriptive alt text
|
|
50
|
+
<img src="/logo.png" alt="Company logo" />
|
|
51
|
+
|
|
52
|
+
// Good - Decorative images
|
|
53
|
+
<img src="/decoration.png" alt="" role="presentation" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Heading Hierarchy: Use proper heading order
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
// Bad - Skipping heading levels
|
|
60
|
+
<h1>Page Title</h1>
|
|
61
|
+
<h3>Subsection</h3> // Should be h2
|
|
62
|
+
|
|
63
|
+
// Good - Proper hierarchy
|
|
64
|
+
<h1>Page Title</h1>
|
|
65
|
+
<h2>Main Section</h2>
|
|
66
|
+
<h3>Subsection</h3>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Link Text: Avoid generic link text
|
|
70
|
+
|
|
71
|
+
```jsx
|
|
72
|
+
// Bad - Generic text
|
|
73
|
+
<a href="/products">Click here</a>
|
|
74
|
+
|
|
75
|
+
// Good - Descriptive text
|
|
76
|
+
<a href="/products">View our products</a>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### ARIA Labels: Use for icon-only buttons
|
|
80
|
+
|
|
81
|
+
```jsx
|
|
82
|
+
<button aria-label="Close dialog">
|
|
83
|
+
<svg>...</svg>
|
|
84
|
+
</button>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
See [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y) for more info.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Additional Resources
|
|
2
|
+
|
|
3
|
+
- [Optimize Largest Contentful Paint (LCP)](https://web.dev/articles/optimize-lcp) — Improve loading performance
|
|
4
|
+
- [Apple's best practices for link previews](https://developer.apple.com/library/archive/technotes/tn2444/_index.html)
|
|
5
|
+
- [Use Open Graph tags](https://ahrefs.com/blog/open-graph-meta-tags/)
|
|
6
|
+
- [Use descriptive link text](https://developers.google.com/search/docs/fundamentals/seo-starter-guide)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Getting Started with Routerino
|
|
2
|
+
|
|
3
|
+
## Starting a New React Project
|
|
4
|
+
|
|
5
|
+
If you're starting from scratch, here's the recommended approach:
|
|
6
|
+
|
|
7
|
+
1. Ensure you have [Node.js](https://nodejs.org/) and npm installed. Consider using a Node version manager like [Volta](https://volta.sh/), [fnm](https://github.com/Schniz/fnm), or [asdf](https://asdf-vm.com/).
|
|
8
|
+
|
|
9
|
+
2. Create a new React project with [Vite](https://vitejs.dev/):
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm create vite@latest my-react-app -- --template react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
3. Install dependencies:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
cd my-react-app
|
|
19
|
+
npm install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
4. Add Routerino:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm install routerino
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Full React Example
|
|
29
|
+
|
|
30
|
+
This example includes the full React configuration. It can replace `src/main.jsx`:
|
|
31
|
+
|
|
32
|
+
```jsx
|
|
33
|
+
import React from "react";
|
|
34
|
+
import { createRoot } from "react-dom/client";
|
|
35
|
+
import Routerino from "routerino";
|
|
36
|
+
|
|
37
|
+
export const routes = [
|
|
38
|
+
{
|
|
39
|
+
path: "/",
|
|
40
|
+
element: <p>Welcome to Home</p>,
|
|
41
|
+
title: "Home",
|
|
42
|
+
description: "Welcome to my website!",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: "/about/",
|
|
46
|
+
element: <p>About us...</p>,
|
|
47
|
+
title: "About",
|
|
48
|
+
description: "Learn more about us.",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
path: "/contact/",
|
|
52
|
+
element: (
|
|
53
|
+
<div>
|
|
54
|
+
<h1>Contact Us</h1>
|
|
55
|
+
<p>
|
|
56
|
+
Please <a href="mailto:user@example.com">send us an email</a> at
|
|
57
|
+
user@example.com
|
|
58
|
+
</p>
|
|
59
|
+
</div>
|
|
60
|
+
),
|
|
61
|
+
title: "Contact",
|
|
62
|
+
description: "Get in touch with us.",
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const App = () => (
|
|
67
|
+
<main>
|
|
68
|
+
<nav>
|
|
69
|
+
<a href="/">Home</a>
|
|
70
|
+
</nav>
|
|
71
|
+
|
|
72
|
+
<Routerino
|
|
73
|
+
title="Example.com"
|
|
74
|
+
notFoundTitle="Sorry, but this page does not exist."
|
|
75
|
+
errorTitle="Yikes! Something went wrong."
|
|
76
|
+
routes={routes}
|
|
77
|
+
/>
|
|
78
|
+
|
|
79
|
+
<footer>
|
|
80
|
+
<p>
|
|
81
|
+
Learn more <a href="/about/">about us</a> or{" "}
|
|
82
|
+
<a href="/contact/">contact us</a> today.
|
|
83
|
+
</p>
|
|
84
|
+
</footer>
|
|
85
|
+
</main>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
createRoot(document.getElementById("root")).render(<App />);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Using Preact
|
|
92
|
+
|
|
93
|
+
Routerino is fully compatible with Preact via `@preact/compat`:
|
|
94
|
+
|
|
95
|
+
1. Install Preact:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
npm i preact @preact/compat
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
2. Configure your bundler:
|
|
102
|
+
|
|
103
|
+
**Vite:**
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
import { defineConfig } from "vite";
|
|
107
|
+
import preact from "@preact/preset-vite";
|
|
108
|
+
|
|
109
|
+
export default defineConfig({
|
|
110
|
+
plugins: [preact()],
|
|
111
|
+
resolve: {
|
|
112
|
+
alias: {
|
|
113
|
+
react: "@preact/compat",
|
|
114
|
+
"react-dom": "@preact/compat",
|
|
115
|
+
"react/jsx-runtime": "@preact/compat/jsx-runtime",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Webpack:**
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
module.exports = {
|
|
125
|
+
resolve: {
|
|
126
|
+
alias: {
|
|
127
|
+
react: "preact/compat",
|
|
128
|
+
"react-dom": "preact/compat",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
3. Use Routerino exactly as you would in a React project — the API is identical.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Image Optimization
|
|
2
|
+
|
|
3
|
+
Routerino delegates image optimization to [`vite-plugin-image-optimizer`](https://github.com/FatehAK/vite-plugin-image-optimizer). Install it along with `sharp` and add it to your Vite config **before** `routerinoForge`:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --save-dev vite-plugin-image-optimizer sharp
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// vite.config.js
|
|
11
|
+
import { defineConfig } from "vite";
|
|
12
|
+
import react from "@vitejs/plugin-react";
|
|
13
|
+
import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
|
|
14
|
+
import { routerinoForge } from "routerino/forge";
|
|
15
|
+
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
plugins: [
|
|
18
|
+
react(),
|
|
19
|
+
ViteImageOptimizer({
|
|
20
|
+
jpg: { quality: 80 },
|
|
21
|
+
jpeg: { quality: 80 },
|
|
22
|
+
png: { quality: 80 },
|
|
23
|
+
webp: { quality: 80 },
|
|
24
|
+
}),
|
|
25
|
+
routerinoForge({ baseUrl: "https://example.com" }),
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use standard HTML `<img>` tags in your components — the plugin optimizes source images in `public/` and imported assets during the Vite build. No special component or props needed.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# SEO Guide
|
|
2
|
+
|
|
3
|
+
## Page Titles
|
|
4
|
+
|
|
5
|
+
- Keep page titles unique for each route. Avoid including the site name like "Foo.com" in individual page titles — Routerino adds that automatically.
|
|
6
|
+
- Aim for concise, descriptive titles that accurately represent the page content.
|
|
7
|
+
- Keep title length at a max of 50-60 characters. Longer text may be ignored or cut off, especially on mobile.
|
|
8
|
+
|
|
9
|
+
## URL Structure & Canonicalization
|
|
10
|
+
|
|
11
|
+
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. Routerino handles this automatically.
|
|
12
|
+
|
|
13
|
+
**With SSG:** Creates both `/about.html` and `/about/index.html` with canonical tags:
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<link rel="canonical" href="https://example.com/about/" />
|
|
17
|
+
<meta property="og:url" content="https://example.com/about/" />
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**With Prerender (SPA):** Includes meta tags for correct status codes:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<!-- For canonical URL (/about/) -->
|
|
24
|
+
<link rel="canonical" href="https://example.com/about/" />
|
|
25
|
+
<meta property="og:url" content="https://example.com/about/" />
|
|
26
|
+
|
|
27
|
+
<!-- For non-canonical URL (/about) -->
|
|
28
|
+
<meta name="prerender-status-code" content="301" />
|
|
29
|
+
<meta name="prerender-header" content="Location: https://example.com/about/" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Use `useTrailingSlash={false}` if you prefer URLs without trailing slashes. Use `baseUrl` if your site is served from multiple domains:
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
<Routerino baseUrl="https://example.com" routes={routes} />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Social Previews & Open Graph
|
|
39
|
+
|
|
40
|
+
Routerino automatically sets core Open Graph tags (`og:title`, `og:description`, `og:url`, `og:image`) for every page.
|
|
41
|
+
|
|
42
|
+
### Image Best Practices
|
|
43
|
+
|
|
44
|
+
- Size: Use 1200x630 pixels (1.91:1 ratio) for maximum compatibility
|
|
45
|
+
- Add dimensions for faster first-share rendering:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
updateHeadTag({ property: "og:image:width", content: "1200" });
|
|
49
|
+
updateHeadTag({ property: "og:image:height", content: "630" });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Branding
|
|
53
|
+
|
|
54
|
+
For site-wide branding, add `og:site_name`:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
updateHeadTag({ property: "og:site_name", content: "Your Brand" });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Platform-Specific Enhancements
|
|
61
|
+
|
|
62
|
+
- Apple/iMessage: Set `touchIconUrl` prop for iMessage link previews
|
|
63
|
+
- Video content:
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
updateHeadTag({
|
|
67
|
+
property: "og:video",
|
|
68
|
+
content: "https://example.com/video.mp4",
|
|
69
|
+
});
|
|
70
|
+
updateHeadTag({ property: "og:video:type", content: "video/mp4" });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Testing Previews
|
|
74
|
+
|
|
75
|
+
Test how your links appear with platform-specific tools (platforms cache aggressively — use these to force a refresh):
|
|
76
|
+
|
|
77
|
+
- [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/)
|
|
78
|
+
- [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/)
|
|
79
|
+
- [Twitter Card Validator](https://cards-dev.twitter.com/validator)
|
|
80
|
+
|
|
81
|
+
### Twitter Cards
|
|
82
|
+
|
|
83
|
+
Routerino automatically includes `summary_large_image` for maximum engagement:
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Meta Descriptions
|
|
90
|
+
|
|
91
|
+
- Provide unique, informative descriptions for each route.
|
|
92
|
+
- Keep them under ~150 characters to avoid truncation in search results.
|
|
93
|
+
|
|
94
|
+
## Structured Data (JSON-LD)
|
|
95
|
+
|
|
96
|
+
Use the `innerHTML` property on a `<script type="application/ld+json">` head tag:
|
|
97
|
+
|
|
98
|
+
```jsx
|
|
99
|
+
{
|
|
100
|
+
path: "/about/",
|
|
101
|
+
element: <AboutPage />,
|
|
102
|
+
tags: [{
|
|
103
|
+
tag: "script",
|
|
104
|
+
type: "application/ld+json",
|
|
105
|
+
innerHTML: JSON.stringify({
|
|
106
|
+
"@context": "https://schema.org",
|
|
107
|
+
"@type": "BreadcrumbList",
|
|
108
|
+
itemListElement: [
|
|
109
|
+
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
|
|
110
|
+
{ "@type": "ListItem", "position": 2, "name": "About", "item": "https://example.com/about/" },
|
|
111
|
+
],
|
|
112
|
+
}),
|
|
113
|
+
}],
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This works both at runtime (via `updateHeadTag`) and during SSG (via the forge plugin).
|
|
118
|
+
|
|
119
|
+
## Hash Links
|
|
120
|
+
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
**Sticky headers:** Use [`scroll-margin-top`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top) to offset the scroll target:
|
|
124
|
+
|
|
125
|
+
```css
|
|
126
|
+
[id] {
|
|
127
|
+
scroll-margin-top: 80px; /* match your header height */
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This works for SPA navigation, native browser hash navigation, and direct page loads.
|
|
132
|
+
|
|
133
|
+
## Additional SEO Considerations
|
|
134
|
+
|
|
135
|
+
- Use semantic HTML elements in your components for better content structure.
|
|
136
|
+
- Implement structured data (JSON-LD) where applicable to enhance rich snippets.
|
|
137
|
+
- Ensure your site is mobile-friendly and loads quickly.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Vendoring Routerino
|
|
2
|
+
|
|
3
|
+
If you prefer to include Routerino directly in your project instead of using it as a dependency, you can vendor the library. This gives you full control over the version and eliminates managing it as an external dependency.
|
|
4
|
+
|
|
5
|
+
1. Download `routerino.jsx` from the [repository](../routerino.jsx).
|
|
6
|
+
|
|
7
|
+
2. Place it in a suitable location within your project:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
your-project/
|
|
11
|
+
├── src/
|
|
12
|
+
│ ├── vendor/
|
|
13
|
+
│ │ └── routerino.jsx
|
|
14
|
+
│ └── ...
|
|
15
|
+
└── ...
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
3. Update your imports:
|
|
19
|
+
|
|
20
|
+
```jsx
|
|
21
|
+
// Before (importing from the package)
|
|
22
|
+
import Routerino from "routerino";
|
|
23
|
+
|
|
24
|
+
// After (importing from the vendored file)
|
|
25
|
+
import Routerino from "./vendor/routerino";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
4. If using the Routerino Forge plugin for SSG and sitemap generation, copy `routerino-forge.js` as well.
|
|
29
|
+
|
|
30
|
+
**Note:** When vendoring, you'll need to manually update the vendored files to incorporate future updates or bug fixes from the main repository.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "routerino",
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.6.2",
|
|
4
|
+
"description": "The React router that Google can read. Built-in SSG, meta tags, sitemaps, and canonical URLs — zero dependencies, no framework lock-in.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/nerds-with-keyboards/routerino.git"
|
|
@@ -11,7 +11,17 @@
|
|
|
11
11
|
"react",
|
|
12
12
|
"seo",
|
|
13
13
|
"prerender",
|
|
14
|
-
"
|
|
14
|
+
"ssg",
|
|
15
|
+
"static-site",
|
|
16
|
+
"static-site-generator",
|
|
17
|
+
"vite",
|
|
18
|
+
"vite-plugin",
|
|
19
|
+
"meta-tags",
|
|
20
|
+
"open-graph",
|
|
21
|
+
"sitemap",
|
|
22
|
+
"seo-friendly",
|
|
23
|
+
"jamstack",
|
|
24
|
+
"zero-dependency"
|
|
15
25
|
],
|
|
16
26
|
"license": "MIT",
|
|
17
27
|
"bugs": {
|