@transclude/core 0.11.1 → 0.11.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transclude/core",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "An HTML-first server framework. A page is an .html file, the directory tree is the route table, and any fragment of a page is a URL of its own. Runs on Node, Bun, Deno and workerd, and ships no client JavaScript by default.",
5
5
  "keywords": [
6
6
  "html",
@@ -57,7 +57,7 @@
57
57
  ],
58
58
  "scripts": {
59
59
  "test": "node --test \"test/**/*.test.js\"",
60
- "test:examples": "npm test --prefix examples/showcase && npm test --prefix examples/todomvc && npm test --prefix examples/blog && npm test --prefix examples/search && npm test --prefix examples/htmx && npm test --prefix examples/includes && npm test --prefix examples/auth && npm test --prefix examples/live && npm test --prefix examples/elements && npm test --prefix examples/markdown",
60
+ "test:examples": "npm test --prefix examples/showcase && npm test --prefix examples/todomvc && npm test --prefix examples/blog && npm test --prefix examples/search && npm test --prefix examples/htmx && npm test --prefix examples/includes && npm test --prefix examples/auth && npm test --prefix examples/live && npm test --prefix examples/elements && npm test --prefix examples/markdown && npm test --prefix examples/atlas",
61
61
  "test:www": "npm test --prefix www",
62
62
  "showcase": "npm run dev --prefix examples/showcase",
63
63
  "todomvc": "npm run dev --prefix examples/todomvc",
@@ -69,6 +69,7 @@
69
69
  "live": "npm run dev --prefix examples/live",
70
70
  "elements": "npm run dev --prefix examples/elements",
71
71
  "markdown": "npm run dev --prefix examples/markdown",
72
+ "atlas": "npm run dev --prefix examples/atlas",
72
73
  "www": "npm run dev --prefix www",
73
74
  "check:src": "tsc -p tsconfig.src.json",
74
75
  "release": "node bin/release.js"
@@ -277,6 +277,14 @@ element name. `card.html` is not, and the file is dropped.
277
277
  **`<transclude>` has no self-closing form.** `<transclude src="#a" />` is read
278
278
  as an open tag and the rest of the page becomes its fallback content.
279
279
 
280
+ **`app.get()` in `app/server.js` is not how a route is made.** The `app` there
281
+ is a real Hono instance and accepts one, but the directory tree is the route
282
+ table, and a handler registered by hand is invisible to the build, the sitemap
283
+ and `npm run check`. Middleware is what belongs in that file. Most of Hono's
284
+ API has an answer here already, and
285
+ [references/server.md](references/server.md) has the line between the two next
286
+ to Hono's own documentation for agents.
287
+
280
288
  **Middleware does not run during the build.** A page gated only by
281
289
  `app/server.js` is prerendered to a file and served by any static host. Declare
282
290
  the paths so the build knows:
@@ -305,6 +313,6 @@ directly. It is the object the whole chain holds.
305
313
  - [references/fragments.md](references/fragments.md) — fragments, includes and
306
314
  transclusion
307
315
  - [references/server.md](references/server.md) — cookies, middleware, security,
308
- config, deployment
316
+ config, caching, deployment, and where Hono's own docs are
309
317
 
310
318
  Full documentation: https://transclude.dev/docs
@@ -16,6 +16,57 @@ export default (app) => {
16
16
  It runs before anything that serves bytes, so a guard there covers prerendered
17
17
  pages and public files.
18
18
 
19
+ ## Hono's documentation
20
+
21
+ Hono publishes its documentation in a form an agent can read. Fetch it rather
22
+ than recall it. The dependency is `hono@^4`, and it moves.
23
+
24
+ | URL | Size | What it holds |
25
+ | --- | --- | --- |
26
+ | `https://hono.dev/llms.txt` | 6 KB | An index. Every page, one line each. |
27
+ | `https://hono.dev/llms-small.txt` | 190 KB | The core: routing, the `Context`, middleware, the helpers. |
28
+ | `https://hono.dev/llms-full.txt` | 360 KB | All of it, a page per built-in middleware. |
29
+
30
+ Read `llms.txt` and follow the one link the question needs. The other two are
31
+ whole manuals, and a question about `cors` does not need one.
32
+
33
+ ### What this framework already answers
34
+
35
+ Most of Hono's surface has an answer here, and reaching past it is the common
36
+ mistake. A route registered by hand answers requests. The build, the sitemap
37
+ and `npm run check` never see it.
38
+
39
+ | In Hono | Here |
40
+ | --- | --- |
41
+ | `app.get('/notes', …)` | `app/routes/notes.html` |
42
+ | `c.req.param('id')` | `params.id` in the loader |
43
+ | `c.req.query('q')` | `new URL(url).searchParams` |
44
+ | `c.req.formData()` | `request.formData()` in a verb export |
45
+ | `getCookie(c, 'theme')` | `ctx.cookies` |
46
+ | `csrf()` | on by default, `csrf` in the config |
47
+ | `secureHeaders()` for a policy | `csp` in the config |
48
+ | `trimTrailingSlash()` | `trailingSlash` in the config |
49
+ | `compress()`, `etag()` | both are built in, per response and at rest |
50
+ | `cache()` | `export const revalidate` |
51
+ | `serveStatic()` | `app/public/` |
52
+ | `c.executionCtx.waitUntil(p)` | `ctx.after(p)` |
53
+ | `c.html()`, `hono/html`, `hono/jsx` | a page is an `.html` file |
54
+ | `hono/ssg` | `npm run build` |
55
+
56
+ Hono's `Context` reaches an app in one place, the middleware in `app/server.js`.
57
+ A loader, an action and an endpoint are handed `ctx`, which belongs to this
58
+ framework and carries no `c`. Reading a form should not cost an author a
59
+ router's API.
60
+
61
+ ### What is still Hono's
62
+
63
+ `app` in `app/server.js` is a real Hono instance, so its built-in middleware
64
+ works unchanged: `cors`, `basicAuth`, `bearerAuth`, `logger`, `bodyLimit`,
65
+ `ipRestriction`, `requestId`, `timeout`, `timing`. So do the helpers `accepts`,
66
+ `conninfo` and `streaming`.
67
+
68
+ `app.request()` in a test is Hono's too. See [Testing](#testing).
69
+
19
70
  ## Cookies
20
71
 
21
72
  `ctx.cookies` reads and writes.
@@ -104,6 +155,7 @@ Source is JavaScript with JSDoc. Do not convert it to TypeScript.
104
155
  | `sitemap` | `false` | `{ hostname }` mounts `/sitemap.xml`. |
105
156
  | `feed` | `false` | `{ hostname, title, items }` mounts a feed. |
106
157
  | `proxy` | `false` | `{ allow: [...] }` for cross-site includes. |
158
+ | `cache` | — | Where a page held by `revalidate` is kept. A bounded map in this process by default. |
107
159
  | `precache` | `false` | `true` writes `/precache.json`. |
108
160
  | `onError` | `null` | `(error, { request, url, method })` per failed request. |
109
161
 
@@ -149,6 +201,81 @@ skipped. Deployed, the URL is a 404. Publishing is deleting the line.
149
201
  `prerender` is read off the page, never off its layouts. A layout that reads a
150
202
  cookie makes every page under it request-dependent, and nothing says so.
151
203
 
204
+ ## Holding a render
205
+
206
+ Between a file written once and a render on every request, there is a page held
207
+ for a while.
208
+
209
+ ```js
210
+ // app/routes/notes.html
211
+ export const prerender = false;
212
+ export const revalidate = 3600;
213
+ ```
214
+
215
+ The number is seconds. Inside that window a request is answered from the store
216
+ and the loader does not run. Past it the held page goes out immediately and a
217
+ fresh one renders behind the response, so nobody waits for a re-render. One
218
+ render happens at a time per URL, however many requests arrive together.
219
+
220
+ The key is the path and the query, because a page reading `?q=` renders
221
+ differently for each one. A rebuild that throws leaves the held page where it is,
222
+ and the error goes to `onError` with the request that started it.
223
+
224
+ Three things hold nothing:
225
+
226
+ - **`npm run dev`.** The dev server renders every request and keeps nothing
227
+ between them. A window has no effect there at all.
228
+ - **A page the build wrote to a file.** The static handler answers before the
229
+ route handler that holds anything, so the window never runs. Adding
230
+ `prerender = false` puts the page back on the path that has one, which is why
231
+ the example above carries both lines.
232
+ - **A fragment.** `?fragment=list` is rendered on demand, for every route,
233
+ prerendered or not.
234
+
235
+ **What is never held:** a page that read a cookie, set a header, answered with a
236
+ `Response`, or has a status outside 2xx. A shared store holding any of those
237
+ hands one visitor's page, or one visitor's `Set-Cookie`, to the next. It is the
238
+ same rule the build uses to decide a route can be a file.
239
+
240
+ ### Tags
241
+
242
+ Seconds say when a page may be out of date. A tag says when it is.
243
+
244
+ ```js
245
+ // app/routes/notes.html
246
+ export const prerender = false;
247
+ export const revalidate = { seconds: 3600, tags: ['notes'] };
248
+
249
+ export default async () => ({ notes: await notes.all() });
250
+ ```
251
+
252
+ ```js
253
+ // app/routes/api/notes.js
254
+ export const POST = async ({ request, revalidateTag }) => {
255
+ await notes.add(await request.json());
256
+
257
+ // Every held page carrying this tag is dropped. The next request for one
258
+ // renders it again.
259
+ revalidateTag('notes');
260
+
261
+ return new Response(null, { status: 204 });
262
+ };
263
+ ```
264
+
265
+ `ctx.revalidateTag` belongs where the change was written, which is an action or
266
+ an endpoint: whatever made the change is what says it happened. A prerendered
267
+ page's loader calling it stops the build, since a build holds nothing yet to
268
+ drop.
269
+
270
+ `revalidate` takes a number of seconds, or `{ seconds, tags }`. Anything else
271
+ throws when the app starts. `revalidate: '1h'` would otherwise hold forever or
272
+ not at all, and say nothing either way.
273
+
274
+ The default store is a bounded map in this process. That is right for one server
275
+ and wrong for several: each holds its own copy, and `revalidateTag` reaches one
276
+ of them. `cache` in the config takes anything with the same `get`, `set`,
277
+ `delete` and `deleteByTag`.
278
+
152
279
  ## Runtimes
153
280
 
154
281
  The same app runs on Node, Bun, Deno and workerd. `bin/serve.js`,