Skip to content

feat: alpha.14 — starter ships in the Vite+ form, oe bin, app-shell, og dedup, Cloudflare guide - #1590

Merged
SisyphusZheng merged 8 commits into
mainfrom
release/alpha14-viteplus-starter
Oct 10, 2026
Merged

SisyphusZheng merged 8 commits into
mainfrom
release/alpha14-viteplus-starter

Conversation

@SisyphusZheng

Copy link
Copy Markdown
Member

What

Four commits from the alpha.14 lane:

  1. The starter ships migrated to Vite+ (feat(router,create)): the qualification battery (fresh scaffold on the vite-plus-core alias; www dev+build on a git-archive copy) came back green — dev serves through the core with compiled tokens, the three-phase build is byte-identical, typecheck passes — so the template ships vp dev / vp fmt / vp lint, catalog-aliases vite to @voidzero-dev/vite-plus-core@1.1.0, drops the standalone vite/oxfmt/oxlint devDependencies, gains the dual oe bin on the router, and teaches layout with an app-shell.tsx that owns the chrome the three pages each carried a copy of. Template self-heal (two unescaped-apostrophe lint errors, pre-format) and .tmpl-copy lint close the template blind spot; starter-smoke rides the migrated fixture.
  2. og per-property suppression wired at both render paths (feat(router)): route-declared head.meta og entries own their property — the site-level default for the same property is not emitted a second time, on SSG and request-time alike, filtered against the resolved document meta (loader-computed og covered). One writer (filterHeadExtrasForRoute beside the emitters); consumer-form tests execute the generated code; status pages keep the raw site block.
  3. Cloudflare deployment guide (docs(www)): static→Pages and Nitro→Workers, written from the nitro-mount adapter contract with the Nitro example built and verified before documenting; bilingual; snippets quote the template verbatim.
  4. Consumer gates follow the new form (fix(release)): packed-starter/ui-appliance gates pin the Vite+ form and fold file:// pins into the template's overrides (catalog survives); full chained gate green locally end to end. The published-consumer qualification legs pin the new-form scripts and go green from the next release.

Verification

  • Full repo gates green: vp run check (4 steps), generate:all, package suites — router 1184, element 566, compiler 27, ui 62, create 38 tests
  • Packed consumer chain green locally (starter: dev/typecheck/test/SSG/start + chromium/firefox/webkit matrix; ui appliance: dev/typecheck/SSG/start)
  • pack:dry-run + pack-surface:check clean (an ADR citation in a shipped comment was caught by the pre-push hook and removed)

Known follow-ups (deliberately not in this PR)

  • The three-OS starter matrix and the full chromium e2e on the migrated fixture run in CI (fixtures updated here)
  • T6 low-priority items (inline re-point move in the release job; releasing.md wording) ride the next release-train touch

…ync)

The alpha.13 publish train's registry sync re-read every published
package's dist-tags after the publish: all six packages on
1.0.0-alpha.13 under latest. The alpha channel alias still names
alpha.12 — the re-point was rejected by the registry under trusted
publishing (E400) and will be repaired separately — so the tracked
block records exactly that state.
The channel alias re-point completed after the first sync: the alpha
tag now names 1.0.0-alpha.13 on all six packages (the first attempt,
run inline seconds after publish, was rejected by the registry with
E400 while the new versions' metadata was still propagating — the
standalone repoint dispatch 30 minutes later succeeded 6/6).
… bin, app-shell layout

The qualification battery (fresh scaffold migrated onto the
@voidzero-dev/vite-plus-core alias; www dev+build on a git-archive copy)
came back green: dev serves through the core with compiled tokens intact,
the three-phase build is byte-identical, typecheck passes, and the
cooling-period interaction is covered by the workspace excludes. The
template therefore ships migrated instead of teaching the migration:

- scripts: dev "vp dev", build/start "oe build"/"oe start", test,
  fmt "vp fmt", lint "vp lint", typecheck — no chained multi-task check
- devDependencies: vite is gone (catalog alias), no standalone
  oxfmt/oxlint (inside vp); vite-plus rides the catalog pinned to
  @voidzero-dev/vite-plus-core@1.1.0
- pnpm-workspace.yaml ships catalog + overrides (vite@* -> catalog) plus
  the existing minimumReleaseAgeExclude entries extended to the vp line
- @openelement/router gains the dual `oe` bin (same dispatcher as
  `openelement`; ng/sv precedent for the two-letter CLI)
- app/islands/app-shell.tsx now owns the shared chrome the three pages
  each carried a copy of; the pages keep only their content
