Skip to content

feat(html): pages/SSG/ISR slice — page() shell + IsrPage (issue #14) - #91

Merged
devin-ai-integration[bot] merged 4 commits into
mainfrom
devin/issue14-ssr-slice
Oct 19, 2026
Merged

devin-ai-integration[bot] merged 4 commits into
mainfrom
devin/issue14-ssr-slice

Conversation

@espetro

@espetro espetro commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Reviewable slice of #14 (M3: component framework server side — pages, SSG, ISR), on top of @chttp/html inside the scriptc subset.

Rendering surface (packages/html/src/index.ts):

  • page(head, body) — full-document shell: <!doctype html> + <html><head> + <body>. Args are markup (same contract as h() children).
  • IsrPage(render, revalidateSeconds) — TTL-cached document. html() serves the cached string and re-renders lazily on the first read after the window (Date.now()); freshUntil() exposes the expiry. Revalidation is synchronous (Next.js blocking-fallback semantics) — there is no background refresh inside the subset.
  • SSG needs no API: render a component once at startup and serve the baked string from a route.
const index = Layout("posts", PostList(POSTS));          // once — SSG
app.get("/", (c) => c.html(index));
const post = new IsrPage(() => Layout("p", PostCard()), 60); // ISR
app.get("/post", (c) => c.html(post.html()));

Example examples/pages (workspace member): a tiny blog — / is rendered once at startup (SSG), /post/:slug keeps one IsrPage per slug, unknown slugs get a 404 document. node:test e2e over real HTTP covers all three routes plus the revalidate boundary.

Tests/gates: test/page.test.js (6 cases); bench/apps/chttp-html.ts exercises both new exports — bash scripts/scriptc-gate.sh stays 100% on all 10 gates; pnpm --filter @chttp/html test 24/24, pnpm --filter chttp-example-pages test 3/3, oxlint + oxfmt clean.

Docs: docs/html.md gains a "Pages, SSG and ISR" section with the honest limits; plan file at .agents/plans/2026-10-19-issue14-pages.md.

Remaining surface (not in this PR)

Per-request data loading (load fns), nested layouts, streaming SSR, islands/hydration, build-time prerender handing off to @chttp/static, SWR-style background revalidate, a metadata/HEAD model beyond a raw head string, and the planned unplugin JSX→h/html lowering. Still upstream-gated for real framework adapters (fetch globals remain not-implemented in scriptc — see #15).

Link to Devin session: https://app.devin.ai/sessions/adf384ec8d3949c083b34bd738357082
Open in Devin Desktop: https://app.devin.ai/desktop/session/adf384ec8d3949c083b34bd738357082?variant=devin
Requested by: @espetro

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Deploying chttpjs with  Cloudflare Pages  Cloudflare Pages

Latest commit: b299475
Status: ✅  Deploy successful!
Preview URL: https://9b110c6d.chttpjs.pages.dev
Branch Preview URL: https://devin-issue14-ssr-slice.chttpjs.pages.dev

View logs

@devin-ai-integration
devin-ai-integration Bot merged commit 963ac16 into main Oct 19, 2026
3 checks passed
@devin-ai-integration
devin-ai-integration Bot deleted the devin/issue14-ssr-slice branch October 19, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant