@emkodev/emroute 1.12.5 → 1.12.6

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.
Files changed (2) hide show
  1. package/README.md +21 -124
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -3,15 +3,19 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- File-based (but storage-agnostic) router with triple rendering. Zero dependencies.
6
+ File-based, storage-agnostic router with triple rendering. Zero dependencies.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://emroute.emko.dev"><strong>emroute.emko.dev →</strong></a>
7
11
  </p>
8
12
 
9
13
  ---
10
14
 
11
- Every route renders three ways from the same component: as a **Single Page App**
12
- in the browser, as **server-rendered HTML**, and as **plain Markdown**. No
13
- separate API layer needed — prefix any route with `/md/` and get text that LLMs,
14
- scripts, and `curl` can consume directly.
15
+ Every route renders three ways from the same component: a **Single Page App**
16
+ in the browser, **server-rendered HTML**, and **plain Markdown**. No separate
17
+ API layer — prefix any route with `/md/` and get text that LLMs, scripts, and
18
+ `curl` can consume directly.
15
19
 
16
20
  ```
17
21
  GET /projects/42 → SPA (hydrated in browser)
@@ -25,136 +29,29 @@ GET /md/projects/42 → plain Markdown
25
29
  npm add @emkodev/emroute # or bun add, pnpm add, yarn add
26
30
  ```
27
31
 
28
- Works on **Node**, **Bun**, and **Deno**. Node uses compiled JS; Bun and Deno
29
- use TypeScript source directly.
30
-
31
- For markdown rendering, add [@emkodev/emkoma](doc/08c-setup-emkoma.md) (built
32
- for emroute) or bring your own — [marked](doc/08a-setup-marked.md) and
33
- [markdown-it](doc/08b-setup-markdown-it.md) both work.
34
-
35
- ## How It Works
36
-
37
- <p align="center">
38
- <img src="https://raw.githubusercontent.com/emko-io/emroute/main/doc/diagram-full.png" alt="emroute architecture" width="480" height="480">
39
- </p>
40
-
41
- One component, three rendering paths:
42
-
43
- <p align="center">
44
- <img src="https://raw.githubusercontent.com/emko-io/emroute/main/doc/diagram-flow-spa.png" alt="SPA flow" width="320" height="320">
45
- <img src="https://raw.githubusercontent.com/emko-io/emroute/main/doc/diagram-flow-ssr-html.png" alt="SSR HTML flow" width="320" height="320">
46
- <img src="https://raw.githubusercontent.com/emko-io/emroute/main/doc/diagram-flow-ssr-md.png" alt="SSR Markdown flow" width="320" height="320">
47
- </p>
32
+ Works on **Node**, **Bun**, and **Deno**.
48
33
 
49
- The SPA and SSR HTML flows both call `renderHTML()` — same output, different
50
- delivery. The SSR Markdown flow calls `renderMarkdown()` instead, bypassing
51
- HTML entirely for plain text output.
34
+ ## Quick taste
52
35
 
53
36
  Routes are files. The filesystem is the config.
54
37
 
55
38
  ```
56
39
  routes/
57
40
  index.page.md → /
58
- about.page.html → /about
59
41
  projects.page.md → /projects
60
- projects/
61
- [id].page.ts → /projects/:id
62
- [id]/
63
- tasks.page.ts → /projects/:id/tasks
64
- 404.page.html → not found
65
- index.error.ts → root error handler
42
+ projects/[id].page.ts → /projects/:id
66
43
  ```
67
44
 
