flamefront 0.1.0-alpha.0 → 0.1.1
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/LICENSE.md +2 -91
- package/README.md +35 -620
- package/package.json +49 -26
- package/src/cli.ts +16 -1
- package/src/entry.ts +49 -0
- package/src/fetch.ts +280 -0
- package/src/fragment-client.ts +127 -87
- package/src/fragment-hydration-client.tsx +81 -0
- package/src/fragment-protocol.ts +3 -3
- package/src/fragment.tsx +656 -0
- package/src/glob.ts +294 -0
- package/src/identifier-prefix.ts +5 -0
- package/src/index.ts +569 -49
- package/src/lifecycle.ts +7 -6
- package/src/octane-client-core.ts +10 -3
- package/src/octane-client.ts +12 -6
- package/src/octane-compiler.d.ts +19 -0
- package/src/octane-default-renderer.tsx +124 -0
- package/src/octane-router-document.ts +19 -2
- package/src/{octane.ts → octane.tsx} +152 -145
- package/src/output.ts +48 -0
- package/src/remix-route-data.ts +28 -20
- package/src/remix-router.ts +10 -4
- package/src/route-data-client.ts +22 -12
- package/src/route-prefetch.ts +19 -12
- package/src/server.ts +122 -24
- package/src/srvx.ts +43 -183
- package/src/typegen.ts +207 -0
- package/src/virtual-remix-routes.d.ts +16 -1
- package/src/vite.ts +364 -27
- package/src/fragment.ts +0 -260
package/README.md
CHANGED
|
@@ -1,643 +1,58 @@
|
|
|
1
1
|
# Flamefront
|
|
2
2
|
|
|
3
|
-
Flamefront
|
|
4
|
-
|
|
5
|
-
The package keeps its TypeScript sources and exposes the `ff` CLI. Node's
|
|
6
|
-
built-in type stripping runs the CLI, while Vite bundles the application.
|
|
3
|
+
Flamefront brings routing, server rendering, and static pages to Octane.
|
|
4
|
+
One route list connects your pages to the server, browser router, and build.
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
hydration, build, or peer dependency contracts before `1.0.0`.
|
|
6
|
+
## Why try it?
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
- **Render each page where it makes sense.** On the server, at build time, or
|
|
9
|
+
in the browser.
|
|
10
|
+
- **React Router-style loaders.** Load data beside your page component and read
|
|
11
|
+
it with `useLoaderData`.
|
|
12
|
+
- **Shared layouts.** Keep navigation and shared UI in place as pages change.
|
|
13
|
+
- **Persistent shell state.** Keep players running, uploads progressing, and
|
|
14
|
+
other shared UI state intact between pages without making the whole app
|
|
15
|
+
client-rendered.
|
|
16
|
+
- **Control interactivity.** Activate a page immediately, when it becomes
|
|
17
|
+
visible, or when someone interacts with it.
|
|
18
|
+
- **Markdown routes.** Use Markdown and MDX files as pages.
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
Flamefront with the matching Octane packages and Vite version:
|
|
15
|
-
|
|
16
|
-
```sh
|
|
17
|
-
pnpm add \
|
|
18
|
-
flamefront@0.1.0-alpha.0 \
|
|
19
|
-
@octanejs/remix-router@0.1.36 \
|
|
20
|
-
@octanejs/vite-plugin@0.1.40 \
|
|
21
|
-
octane@0.1.40 \
|
|
22
|
-
vite@8.2.2
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
`@octanejs/remix-router` is an optional peer of Flamefront, but the
|
|
26
|
-
quickstart uses it for `Outlet`, `Link`, and loader data. The
|
|
27
|
-
`@octanejs/vite-plugin` package compiles TSRX and must be installed alongside
|
|
28
|
-
the Flamefront Vite plugin.
|
|
29
|
-
|
|
30
|
-
The app must use ESM and keep its route manifest at `src/app.ts`. The
|
|
31
|
-
server entry and browser entry can be placed elsewhere, but the commands
|
|
32
|
-
below assume the conventional paths shown here.
|
|
33
|
-
|
|
34
|
-
## Supported versions
|
|
35
|
-
|
|
36
|
-
| Package or runtime | Supported version | Notes |
|
|
37
|
-
| ------------------------ | ----------------- | ----------------------------------------------------------------------- |
|
|
38
|
-
| Node.js | `>=22.22.2` | CI runs Node 22.22.2, 24.x, and 26.x. |
|
|
39
|
-
| Vite | `^8.0.16` | The repository and consumer check currently use Vite 8.2.2. |
|
|
40
|
-
| Octane | `0.1.40` | Flamefront declares this as an exact peer. |
|
|
41
|
-
| `@octanejs/vite-plugin` | `0.1.40` | Use the matching TSRX compiler plugin. |
|
|
42
|
-
| `@octanejs/remix-router` | `0.1.36` | Optional to Flamefront, required by the router and quickstart examples. |
|
|
43
|
-
|
|
44
|
-
The release checks use pnpm 11.21.0. Other package managers may work, but
|
|
45
|
-
they are not part of this alpha's verification contract.
|
|
46
|
-
|
|
47
|
-
## Migration guide
|
|
48
|
-
|
|
49
|
-
The [brownfield migration guide](./docs/brownfield-migration.md) covers a
|
|
50
|
-
full application cutover from an existing routing and rendering stack. It
|
|
51
|
-
maps the framework-owned boundaries to Flamefront while preserving application
|
|
52
|
-
code where possible.
|
|
53
|
-
|
|
54
|
-
## Minimal app quickstart
|
|
55
|
-
|
|
56
|
-
Create this small project after installing the packages above:
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
.
|
|
60
|
-
├── index.html
|
|
61
|
-
├── vite.config.ts
|
|
62
|
-
└── src
|
|
63
|
-
├── AboutPage.tsrx
|
|
64
|
-
├── AppShell.tsrx
|
|
65
|
-
├── HomePage.tsrx
|
|
66
|
-
├── app.ts
|
|
67
|
-
├── entry-server.ts
|
|
68
|
-
└── main.ts
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Set `"type": "module"` in the app's `package.json`, then add the Vite
|
|
72
|
-
configuration:
|
|
73
|
-
|
|
74
|
-
```ts
|
|
75
|
-
// vite.config.ts
|
|
76
|
-
import { defineConfig } from "vite"
|
|
77
|
-
import { octane } from "@octanejs/vite-plugin"
|
|
78
|
-
import { flamefront } from "flamefront/vite"
|
|
79
|
-
|
|
80
|
-
export default defineConfig({
|
|
81
|
-
plugins: [flamefront(), octane()],
|
|
82
|
-
})
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
The route manifest declares the persistent shell and two routes. The home
|
|
86
|
-
route renders on the server and has a loader. The about route is pre-rendered
|
|
87
|
-
as a static route:
|
|
88
|
-
|
|
89
|
-
```ts
|
|
90
|
-
// src/app.ts
|
|
91
|
-
import { defineApp, route } from "flamefront"
|
|
92
|
-
|
|
93
|
-
export const app = defineApp({
|
|
94
|
-
shell: "/src/AppShell.tsrx",
|
|
95
|
-
routes: [
|
|
96
|
-
route("/", "/src/HomePage.tsrx", { render: "server" }),
|
|
97
|
-
route("/about", "/src/AboutPage.tsrx", { render: "static" }),
|
|
98
|
-
],
|
|
99
|
-
})
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
// src/AppShell.tsrx
|
|
104
|
-
import { Outlet } from "@octanejs/remix-router"
|
|
105
|
-
|
|
106
|
-
export default function AppShell() @{
|
|
107
|
-
<div>
|
|
108
|
-
<Outlet />
|
|
109
|
-
</div>
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```tsx
|
|
114
|
-
// src/HomePage.tsrx
|
|
115
|
-
import { useLoaderData } from "@octanejs/remix-router"
|
|
116
|
-
import type { LoaderArgs } from "flamefront/server"
|
|
117
|
-
|
|
118
|
-
export async function loader({ request }: LoaderArgs) {
|
|
119
|
-
return { pathname: new URL(request.url).pathname }
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export default function HomePage() @{
|
|
123
|
-
const data = useLoaderData<{ pathname: string }>()
|
|
124
|
-
|
|
125
|
-
<main>
|
|
126
|
-
Flamefront loader: {data.pathname}
|
|
127
|
-
</main>
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
```tsx
|
|
132
|
-
// src/AboutPage.tsrx
|
|
133
|
-
export default function AboutPage() @{
|
|
134
|
-
<main>About this app</main>
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
The server entry connects the generated route importer, route runtime, Octane
|
|
139
|
-
document service, and srvx transport. It must default-export the composed
|
|
140
|
-
entry:
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
// src/entry-server.ts
|
|
144
|
-
import { importRoute } from "virtual:flamefront/server-routes"
|
|
145
|
-
import { createOctaneDocuments } from "flamefront/octane"
|
|
146
|
-
import { createRouteRuntime } from "flamefront/server"
|
|
147
|
-
import { createSrvxServerEntry } from "flamefront/srvx"
|
|
148
|
-
import { app } from "./app.ts"
|
|
149
|
-
|
|
150
|
-
const runtime = createRouteRuntime({ app, importRoute })
|
|
151
|
-
const documents = createOctaneDocuments({ app, runtime })
|
|
152
|
-
|
|
153
|
-
export default createSrvxServerEntry({
|
|
154
|
-
app,
|
|
155
|
-
documents,
|
|
156
|
-
assets: {
|
|
157
|
-
clientDirectory: new URL("../client/", import.meta.url),
|
|
158
|
-
},
|
|
159
|
-
})
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
The browser entry starts the generated Octane router and adopts the server
|
|
163
|
-
hydration payload:
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
// src/main.ts
|
|
167
|
-
import { startOctaneClient } from "flamefront/octane/client"
|
|
168
|
-
import { app } from "./app.ts"
|
|
169
|
-
|
|
170
|
-
await startOctaneClient({ app })
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
The HTML template only needs a module entry for the browser:
|
|
174
|
-
|
|
175
|
-
```html
|
|
176
|
-
<!-- index.html -->
|
|
177
|
-
<!doctype html>
|
|
178
|
-
<html lang="en">
|
|
179
|
-
<head>
|
|
180
|
-
<meta charset="UTF-8" />
|
|
181
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
182
|
-
<title>Flamefront app</title>
|
|
183
|
-
</head>
|
|
184
|
-
<body>
|
|
185
|
-
<div id="root"></div>
|
|
186
|
-
<script type="module" src="/src/main.ts"></script>
|
|
187
|
-
</body>
|
|
188
|
-
</html>
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Run the app and inspect its graph:
|
|
192
|
-
|
|
193
|
-
```sh
|
|
194
|
-
pnpm exec ff dev --port 3000
|
|
195
|
-
pnpm exec ff routes
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
The CLI reads `src/app.ts` from the current working directory. The
|
|
199
|
-
development server uses the `--port` value, then `PORT`, and otherwise
|
|
200
|
-
defaults to 5173. Build and serve the production output with:
|
|
201
|
-
|
|
202
|
-
```sh
|
|
203
|
-
pnpm exec ff build
|
|
204
|
-
PORT=4173 pnpm exec ff preview
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
`ff routes --json` prints the normalized route collection. A route loader
|
|
208
|
-
receives a standard `Request` and decoded `params`; the result is available
|
|
209
|
-
through the matching Remix Router loader-data hook.
|
|
210
|
-
|
|
211
|
-
## Deployment shape
|
|
212
|
-
|
|
213
|
-
`ff build` produces one application artifact under `dist`:
|
|
214
|
-
|
|
215
|
-
- `dist/client` contains browser assets, the application template, and
|
|
216
|
-
pre-rendered static route files.
|
|
217
|
-
- `dist/client/<route>/index.data.json` contains build-time route data for
|
|
218
|
-
each static route.
|
|
219
|
-
- `dist/client/<route>/index.fragment.html` and
|
|
220
|
-
`index.fragment.json` contain the static navigation artifacts.
|
|
221
|
-
- `dist/server/server.js` default-exports the srvx-compatible
|
|
222
|
-
`FlamefrontServerEntry`.
|
|
223
|
-
- `dist/server/index.html` is the server template copied from the client
|
|
224
|
-
build.
|
|
225
|
-
|
|
226
|
-
For a Node deployment, build in the build stage and run the packaged CLI in
|
|
227
|
-
the runtime stage:
|
|
228
|
-
|
|
229
|
-
```sh
|
|
230
|
-
pnpm exec ff build
|
|
231
|
-
PORT=3000 pnpm exec ff preview
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Keep `dist/client` and `dist/server` together. The preview process serves
|
|
235
|
-
browser assets and static fragments, renders server and client routes through
|
|
236
|
-
the built entry, and handles the route-data endpoint. A custom Node host can
|
|
237
|
-
load the default export from `dist/server/server.js` and pass it to srvx;
|
|
238
|
-
the host must preserve the entry's middleware and lifecycle fields.
|
|
239
|
-
|
|
240
|
-
An app with only concrete `static` routes can serve `dist/client` from a
|
|
241
|
-
static host after the build. Server and client routes, live loaders, redirects,
|
|
242
|
-
and server-rendered error responses need the Node handler.
|
|
243
|
-
|
|
244
|
-
## Common failure guidance
|
|
245
|
-
|
|
246
|
-
| Symptom | Fix |
|
|
247
|
-
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
248
|
-
| `Could not find .../src/app.ts` | Run `ff` from the app root and export `app` from `src/app.ts`. |
|
|
249
|
-
| The server entry validation fails | Default-export the value returned by `createSrvxServerEntry`; named exports are not consumed by `ff`. |
|
|
250
|
-
| `virtual:flamefront/server-routes` cannot resolve | Add `flamefront()` and `octane()` to the app's Vite plugins, in that order, and keep the import in the server entry. |
|
|
251
|
-
| `ff preview` cannot find `dist/server/server.js` | Run `ff build` first and start preview from the same app root. |
|
|
252
|
-
| A static link performs a full document load or returns 404 | Serve the complete `dist/client` tree, including the `.fragment.html` and `.fragment.json` files generated by `ff build`. |
|
|
253
|
-
| Hydration fails at startup | Keep one `#root` element in the HTML template and let `startOctaneClient` use the same router document as the server. |
|
|
254
|
-
| A dependency resolution error mentions a peer version | Install the versions in the support matrix. Do not mix the alpha with a different Octane or Remix Router minor. |
|
|
255
|
-
|
|
256
|
-
## Known limitations
|
|
257
|
-
|
|
258
|
-
- This is an alpha. Pin exact package versions and expect breaking changes
|
|
259
|
-
before `1.0.0`. There is no alpha-to-public compatibility promise yet.
|
|
260
|
-
- Flamefront exports raw TypeScript files. The CLI depends on Node's built-in
|
|
261
|
-
type stripping, and consumers need a toolchain that can resolve TypeScript
|
|
262
|
-
package exports.
|
|
263
|
-
- The CLI expects `src/app.ts` and `src/entry-server.ts` at the project
|
|
264
|
-
paths described above. Custom project layouts need an app-owned wrapper or a
|
|
265
|
-
future lifecycle extension.
|
|
266
|
-
- Static pre-rendering accepts concrete paths only. A static route containing
|
|
267
|
-
`:` or `*` cannot be generated without adding concrete route entries.
|
|
268
|
-
- Route modules have a default component export and may export a `loader`.
|
|
269
|
-
Flamefront does not currently define an action or mutation API.
|
|
270
|
-
- Flamefront removes `loader` and its server-only dependency graph from
|
|
271
|
-
client route modules. A `.server` module that remains reachable from
|
|
272
|
-
client code is a build error.
|
|
273
|
-
- A custom document composer may move or wrap the framework-provided hydration
|
|
274
|
-
script, but it must keep the script, payload, serialization, and identifier
|
|
275
|
-
intact.
|
|
276
|
-
- Client source maps omit embedded `sourcesContent` for mixed route sources
|
|
277
|
-
so removed server implementations are not republished in browser maps.
|
|
278
|
-
- Node is required for server and client routes. A static host is suitable
|
|
279
|
-
only for an app whose deployed behavior is fully covered by the generated
|
|
280
|
-
static output.
|
|
281
|
-
|
|
282
|
-
## License terms
|
|
283
|
-
|
|
284
|
-
Flamefront remains licensed under the Functional Source License, Version 1.1,
|
|
285
|
-
MIT Future License (`FSL-1.1-MIT`). The complete terms are in
|
|
286
|
-
[LICENSE.md](./LICENSE.md), and they control if this summary differs from the
|
|
287
|
-
license.
|
|
288
|
-
|
|
289
|
-
The current FSL grant permits use, copying, modification, derivative works,
|
|
290
|
-
public performance, public display, and redistribution for any Permitted
|
|
291
|
-
Purpose. A Competing Use is excluded. The license specifically lists internal
|
|
292
|
-
use and access, non-commercial education, non-commercial research, and
|
|
293
|
-
professional services provided to a licensee as Permitted Purposes.
|
|
294
|
-
|
|
295
|
-
Redistributions must include the license terms or a link to them and retain
|
|
296
|
-
the copyright notices. The software is provided without warranties or
|
|
297
|
-
liability. The license does not grant rights to use Flamefront trademarks,
|
|
298
|
-
trade names, service marks, or product names beyond identifying the software's
|
|
299
|
-
origin.
|
|
300
|
-
|
|
301
|
-
The license includes an irrevocable MIT grant that becomes effective on the
|
|
302
|
-
second anniversary of the date the software is made available. The current
|
|
303
|
-
`FSL-1.1-MIT` terms and the future MIT grant are part of the release
|
|
304
|
-
contract; this documentation does not change either one.
|
|
305
|
-
|
|
306
|
-
## Route manifest
|
|
307
|
-
|
|
308
|
-
The app owns one explicit, centralized route manifest:
|
|
20
|
+
## One route list
|
|
309
21
|
|
|
310
22
|
```ts
|
|
311
|
-
import { defineApp,
|
|
23
|
+
import { clientRoute, defineApp, serverRoute, staticRoute } from "flamefront"
|
|
312
24
|
|
|
313
25
|
export const app = defineApp({
|
|
314
26
|
shell: "/src/AppShell.tsrx",
|
|
315
27
|
routes: [
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
28
|
+
serverRoute("/", "/src/HomePage.tsrx"),
|
|
29
|
+
staticRoute("/docs", "/src/DocsPage.tsrx"),
|
|
30
|
+
clientRoute("/settings", "/src/SettingsPage.tsrx"),
|
|
319
31
|
],
|
|
320
32
|
})
|
|
321
33
|
```
|
|
322
34
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
is the normalized leaf collection used for matching, filtering, static output,
|
|
326
|
-
and CLI inspection.
|
|
327
|
-
|
|
328
|
-
The manifest contains route behavior only. App-specific display data, such as
|
|
329
|
-
navigation labels, remains in app code.
|
|
330
|
-
|
|
331
|
-
Use `app.match(url)` to select the most specific route and read decoded
|
|
332
|
-
parameters. Pass `{ render: "client" }` to select only routes with a
|
|
333
|
-
particular render mode. Flamefront delegates route grammar and specificity to
|
|
334
|
-
`@remix-run/route-pattern` rather than maintaining its own matcher.
|
|
335
|
-
|
|
336
|
-
`ff build` emits client assets and a srvx-compatible
|
|
337
|
-
`dist/server/server.js`, then pre-renders every static route. The server
|
|
338
|
-
build default-exports one `FlamefrontServerEntry`: srvx server options plus
|
|
339
|
-
the mode-aware document and route-data operations used by the lifecycle.
|
|
340
|
-
`ff dev`, `ff build`, and `ff preview` consume that default object
|
|
341
|
-
directly; named server exports are not part of the contract.
|
|
342
|
-
|
|
343
|
-
## Composable server entry
|
|
344
|
-
|
|
345
|
-
The app's `src/entry-server.ts` is a composition root. It supplies the
|
|
346
|
-
generated server route importer, then connects the route runtime, Octane
|
|
347
|
-
document service, and srvx transport:
|
|
348
|
-
|
|
349
|
-
```ts
|
|
350
|
-
import { importRoute } from "virtual:flamefront/server-routes"
|
|
351
|
-
import { createOctaneDocuments } from "flamefront/octane"
|
|
352
|
-
import { createRouteRuntime } from "flamefront/server"
|
|
353
|
-
import { createSrvxServerEntry } from "flamefront/srvx"
|
|
354
|
-
import { app } from "./app.ts"
|
|
355
|
-
|
|
356
|
-
const runtime = createRouteRuntime({ app, importRoute })
|
|
357
|
-
const documents = createOctaneDocuments({ app, runtime })
|
|
358
|
-
|
|
359
|
-
export default createSrvxServerEntry({
|
|
360
|
-
app,
|
|
361
|
-
documents,
|
|
362
|
-
assets: {
|
|
363
|
-
clientDirectory: new URL("../client/", import.meta.url),
|
|
364
|
-
},
|
|
365
|
-
})
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
The three layers have separate ownership:
|
|
369
|
-
|
|
370
|
-
- `createRouteRuntime({ app, importRoute, requestContext? })` owns route
|
|
371
|
-
matching, route-module loading, loader execution, and the request-data
|
|
372
|
-
response. `requestContext` receives the request, matched route and params,
|
|
373
|
-
the purpose (`data` or `document`), and the document mode when applicable.
|
|
374
|
-
For a document request, the resulting context is passed to the server
|
|
375
|
-
router and its route loaders.
|
|
376
|
-
- `createOctaneDocuments({ app, runtime, routerDocument?, composeDocument? })`
|
|
377
|
-
owns shell versus full route rendering, the Remix static-router branch,
|
|
378
|
-
Octane rendering, and static route-data extraction. Its generated default is
|
|
379
|
-
shared with `startOctaneClient`. `routerDocument` can replace it with a
|
|
380
|
-
shared application provider component. `composeDocument` receives the
|
|
381
|
-
template, rendered body, CSS, framework hydration script, and request/mode
|
|
382
|
-
metadata so the app can control HTML placement or add markup.
|
|
383
|
-
- `createSrvxServerEntry({ app, documents, assets, middleware?, headers? })`
|
|
384
|
-
owns the srvx `fetch` handler, static asset middleware, template lookup,
|
|
385
|
-
route-data dispatch, render-mode dispatch, and default response headers.
|
|
386
|
-
The required `assets.clientDirectory` locates client files. Application
|
|
387
|
-
middleware runs in declaration order around the framework transport, and
|
|
388
|
-
`headers` can merge application policy with the default and document
|
|
389
|
-
headers.
|
|
390
|
-
|
|
391
|
-
The app owns the route importer and request-scoped services such as
|
|
392
|
-
authentication or database handles, router providers and document composition,
|
|
393
|
-
template and asset locations, middleware and response headers, and shared
|
|
394
|
-
routing paths. Flamefront owns render-mode branching, loader and router
|
|
395
|
-
semantics, the srvx adapter, and default redirect and asset behavior.
|
|
396
|
-
|
|
397
|
-
Configure shared paths on the app definition so matching, generated browser
|
|
398
|
-
routes, the server router, the data endpoint, and srvx use the same values:
|
|
399
|
-
|
|
400
|
-
```ts
|
|
401
|
-
import { defineApp, route } from "flamefront"
|
|
402
|
-
|
|
403
|
-
export const app = defineApp({
|
|
404
|
-
shell: "/src/AppShell.tsrx",
|
|
405
|
-
routing: {
|
|
406
|
-
basename: "/docs",
|
|
407
|
-
dataPath: "/docs/__flamefront/data",
|
|
408
|
-
},
|
|
409
|
-
routes: [route("/", "/src/HomePage.tsrx", { render: "server" })],
|
|
410
|
-
})
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Hydration and data protocols remain framework-owned. The document composer may
|
|
414
|
-
place or surround the supplied hydration script, but it cannot replace its
|
|
415
|
-
payload, serialization, or identifier. Likewise, the route-data JSON response,
|
|
416
|
-
static `.data.json` artifacts, and their browser loading behavior are not
|
|
417
|
-
application codecs.
|
|
418
|
-
|
|
419
|
-
## Octane browser entry
|
|
420
|
-
|
|
421
|
-
Use the matching client adapter instead of assembling the browser router and
|
|
422
|
-
root component separately:
|
|
423
|
-
|
|
424
|
-
```ts
|
|
425
|
-
import { startOctaneClient } from "flamefront/octane/client"
|
|
426
|
-
import { app } from "./app.ts"
|
|
427
|
-
|
|
428
|
-
await startOctaneClient({ app })
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
`startOctaneClient` mounts client-rendered routes and hydrates server or
|
|
432
|
-
static routes after the browser router initializes. By default, it and
|
|
433
|
-
`createOctaneDocuments` use the same `RouterDocument` exported by the
|
|
434
|
-
generated Remix route module. This shared root is the `RouterProvider` itself,
|
|
435
|
-
so Octane can adopt the server tree instead of recovering from a different
|
|
436
|
-
client root.
|
|
437
|
-
|
|
438
|
-
Applications that wrap the router in providers can pass `routerDocument`.
|
|
439
|
-
Export that component from one shared module and pass the same import to
|
|
440
|
-
`createOctaneDocuments` and `startOctaneClient`.
|
|
441
|
-
|
|
442
|
-
The Vite plugin generates `virtual:flamefront/server-routes`; supplying its
|
|
443
|
-
`importRoute` function keeps bundler-specific route importing at the app
|
|
444
|
-
boundary. It also generates `virtual:flamefront/remix-routes` for the
|
|
445
|
-
Remix Router adapter.
|
|
446
|
-
|
|
447
|
-
## Route loaders
|
|
448
|
-
|
|
449
|
-
A manifest entry is a route module. It may export a server loader alongside
|
|
450
|
-
its default component:
|
|
451
|
-
|
|
452
|
-
```ts
|
|
453
|
-
import type { LoaderArgs } from "flamefront/server"
|
|
454
|
-
|
|
455
|
-
export async function loader({ request, params }: LoaderArgs) {
|
|
456
|
-
return { pathname: new URL(request.url).pathname, id: params.id }
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export default function Route({ loaderData }) {
|
|
460
|
-
// Render with data resolved before the component renders.
|
|
461
|
-
}
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
Server adapters call `loadRoute()` from `flamefront/server`. Browser routers
|
|
465
|
-
can call `app.load(url)` from their route loaders. `app.load(url)` and
|
|
466
|
-
`app.prefetch(url)` share a browser-side `RouteDataClient` with generated
|
|
467
|
-
route loaders, so a prefetched result is reused during client navigation.
|
|
468
|
-
`app.load` remains the explicit data-only API for static `.data.json`
|
|
469
|
-
artifacts. Static route navigation and route-aware prefetching use the
|
|
470
|
-
fragment JSON transport instead, so a navigation never renders a static route
|
|
471
|
-
module from loader data.
|
|
472
|
-
|
|
473
|
-
`prefetchRoute()` chooses resources from the matched route. Client and server
|
|
474
|
-
routes warm live data plus their client route and pathless layout modules:
|
|
475
|
-
|
|
476
|
-
```ts
|
|
477
|
-
import { prefetchRoute } from "flamefront/remix-router"
|
|
478
|
-
|
|
479
|
-
void prefetchRoute(app, "/products/one")
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
Static routes use the fragment transport instead of importing their route
|
|
483
|
-
module as a normal navigation renderer. `createRoutePrefetcher(app)` wires
|
|
484
|
-
the transport into the existing prefetch seam; custom
|
|
485
|
-
`RoutePrefetchResources.staticFragment` callbacks can replace it.
|
|
486
|
-
|
|
487
|
-
Flamefront's Vite transform loads the centralized route manifest. Octane
|
|
488
|
-
compiles TSRX first, then Flamefront removes loaders and their private
|
|
489
|
-
dependency graph from client modules while retaining them in server modules:
|
|
490
|
-
|
|
491
|
-
```ts
|
|
492
|
-
import { octane } from "@octanejs/vite-plugin"
|
|
493
|
-
import { flamefront } from "flamefront/vite"
|
|
494
|
-
|
|
495
|
-
export default {
|
|
496
|
-
plugins: [flamefront(), octane()],
|
|
497
|
-
}
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
Files and directories named `.server` are rejected if they remain reachable
|
|
501
|
-
from client code after loader removal. This turns accidental server imports
|
|
502
|
-
into compile-time errors in development and production.
|
|
503
|
-
|
|
504
|
-
When client source maps are emitted, mixed route sources omit embedded
|
|
505
|
-
`sourcesContent` so removed server implementations are not republished in
|
|
506
|
-
map files. The generated client code remains mapped, but developer tools need
|
|
507
|
-
local source access to display those route sources.
|
|
508
|
-
|
|
509
|
-
## Remix Router adapter
|
|
510
|
-
|
|
511
|
-
Applications that install `@octanejs/remix-router` can opt into Flamefront's
|
|
512
|
-
Remix adapter. Flamefront keeps that package as an optional peer, so core route
|
|
513
|
-
configuration and matching remain router-agnostic.
|
|
514
|
-
|
|
515
|
-
```ts
|
|
516
|
-
import {
|
|
517
|
-
createClientRouter,
|
|
518
|
-
createRoutePrefetcher,
|
|
519
|
-
createServerRouter,
|
|
520
|
-
} from "flamefront/remix-router"
|
|
521
|
-
|
|
522
|
-
const browserRouter = createClientRouter({
|
|
523
|
-
hydrationData,
|
|
524
|
-
prefetch: createRoutePrefetcher(app),
|
|
525
|
-
})
|
|
526
|
-
const serverResult = await createServerRouter(request)
|
|
527
|
-
if (serverResult instanceof Response) return serverResult
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
The server result contains `router`, `context`, and serializable
|
|
531
|
-
`hydrationData`. Redirect responses are returned directly and route errors
|
|
532
|
-
stay in both the static context and hydration state. The exported `routes`
|
|
533
|
-
collection is available when an application needs lower-level Remix Router
|
|
534
|
-
APIs.
|
|
535
|
-
|
|
536
|
-
Pass `createRoutePrefetcher(app)` to the browser router's `prefetch`
|
|
537
|
-
option to connect `Link` and `NavLink` modes such as `prefetch="intent"`.
|
|
538
|
-
Programmatic callers can use the same router cache with
|
|
539
|
-
`router.prefetch(to)`.
|
|
540
|
-
|
|
541
|
-
Generated route objects expose `handle.flamefront` metadata with stable
|
|
542
|
-
`id`, `boundary`, and `parent` values. The adapter also exports the flat
|
|
543
|
-
`routeMetadata` collection. Leaf routes include their `render` mode and
|
|
544
|
-
`navigation` strategy. Static routes use `navigation: "fragment"`; client
|
|
545
|
-
and server routes use `navigation: "router"`. The metadata is also the
|
|
546
|
-
static-fragment contract: the build records the shell, layout, and leaf
|
|
547
|
-
boundary hierarchy in each fragment artifact. Browser navigation inserts the
|
|
548
|
-
leaf HTML first, then applies the route's hydration policy.
|
|
549
|
-
|
|
550
|
-
Route modules and pathless layout modules use default component exports and
|
|
551
|
-
are loaded lazily. Server routers call route modules' exported loaders
|
|
552
|
-
directly; browser routers use Flamefront's route-data endpoint with navigation
|
|
553
|
-
abort signals and HTTP error handling.
|
|
554
|
-
|
|
555
|
-
Server routes can choose who owns hydration:
|
|
556
|
-
|
|
557
|
-
```ts
|
|
558
|
-
route("/reviews/:productId", "/src/Reviews.tsrx", {
|
|
559
|
-
render: "server",
|
|
560
|
-
hydration: { when: "visible", rootMargin: "200px" },
|
|
561
|
-
})
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
- `full` or an omitted value hydrates with the shared shell.
|
|
565
|
-
- `deferred` means the route authors its own Octane `<Hydrate>` boundaries.
|
|
566
|
-
- `none` generates a permanent `never()` boundary around server output.
|
|
567
|
-
- `{ when: "idle" }`, `{ when: "visible" }`,
|
|
568
|
-
`{ when: "interaction" }`, and `{ when: "media" }` generate one
|
|
569
|
-
route-level Octane boundary with the corresponding strategy options.
|
|
570
|
-
|
|
571
|
-
Generated boundaries defer only DOM that came from server rendering. If the
|
|
572
|
-
same route is first mounted by client navigation, Octane renders it
|
|
573
|
-
immediately. Static routes accept `none`, and client routes accept `full`;
|
|
574
|
-
trigger objects are server-only because they need existing server HTML to
|
|
575
|
-
defer.
|
|
576
|
-
|
|
577
|
-
## Alpha release notes
|
|
578
|
-
|
|
579
|
-
### 0.1.0-alpha.0
|
|
580
|
-
|
|
581
|
-
This release is the first external-consumer alpha of the owned `flamefront`
|
|
582
|
-
package. It includes:
|
|
583
|
-
|
|
584
|
-
- the unscoped `flamefront` package and `ff` executable;
|
|
585
|
-
- raw TypeScript exports for the route manifest, Vite integration, server
|
|
586
|
-
runtime, srvx entry, Octane browser entry, and Remix Router adapter;
|
|
587
|
-
- `client`, `server`, and `static` render modes with route layouts,
|
|
588
|
-
loaders, hydration policies, static route data, and static fragments;
|
|
589
|
-
- `ff dev`, `ff build`, `ff preview`, and `ff routes`;
|
|
590
|
-
- packed-package consumer verification across development, build, preview, and
|
|
591
|
-
route-data flows;
|
|
592
|
-
- browser acceptance coverage for hydration, client navigation, static
|
|
593
|
-
fragments, loaders, errors, redirects, basenames, and history traversal.
|
|
594
|
-
|
|
595
|
-
Pin `flamefront@0.1.0-alpha.0` and the matching peer versions while
|
|
596
|
-
evaluating the alpha. Before upgrading, read the release notes, rebuild the
|
|
597
|
-
application, and rerun the full release checks. Alpha releases can change
|
|
598
|
-
public APIs, generated artifacts, or the supported version matrix without a
|
|
599
|
-
migration guarantee.
|
|
600
|
-
|
|
601
|
-
This documentation records the release candidate. Publishing the package and
|
|
602
|
-
making public announcements remain separate, supervisor-controlled actions.
|
|
35
|
+
The shell holds shared UI. Each route pairs a URL with an Octane page component
|
|
36
|
+
and chooses how it renders.
|
|
603
37
|
|
|
604
|
-
##
|
|
38
|
+
## Quickstart
|
|
605
39
|
|
|
606
|
-
|
|
40
|
+
[Try the included app](./docs/getting-started.md): build a static page, inspect
|
|
41
|
+
its generated HTML, and serve it locally. Then [create your own app](./docs/create-app.md).
|
|
607
42
|
|
|
608
|
-
|
|
43
|
+
## Before you try it
|
|
609
44
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
pre-1.0 version, exposes `ff`, and contains only intentional packed files.
|
|
613
|
-
- [ ] Run `pnpm install --frozen-lockfile` with pnpm 11.21.0.
|
|
614
|
-
- [ ] Run the release checks on Node 22.22.2, 24.x, and 26.x.
|
|
615
|
-
- [ ] Confirm `pnpm lint`, `pnpm format:check`, `pnpm typecheck`,
|
|
616
|
-
`pnpm test`, `pnpm build`, `pnpm check:routes`,
|
|
617
|
-
`pnpm check:consumer`, and `pnpm check:browser` all pass.
|
|
618
|
-
- [ ] Confirm `pnpm check` passes as the single aggregate gate.
|
|
619
|
-
- [ ] Inspect the packed tarball and verify that it contains the license,
|
|
620
|
-
README, CLI files, and source exports, with no workspace-only files.
|
|
45
|
+
Flamefront is an early alpha and requires Node.js 26+. Expect changes before
|
|
46
|
+
1.0. Follow the setup guide for matching packages.
|
|
621
47
|
|
|
622
|
-
|
|
48
|
+
There is no built-in form action or mutation API yet. If your current framework
|
|
49
|
+
already covers your needs, there's no need to switch.
|
|
623
50
|
|
|
624
|
-
|
|
625
|
-
registry policy. Do not replace the candidate after verification.
|
|
626
|
-
- [ ] Install that exact published version in a fresh consumer outside the
|
|
627
|
-
workspace. Confirm the resolved package is not a workspace link.
|
|
628
|
-
- [ ] Run the consumer through development, production build, preview, route
|
|
629
|
-
inspection, static navigation, and route-data flows.
|
|
630
|
-
- [ ] Run the browser acceptance path against the published package and verify
|
|
631
|
-
initial hydration, client routes, static fragments, loaders, errors,
|
|
632
|
-
redirects, basenames, and back/forward navigation.
|
|
633
|
-
- [ ] Repeat the supported Node matrix against the published package.
|
|
51
|
+
Licensed under [MIT](./LICENSE.md).
|
|
634
52
|
|
|
635
|
-
|
|
53
|
+
## Learn more
|
|
636
54
|
|
|
637
|
-
- [ ]
|
|
638
|
-
|
|
639
|
-
- [ ]
|
|
640
|
-
|
|
641
|
-
- [ ] Confirm the FSL-1.1-MIT file and its future MIT grant are unchanged.
|
|
642
|
-
- [ ] Obtain release-owner approval for the package publication and any
|
|
643
|
-
announcement.
|
|
55
|
+
- [How Flamefront fits](./docs/index.md)
|
|
56
|
+
- [Route rendering and data](./docs/routes.md)
|
|
57
|
+
- [Build and deployment](./docs/deployment.md)
|
|
58
|
+
- [Migrating an existing app](./docs/brownfield-migration.md)
|