Repository navigation
release: 1.0.0-alpha.13 — starter lifecycle bin and artifact hygiene train - #1588
Merged
Merged
Conversation
…train Lifecycle contract: - Router ships an `openelement` bin (build / start [--mode=preview]) declared through the packed manifest; the generated starter's scripts run the short commands through the installed .bin shim instead of installed-tree paths. - The starter's preview script is removed: the default scaffold has request-time routes, so static-only preview always refused; the mode stays available as `openelement start --mode=preview` for builds without one. - `tailwind.theme`/`tailwind.components` sources resolve app-relative against the project root, matching the documented contract; the template declares `app/styles/theme.css` (no more hand-counted ../.. climbs). Starter dependencies: - Caret ranges (^1.0.0-alpha.13) over the release line instead of exact pins; `pnpm update` picks up later 1.0.0 prereleases and the final 1.0.0. - `@hono/vite-dev-server` and `hono` moved to devDependencies (dev-only surface); `@playwright/test` removed from the scaffold. Build output: - The zero-byte `_virtual_open-build-trigger-*` chunk no longer ships in dist. - The client build no longer copies public/ into dist/client/ (no duplicated assets under a second URL). Docs and DX: - Getting-started no longer teaches a nonexistent --no-tailwind flag; configuration documents the tokens.css vs theme.css relationship; the 404 build semantics are corrected (hybrid renders via the request-time server); create README's Tailwind self-contradiction and stale version pins fixed. - The create handoff box prints the generator version; quieter dev logs. Release: version bumped to 1.0.0-alpha.13 across all stamp sites and workspace members; CHANGELOG entry added; publish-surface scans extended (installed-tree command form, template-script path form, mutually exclusive contract terms) with red/green fixtures.
Deploying openelement with
|
| Latest commit: |
3b940e9
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3c0eca83.lessjs.pages.dev |
| Branch Preview URL: | https://release-alpha13-artifact-hon.lessjs.pages.dev |
…13 E lane) Fact layer (E1): - The version note, roadmap publish status and getting-started note no longer assert registry state from a possibly-stale tracked block: they state the invariant truth and point at `npm view @openelement/create dist-tags`. - Package counts derive from the release-state packages array (six) instead of hand-written numbers; the ambiguous "no single stable version" caption now says what it means (prerelease line, no stable release yet, one shared version); "3 browser engines in CI", "0 third-party runtime deps", the WinterCG server entry wording replace the vague originals. en + zh. Homepage (E2, bounded): - One-line version block (v1.0.0-alpha.13 · six packages · one version, mono/nowrap, linked to npm) replaces the six-fold repeated version list. - Sentence-form stats strip at readable contrast; marquee aria-hidden with prefers-reduced-motion stop and hover pause; top nav gains API and Roadmap; code blocks scroll in one place; §1 double scrollbar and the WebKit slotted-code @scope seam fixed (surface moved to the doc layer, e2e-pinned across three engines). Registry truth machinery (E3): - Publish train ends with a registry read-back written into release-state and the site's display constants (registry-sync.ts, the one writer both drift checks read); a second read-back after the alpha alias re-point records both tags as served. Synced files land via maintainer PR from the release artifact; until they land, the gate:release drift check stays red. - New registry-drift:check verifies displayed versions against the live registry (fail-closed on drift, explicit SKIP only when offline, proved findings never dropped on network blips). - The tracked registry block and site constants now carry the real registry truth (alpha.12) — fixing the stale homepage version table. Cleanup (E4): - routes-types gate: add the css-modules ambient types (22 TS2307 gone). - zag-combobox spec: explicit island-defined waits; WebKit root cause (loader race under shared-chunk TLA) documented in the local ledger. - HMR test deadline 30s; `openelement version` / `--version`; starter README pnpm supply-chain note. CHANGELOG extended.
…3 F lane) - The site's Tailwind preset now rides the framework's config-file `tailwind` key (openelement.config.ts) instead of a build-only consumer plugin: dev serves the compiled theme sheet from /.openElement/tailwind-preset/entry.css and links it, the build emits the same compile as /assets/open-tailwind.css — both channels deliver one fact, and local dev shows the real site. - Hero scrim: the darkening gradient now covers the photograph band's full height (previously only the lower third; stats copy sat on raw photography at 2.7:1 dark / 1.3:1 light), the ramp starts earlier, and the hero box clips the stage's exit transform so it can no longer spill over the stats strip and marquee bands. e2e gains a band guard pinning both.
…er take the dev channel down (KR-5) The build half's inner vite build runs with emptyOutDir against .openElement/tailwind-preset/, so any `vite build` emptied the directory the dev channel staged its entry at: a dev server that had run beside a build answered the document's stylesheet link with 404 until restarted (reproduced on the site, alpha.13 F lane). The dev channel now owns no file. resolveId maps the contract URL — in both spellings Vite hands plugins (absolute path and root-relative URL, query suffix preserved) — onto the entry's identity path, and load serves the generated text per request (the same renderStagedPresetEntry the build compiles, so both channels keep one compile input). configResolved writes nothing. URL contract, HMR css-update semantics (#1582) and the OFF state are unchanged. The regression test pins the incident: dev up, no file on disk, a stale staging write is not the served source, and after wiping the directory both the ?t= and plain URL forms still answer the compile.
…rflow (alpha.13 H lane) - Fonts are npm dependencies now (@fontsource 5.3.0, byte-identical to the CDN pins): the Tailwind preset bundle compiles the package stylesheets and emits each woff2 as a hashed same-origin asset. The four jsDelivr render-blocking links are gone — a hung CDN no longer stalls first paint (measured: old build never fires load under a hung CDN; new build 121ms), and hero glyphs are pixel-identical. font-delivery/build-output tests pin the new contract; no artifact may reference cdn.jsdelivr.net. - The static serve path answers a miss with the build's own 404.html (and its locale copies) with a 404 status, and /404.html itself answers 404 — the error document is never a 200 page. Dynamic builds keep their own 404 (dist/server takes precedence). One seam in static-serve.ts covers the CLI and every fixture server; registered in seams.md with consumer tests. - Long-form pages no longer scroll horizontally at 390px: unwrappable generated URL tokens and inline identifiers get break opportunities, the contributing fence owns its scroll, grid tracks get a minmax(0,1fr) floor. All 68 built routes sweep 0px at 390/768; an e2e guard pins the four pages with a negative proof. The /reference split remains a documented follow-up (needs route/nav/search re-homing decisions).
…ompiles, trustedHtml islands SSR (alpha.13 I lane) - packageIslands now works from packed artifacts, end to end: the plugin's config hook places the derived ssr.noExternal on the resolved config (dev SSR bundles declared packages), and the compiler recovers the style edges of its own emitted artifacts so client/dev builds emit real .css assets instead of failing MISSING_EXPORT. A new packed-consumer UI leg rides consumer:packaged (pack -> scaffold -> open-button/dialog/code-block app -> dev/build/start), with both detectors proven by mutation. - The compiler admits ErrorBoundary as a canonical base (README pattern compiles verbatim: subclass, hasError branch, catchError/retry). The base publishes kernel captures into a now-writable hasError field; the README sentences are pinned unchanged by test. - trustedHtml @Property defaults survive island SSR: the seed resolves the class's own branded static-props default when the metadata projection is null — the exact /tmp/allpkgs failure now builds, serves and hydrates the branded markup. - The action success channel is documented as what it is (303 PRG; the never-emitted success envelope is removed from the wire type) and the router guide shows the loader-side success-data pattern (en + zh). - New guide page "The compiled module grammar" (en + zh): thirteen enforced laws, each traced to its OEC site with a compiled positive example and the actual rejection. The tag-name JSX diagnostic now says so in plain words.
…(CodeQL) The null guard above the loop already skips null candidates, so the `candidate !== null` inside the object branch was a dead comparison (js/comparison-between-incompatible-types). Behavior is unchanged.
….13 J) The README sentence led readers to a two-return render with a binding inside the branch — three natural readings, all rejected by the compiler. The section now states the compilable shape (re-declared @Property hasError, single-return render with a fully static ternary, catchError sets the flag) and points at the compiled grammar guide. The admission test pins the new sentences (the contract is unchanged: what the README teaches must compile), and the grammar guide gains the failure-injection law — throws live in lifecycle methods, never in render() (en + zh).
…scan (CodeQL) #4226 (js/file-system-race): the dev-channel-writes-no-file assertion was an existsSync check on the same path the test then writeFileSync's a stale staging fixture onto — the TOCTOU shape. Assert via readFileSync throwing ENOENT instead: no exists->write pairing, and a strictly stronger claim. #4227 (js/incomplete-url-substring-sanitization): the jsDelivr scan was a bare substring test. Anchor it on the URL host boundary (scheme-or-protocol-relative //cdn.jsdelivr.net followed by a delimiter or end) so the predicate is complete.
…rappers, signal-write routing, SSR fallback The compiled model compiled ErrorBoundary and its manual catchError/retry/ reset channel, but no automatic capture existed: authored lifecycle throws were emitted verbatim and escaped to window.onerror, a property write whose signal-graph evaluation threw escaped through the facade setter, kernel update failures were captured only into the element-local service with no ancestor routing, and SSR had no boundary at all — a subtree evaluation throw 500'd the route while the README claimed the boundary renders a fallback. - OpenElement gains a protected _captureError(error) that climbs the composed ancestor chain (crossing shadow boundaries via the host) to the nearest isErrorBoundary and captures through that boundary's own error service, so publication rides the existing onError -> hasError path: the fallback Region flips exactly as an application catchError() call. With no boundary it returns false and callers keep today's rethrow semantics. - The compiler wraps the seven platform lifecycle callback bodies in try/catch -> _captureError at emission time (pay at compile time; the body's source-map segments stay byte-identical, the scaffolding lines stay unmapped; module ABI 1 -> 2). - The facade property setter routes synchronous signal-graph evaluation throws — handler-driven and external writes alike. - The kernel's Region update-error sink additionally routes non-boundary elements to the nearest boundary. - SSR: a subtree throw at renderDsd re-serializes the nearest boundary's program with hasError forced true — the program's own when-Region renders the fallback branch in place of the failed subtree; without a boundary the route still fails loudly. Seams registered in docs/architecture/seams.md with consumer-form tests (element/compiler/router suites incl. Chromium).
…cument context and the page-scope contract - ui README and CUSTOMIZATION.md advertised open-card/open-badge/ open-callout/open-tabs, which do not ship (the package exports button, input, code-block, theme-toggle, dialog, dropdown only). Removed, with the customization guard's pinned surface updated in the same change per its own documented protocol. - compiled-grammar's canonical boundary example used a named export; the static-component scanner registers only the module's default export tag, so the verbatim example never SSR-expanded. Now default-exported, with the registration asymmetry documented: page-scope components register through the route import chain, islands through the template scan. - The context example referenced a starter file that does not exist and imported consumeContext from the wrong module. Replaced with a worked provider->consumer example against the real API, stating the grammar constraint that forces the subscribe-and-copy shape. - islands-and-ssr now states the page-scope contract explicitly: non-island components are server-rendered only by design — no client code, no upgrade, no runtime lifecycle; interactivity is the island form.
…e --tw-shadow dev/build delta --mode=preview delegated to the app's own vite preview, whose index.html fallback answered 200 for every miss and even for extensionless pretty URLs like /about — two static serving modes disagreeing. Preview now rides the same createFetchHandler/serveFetch dispatch as start: pretty URLs resolve the real page, a miss answers 404 + the build's 404.html, /404.html itself answers 404. The vite-preview ergonomics stay (--port/--host/--strictPort, the 4173 default, next-port probing, and a loopback-only default bind — start remains the 0.0.0.0 deployment server). The dev/build Tailwind parity test now pins --tw-shadow explicitly. The peer's serve and build variants order @layer properties differently around utilities and differ only in minified literal spellings; after normalization the declaration sets are equal. The three inherent delta classes are documented in the test, and anything beyond them fails.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The 1.0.0-alpha.13 train: the generated starter's lifecycle rides a real package bin, the scaffold's dependency surface matches what the docs say, and the build output drops two artifact defects.
Lifecycle contract
@openelement/routernow ships anopenelementbin (build/start [--mode=preview]), declared through the packed manifest (packedMetadata()/PACKAGE_BINS, with the entry path sourced from the same pack-layer constant that puts the module in the tarball). The starter'sbuild/startscripts run the short commands through the installed.binshim — no installed-tree paths in scripts, READMEs, or CLI hints.previewscript is removed. The default scaffold has request-time routes, so static-only preview always refused; the mode remains available asopenelement start --mode=previewfor builds without a server side, and the refusal message points atopenelement start.tailwind.theme/tailwind.componentssources now resolve app-relative against the project root, matching the documented contract. The template declares['app/styles/theme.css']; hand-counted../../climbs are gone. Disambiguation is lexical plus filesystem (a source that exists under the app root is the app file;@/#specifiers pass through), sotailwindcss/theme.cssstyle package sources keep working.Starter dependencies
@openelement/*deps use caret ranges (^1.0.0-alpha.13) over exact pins: a fresh install resolves the current release,pnpm updatepicks up later 1.0.0 prereleases and the final 1.0.0.@hono/vite-dev-serverandhonomoved todevDependencies(they are dev-server-only surface;build/startnever resolve them), and@playwright/testis removed from the scaffold. Docs updated to match.Build output
_virtual_open-build-trigger-*chunk no longer ships indist/.publicDir: false, sopublic/is no longer copied intodist/client/— every static asset previously shipped at a second URL, byte-identical and differently cached.Docs and DX
--no-tailwindflag (en + zh); the configuration guide documents thetokens.cssvstheme.cssrelationship (en + zh); 404 build semantics corrected across the affected guides and template comments (hybrid builds render the not-found route via the request-time server; static-only builds writedist/404.html); the create README's Tailwind self-contradiction and stale version prose are fixed.node node_modules/...command form, template-script file-path form, mutually-exclusive contract terms) with red fixtures plus a live-green run, so these classes fail in the gate instead of shipping.Release
Version bumped to 1.0.0-alpha.13 across all stamp sites and workspace members (dry-run roster verified against the previous train's bump commit); CHANGELOG entry added.
Verification
pack:dry-run→pack-surface:check(incl. new bin-equality and missing-bin-target scans) →package-artifacts:check(new rules) green on real tarballs; the packed router tarball carriesbin: { openelement: ./src/cli/cli.js }at 1.0.0-alpha.13.consumer:packagedend-to-end green: scaffolds from the packed create, installs the packed tarballs, exercises dev/check/test/build/start, the 3-browser matrix, preview refusal, and build equivalence between bin and subpath entries.packages/router/__tests__/cli-bin.test.ts; the consumer probe's Playwright pin anchored to the root pin by test.Pre-existing (reproduced on pristine main, not introduced here)
@openelement/www#check:routes-typesfails with 22 TS2307./x.csserrors — identical on a clean main worktree.Both are worth separate follow-ups; neither is touched by this change.
E lane (appended): www fact layer, homepage redesign, registry-truth machinery
Fact layer. Version notes, roadmap publish status and the getting-started note no longer assert registry state from a tracked block that can lag: they state the invariant and point at
npm view @openelement/create dist-tags. Package counts derive from the release-state packages array (hand-written counts eliminated); the ambiguous "no single stable version" caption now says what it means; stat-copy calibrated ("3 browser engines in CI", "0 third-party runtime deps", WinterCG server entry wording). en + zh.Homepage (bounded redesign). One-line version block (
v1.0.0-alpha.13 · six packages · one version, mono/nowrap, linked to npm); sentence-form stats strip at readable contrast; marquee aria-hidden with reduced-motion stop and hover pause; top nav gains API and Roadmap; code-block scrolling consolidated; the §1 double scrollbar and a WebKit slotted-@scopestyling seam fixed and e2e-pinned across three engines.Registry-truth machinery. The publish train ends with a registry read-back written into the tracked release state and the site's display constants (single-writer module shared with both drift checks), with a second read-back after the alpha alias re-point so both tags are recorded as served. The synced files land via a maintainer PR from the release artifact; until they land, the
gate:releasedrift check stays red. A newregistry-drift:checkverifies displayed versions against the live registry — fail-closed on drift, explicit SKIP only when offline, proved findings never dropped on network blips. The tracked block now carries the real registry truth, which is what fixes the stale version table on the homepage.Cleanup. The routes-types gate typechecks again (css-modules ambient types added; 22 TS2307 gone, no hidden errors surfaced); the zag-combobox spec waits on island definition explicitly, with the WebKit root cause (loader race under shared-chunk TLA) documented for a follow-up; HMR test deadline raised for 2-core CI;
openelement version/--versionadded; starter README notes pnpm's supply-chain bookkeeping file. CHANGELOG extended accordingly.F lane (appended): dev/build styling parity + hero scrim
The site's Tailwind preset now rides the framework's config-file
tailwindkey instead of a build-only consumer plugin, so dev serves the same compiled theme sheet the build ships — local development shows the real site. The hero scrim covers the photograph band's full height (the stats copy previously sat on raw photography at 2.7:1 dark / 1.3:1 light), the ramp starts earlier, and the hero box clips the stage's exit transform so it can no longer spill over the stats strip and marquee bands; e2e pins both.G lane (appended): the dev preset channel owns no file (KR-5)
The build half's inner vite build empties
.openElement/tailwind-preset/, which used to be where the dev channel staged its entry — a dev server that had run beside any build answered the stylesheet link with 404 until restarted. The dev channel now serves the entry as an in-memory module at the same URL (resolveId/load over the same generator the build compiles), writes nothing to disk, and keeps the HMR contract; a regression test replays the incident end to end.H lane (appended): self-hosted fonts, the error document, mobile overflow
loadunder a hung CDN; new build 121ms), hero glyphs pixel-identical, and no artifact may reference cdn.jsdelivr.net (test-enforced).404.html(and locale copies) at a 404 status;/404.htmlitself answers 404 — the error document is never a 200 page. Dynamic builds keep their own 404. One seam instatic-serve.tscovers the CLI and every fixture server./referenceper-package split is documented as a follow-up (route/nav/search re-homing decisions).I lane (appended): package islands work packed; ErrorBoundary compiles; trustedHtml islands; grammar docs
packageIslandsworks from packed artifacts end to end: the plugin's config hook places the derivedssr.noExternalon the resolved config, and the compiler recovers the style edges of its own emitted artifacts so client builds emit real.cssassets instead ofMISSING_EXPORT. A new packed-consumer UI appliance ridesconsumer:packaged(pack → scaffold → open-button/dialog/code-block app → dev/build/start), with both detectors proven by mutation — the flagship "consume @openelement/ui as package islands" story now holds outside the workspace.ErrorBoundaryas a canonical base: the README pattern (subclass,hasErrorbranch,catchError/retry) compiles verbatim; the README sentences themselves are pinned unchanged by a test.trustedHtmlproperty defaults survive island SSR (the seed resolves the class's own branded default when the metadata projection is null).