- template self-heal: the two unescaped-apostrophe lint errors fixed and
  every template file pre-formatted; create tests lint .tmpl copies and
  assert the scaffolded form; starter-smoke rides the migrated fixture
Route-declared head.meta og entries now own their property: the site-level
og fragment for the same property is not emitted a second time, on the SSG
render path and on the request-time path alike. The suppression lives in
one place — filterHeadExtrasForRoute beside the head emitters (single
writer) — and the generated entries bind it against the RESOLVED __doc.meta,
so og tags computed from loader data are covered too. Status pages (404
redirects and error renders) keep the raw site block: they emit no route
meta, and filtering there would orphan the head of its og block.

Consumer-form tests execute the generated code verbatim: a route declaring
og:title emits exactly one og:title on both paths; an undeclaring route
keeps the site block byte-identical; a not-found status page never loses
its og block. The renderer-adapter byte pins are re-baselined per the
file's documented ritual. The starter's head.tsx comment now states this
exact contract (declared property wins per-property; name= entries never
suppress).
Written from the nitro-mount adapter's actual contract (33 lines, one
createOpenElementNitroHandler) and the WinterTC dispatch, with the Nitro
example built and verified before being documented. Section A: a
static-only build (drop the 404 route's renderIntent) deploys to
Cloudflare Pages as plain files. Section B: a minimal Nitro project mounts
the built dist/server through the adapter and deploys with
--preset=cloudflare_module; the Nitro version named is the one pinned in
tools/release/nitro-compatibility.ts. Snippets quote the starter template
verbatim; internal process vocabulary removed from both language versions.
The packed-starter and ui-appliance gates pinned the pre-Vite+ form (vite
devDep 8.0.16, a check script, openelement-only bin spelling) and rewrote
pnpm-workspace.yaml wholesale — which dropped the catalog block and made
vite-plus "catalog:" unresolvable. The gates now assert the shipped Vite+
form, fold the file:// tarball pins into the template's existing
overrides key (catalog and excludes survive verbatim), and run typecheck
where they ran the retired all-in-one check. The published-consumer
qualification legs pin the same new-form scripts — they run against the
published create and go green from the next release onward. The full
chained gate runs green end to end locally (starter + ui appliance, three
browser engines).
@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying openelement with  Cloudflare Pages  Cloudflare Pages

Latest commit: 11a9d08
Status: ✅  Deploy successful!
Preview URL: https://8ad5bb00.lessjs.pages.dev
Branch Preview URL: https://release-alpha14-viteplus-sta.lessjs.pages.dev

View logs

…terminism

Two js/file-system-race findings in the consumer gates: the workspace-yaml
fold probed with existsSync before writing. The read is now the existence
check (ENOENT becomes the gate's own missing-file error) and the fold is
one deterministic pass — compute, validate against the same in-memory
string, write once. The written bytes are unchanged.

The router bin test timed out deterministically in CI, not from cold
boots: the dist/server fixture was created inside the per-bin loop, so the
second iteration's plain start booted a real server that never exits. The
entry-reference runs are hoisted out of the loop and every plain-start
spawn now runs before the fixture exists (all against the missing-dist
refusal, the test's own documented intent); six spawns instead of eight,
timeout raised to 180s for CI cold-boot cost.
…vation

Islands hydrated from the same deferred callback race their module chains
(each island chunk carries its own top-level style await), so an outer
island can claim and activate while a nested inner host is still
un-upgraded. Adoption was pure composed-tree containment: the outer
activation adopted the inner island's pending record, dispatched it into a
tree with no handlers yet, consumed and released it — the inner island's
own activation then replayed nothing. Deterministic on chromium under the
Vite+ chunk graph (the outer island resolves first there); latent on the
previous graph.

The adoption filter now also requires that no declared, still-unsettled
island host sits between the target and the adopting root, which
transitively fixes replay and release (both ride adoption); blocked
records stay in the shared pool for the inner activation — the same
pending-for-my-own-upgrade rule as #1170, one level up. Without a declared
tag set the guard is inert and adoption keeps the containment contract.

Unit tests pin both orderings: outer-first (record survives, replays at
inner hydration exactly once) and inner-first (replays once, the later
outer activation stays silent). Six consecutive chromium interaction-matrix
runs green on the packed migrated fixture; firefox/webkit suites green.
@SisyphusZheng
SisyphusZheng merged commit d7b2f46 into main Oct 10, 2026
13 checks passed
@SisyphusZheng
SisyphusZheng deleted the release/alpha14-viteplus-starter branch October 12, 2026 15:03
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