68
- A route can be a `.md` file, an `.html` template, a `.ts` component, or a
69
- combination. When a `.page.ts` exists, it controls data fetching and rendering.
70
- When it doesn't, the framework renders the `.html` or `.md` file directly.
71
-
72
- ```ts
73
- import { PageComponent } from '@emkodev/emroute';
74
-
75
- class ProjectPage extends PageComponent<{ id: string }, ProjectData> {
76
- override readonly name = 'project';
77
-
78
- override async getData({ params }: this['DataArgs']) {
79
- const res = await fetch(`/api/projects/${params.id}`);
80
- return res.json();
81
- }
45
+ A route can be a `.md` file, an `.html` template, a `.ts` component, or any
46
+ combination. When a `.page.ts` exists, it controls data fetching and
47
+ rendering. When it doesn't, the framework renders the companion file
48
+ directly.
82
49
 
83
- override renderHTML({ data, params, context }: this['RenderArgs']) {
84
- // context.files.html has the companion .page.html template if it exists
85
- const template = context.files?.html ?? `<h1>${data.name}</h1>`;
86
- return template.replaceAll('{{id}}', params.id) + '<router-slot></router-slot>';
87
- }
88
-
89
- override renderMarkdown({ data, context }: this['RenderArgs']) {
90
- // context.files.md has the companion .page.md content if it exists
91
- return context.files?.md ?? `# ${data.name}\n\nStatus: ${data.status}`;
92
- }
93
- }
94
-
95
- export default new ProjectPage();
96
- ```
50
+ ## Documentation
97
51
 
98
- ## Features
99
-
100
- - **File-based routing** with dynamic segments (`[id]`), catch-all directories, and nested layouts via `<router-slot>`. Routes follow REST conventions: exact routes are terminal resources, catch-all directories own their namespace
101
- - **Triple rendering** — SPA, SSR HTML, SSR Markdown from one component
102
- - **Companion files** — `.page.html`, `.page.md`, `.page.css` loaded automatically and passed through context
103
- - **Widgets** — interactive islands with their own data lifecycle, error handling, and optional file companions (`.html`, `.md`, `.css`). Auto-discovered from a `widgets/` directory or registered manually. `this.element` gives opt-in DOM access in the browser. `<widget-foo lazy>` defers loading until visible via `IntersectionObserver`
104
- - **View Transitions** — SPA route changes animate via `document.startViewTransition()`. Progressive enhancement with CSS-only customization
105
- - **Scoped CSS** — companion `.widget.css` files auto-wrapped in `@scope (widget-{name}) { ... }`
106
- - **Shadow DOM** — unified Declarative Shadow DOM architecture for SSR and SPA. Widgets render into shadow roots for true CSS encapsulation and Web Components spec compliance
107
- - **SSR hydration** — server-rendered HTML adopted by the SPA without re-rendering. Widgets can implement `hydrate(args)` to attach event listeners after SSR adoption, receiving `{ data, params, context }`
108
- - **Error boundaries** — scoped error handlers per route prefix, plus status pages (`404.page.html`) and a root fallback
109
- - **Extensible context** — inject app-level services (RPC clients, auth, feature flags) into every component via `extendContext` on the router. Type-safe access through module augmentation or a per-component generic
110
- - **Declarative overlays** — popovers, modals, and toasts with zero JS via Invoker Commands API and CSS keyframe animations. Programmatic API available for dynamic content
111
- - **Zero dependencies** — native APIs only (URLPattern, custom elements, Navigation API). No framework runtime, no virtual DOM, no build-time magic
112
- - **Pluggable markdown** — `<mark-down>` custom element with a swappable parser interface; bring your own renderer
113
- - **Redirects** — declarative `.redirect.ts` files with 301/302 support
114
- - **Configurable base paths** — `/html/` and `/md/` prefixes are configurable via `BasePath`
115
- - **SPA modes** — `'root'` (default), `'leaf'`, `'none'`, or `'only'` to control how the server handles non-file requests and SSR endpoints
116
- - **Sitemap generation** — opt-in `sitemap.xml` from the routes manifest with support for dynamic route enumerators
117
- - **On-the-fly transpilation** — `BunFsRuntime` serves `.ts` files as transpiled JavaScript with companion files inlined. No build step required for development. `buildClientBundles()` is an optional production optimization
118
-
119
- ## Runtimes
120
-
121
- The router is storage-agnostic — it reads routes through a `Runtime` abstraction,
122
- not the filesystem directly. emroute ships four runtimes:
123
-
124
- - **`BunFsRuntime`** — Bun-native APIs (`Bun.file()`, `Bun.write()`,
125
- `Bun.Transpiler`). The default choice for Bun projects.
126
- - **`UniversalFsRuntime`** — `node:` APIs only. Works on Node, Deno, and Bun.
127
- - **`BunSqliteRuntime`** — stores routes in a SQLite database. Proves the
128
- storage-agnostic design: no filesystem needed.
129
- - **`FetchRuntime`** — browser runtime that fetches files from a remote server.
130
- Powers the SPA in `root` and `only` modes.
131
-
132
- Bun runs TypeScript source directly. Node and Deno use the compiled JS from
133
- `dist/`. See [ADR-0017](doc/architecture/ADR-0017-move-to-bun-ecosystem.md) for
134
- the full analysis.
135
-
136
- ## Getting Started
137
-
138
- Pick your runtime: [Bun](doc/01a-setup-bun.md) | [Node](doc/01b-setup-node.md) | [Deno](doc/01c-setup-deno.md)
52
+ Everything else — setup, routing, widgets, SSR, hydration, the runtime
53
+ abstraction, design decisions — lives at **[emroute.emko.dev](https://emroute.emko.dev)**.
139
54
 
140
- ## Documentation
55
+ ## License
141
56
 
142
- - Setup — [Bun](doc/01a-setup-bun.md), [Node](doc/01b-setup-node.md), [Deno](doc/01c-setup-deno.md)
143
- - [First route](doc/02-first-route.md) — route files and rendering modes
144
- - [Pages](doc/03-pages.md) — page components, companion files, data fetching
145
- - [Routing](doc/04-routing.md) — dynamic segments, catch-all, redirects
146
- - [Nesting](doc/05-nesting.md) — layouts, slots, passthrough pages, tips and tricks
147
- - [Widgets](doc/06-widgets.md) — interactive islands with data lifecycle
148
- - [Server](doc/07-server.md) — `Emroute.create`, composition, static files
149
- - [Markdown renderers](doc/08-markdown-renderer.md) — pluggable parser interface and setup
150
- - [Runtime](doc/09-runtime.md) — abstract runtime, UniversalFsRuntime, BunFsRuntime, BunSqliteRuntime
151
- - [SPA modes](doc/10-spa-mode.md) — none, leaf, root, only
152
- - [Error handling](doc/11-error-handling.md) — widget errors, boundaries, status pages
153
- - [Shadow DOM](doc/12-shadow-dom.md) — unified architecture, SSR hydration
154
- - [Hono integration](doc/13-hono.md) — using emroute with Hono
155
-
156
- ### For contributors and architects
157
-
158
- - [Architectural decisions](doc/architecture/) — ADR-0001 through ADR-0017
159
-
160
- <img src="https://raw.githubusercontent.com/emko-io/emroute/main/doc/logo-full.png" alt="emroute" width="197" height="40">
57
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emkodev/emroute",
3
- "version": "1.12.5",
3
+ "version": "1.12.6",
4
4
  "description": "File-based (but storage-agnostic) router with triple rendering (SPA, SSR HTML, SSR Markdown). Zero dependencies.",
5
5
  "license": "BSD-3-Clause",
6
6
  "author": "emko.dev",
@@ -137,6 +137,6 @@
137
137
  "test:browser:root": "bun test test/browser/root",
138
138
  "test:browser:only": "bun test test/browser/only",
139
139
  "lint": "eslint .",
140
- "dev": "echo 'Use a custom server.ts — see doc/01-setup.md'"
140
+ "dev": "echo 'Use a custom server.ts — see https://emroute.emko.dev/html/setup'"
141
141
  }
142
142
  }