feat(templates): Ember 7 on Embroider + Vite #136
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
| name: CI | |
| # Three tiers, cheapest first (mirrors the retired GitLab CI): | |
| # | |
| # gate - offline, Wasm-free guards (toolchain subsystem + llhttp Wasm HTTP | |
| # parser). Runs on every push/PR; seconds; catches silent regressions | |
| # such as esbuild-wasm drift or a broken native->wasm alias table. | |
| # verify - the hermetic offline suite (scripts/verify-node.mjs). Needs the Wasm | |
| # VFS/codec/crypto built for Node; runs on PRs + the default branch. | |
| # pm-gate - the package-manager North Star (real npm/yarn/pnpm/corepack in-VM). | |
| # Network + the Wasm VFS/codec/crypto, so it's manual/scheduled like | |
| # the spikes tier — but it FAILS the run, unlike spikes-net. | |
| # spikes - the network tier: boots real templates and installs from the live | |
| # npm registry in-VM. Slow + registry-dependent, so it's manual/scheduled. | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| schedule: | |
| # Nightly network spikes. | |
| - cron: "0 3 * * *" | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # --- fast gate: offline, no Wasm, every push/PR ---------------------------- | |
| toolchain-gate: | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - run: node scripts/run-spikes.mjs --offline | |
| # The notebook's view, rendered under jsdom. It is `net` only because it | |
| # installs React, a DOM and a bundler off the registry — it runs no | |
| # container, needs no Wasm and touches no network of its own, so it belongs | |
| # in the PR gate and not in spikes-net, which is schedule-only and | |
| # `continue-on-error: true` and therefore gates nothing. That distinction is | |
| # not academic here: the notebook shipped with every cell editor dead, and | |
| # this is the only job that would have gone red for it. | |
| - name: the notebook view mounts | |
| run: node scripts/run-spikes.mjs --net notebook-view | |
| # The static probes. Both are Wasm-free and take under a second, and | |
| # neither was wired into any job before — probe:node-registry shipped as | |
| # the guard against unresolvable builtin ids and had never actually run in | |
| # CI, which is the same "written but never executed" gap the spike table | |
| # had. | |
| - run: npm run probe:node-registry | |
| - run: npm run probe:http-egress | |
| # The browser egress header policy. Pure logic on purpose: Node has no CORS | |
| # and the headless fetchers forward every header, so no spike can see a | |
| # regression here — a stripped Authorization header shows up as a request | |
| # that quietly succeeds anonymously. | |
| - run: npm run probe:egress-headers | |
| - run: npm run probe:terminal-feedback | |
| # The cookie jar's RFC 6265 subset. Pure logic on purpose: a path rule that | |
| # is slightly too generous hands one route's session to another, and neither | |
| # that nor an over-eager expiry shows up as an error anywhere. | |
| - run: npm run probe:cookie-jar | |
| # SDK packaging + public-API contract guard (offline, no Wasm, no browser). | |
| # Also regression-checks the shipped preview sw.js branding + examples/basic. | |
| sdk-smoke: | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - run: npm run smoke | |
| # --- offline hermetic suite (needs the Rust->Wasm build) ------------------- | |
| verify: | |
| if: github.event_name == 'push' || github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown, wasm32-wasip1 | |
| - uses: jetli/wasm-pack-action@v0.4.0 | |
| with: | |
| version: v0.13.1 | |
| - name: Cache cargo | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| packages/*/target | |
| key: cargo-${{ runner.os }}-${{ hashFiles('packages/*/Cargo.lock') }} | |
| - name: Build Wasm crates for Node | |
| run: npm run build:vfs:node && npm run build:codec:node && npm run build:crypto:node && npm run build:wasi-demo | |
| # These are offline but need the Rust/Wasm VFS, so they can't run in the | |
| # Wasm-free toolchain-gate (run-spikes.mjs would silently skip them); run them | |
| # here, after the crates are built above. The `bun` filter is a substring | |
| # match, so it also re-runs the Wasm-free bun-offline spike — cheap, and it | |
| # means a Bun change is never merged on a green run that skipped Bun. | |
| # | |
| # EVERY `needsWasm` offline spike belongs in this list. One that is registered | |
| # but missing here runs nowhere at all: skipped in toolchain-gate for want of | |
| # the crates, and never selected in the only job that has them. | |
| - name: offline spikes that need the Wasm VFS | |
| run: node scripts/run-spikes.mjs --offline dep-cache bun http-binary-body http-response-bytes cookie-session fs-cp fs-errors worker-pool node-cli repl stack-traces readline watch child-stdin fs-metadata crypto-jwk zlib-brotli port-liveness constants diag-liveness fatal-errors net-close-order net-blocklist | |
| - run: npm run verify | |
| # --- package-manager gate: the North Star, gated on its own ---------------- | |
| # Running the real npm/yarn/pnpm/corepack CLIs in-VM is the headline capability, | |
| # so it gets a job that can actually go red. It is deliberately NOT part of | |
| # spikes-net: that job is `continue-on-error: true` (registry flakiness across | |
| # 40+ template installs would make it noise), which means a broken package | |
| # manager would show up as a green run there. | |
| # | |
| # Not on push/PR either: each PM spike vendors a real CLI and runs a real | |
| # install from the registry, so the eight of them cost far more than the PR | |
| # budget allows. Making this PR-blocking needs the vendor assets cached or | |
| # committed first — see scripts/run-spikes.mjs VENDORS. | |
| pm-gate: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - uses: jetli/wasm-pack-action@v0.4.0 | |
| with: | |
| version: v0.13.1 | |
| - name: Cache cargo | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| packages/*/target | |
| key: cargo-${{ runner.os }}-${{ hashFiles('packages/*/Cargo.lock') }} | |
| # All three crates, not just the VFS. A package manager is a crypto and | |
| # compression workload before it is a filesystem one: npm verifies every | |
| # tarball against its sha512 integrity, and only md5/sha1/sha256 have a JS | |
| # fallback, so without the crypto crate `npm install` dies on the first | |
| # dependency with FETCH_ERROR "digest 'sha512' needs the wasm codec". The | |
| # codec crate is just as load-bearing — a registry tarball is a .tgz, and | |
| # without zlib the extract fails with "zlib wasm codec is not available". | |
| - name: Build the Node Wasm crates | |
| run: npm run build:vfs:node && npm run build:codec:node && npm run build:crypto:node | |
| # Provisions its own scratch dirs + studio delivery assets (see VENDORS); | |
| # a provisioning failure is reported as a FAIL, not skipped. | |
| - run: npm run spikes:pm | |
| # --- framework-template gate: the shipped templates, on a job that can go red - | |
| # Same argument as pm-gate, and it has now been paid for. `vite: ^8.0.0` floated | |
| # onto rolldown 1.2.2, which dropped @rolldown/binding-wasm32-wasi from its | |
| # optionalDependencies — so nothing installed the wasm binding any more, and the | |
| # dev server in every Vite 8 template stopped starting. FOUR spikes went red and | |
| # said so for as long as it took anyone to look, which was never: spikes-net is | |
| # `continue-on-error: true`, so its run is green whatever happens inside it. | |
| # | |
| # These six are separable from that tolerance on their own merits. They are fast | |
| # (11-16s each, versus the 40+ installs that made the tier noisy), they install one | |
| # small tree apiece, and a failure here is not registry weather — it is the | |
| # product's headline surface not starting. Registry drift is exactly what it is | |
| # supposed to catch, so tolerating it defeats the job. | |
| # | |
| # Scheduled/dispatch rather than per-push for the reason pm-gate gives: the shared | |
| # harness vendors a real npm CLI, and that provisioning is not cached yet. | |
| template-gate: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - uses: jetli/wasm-pack-action@v0.4.0 | |
| with: | |
| version: v0.13.1 | |
| - name: Cache cargo | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| packages/*/target | |
| key: cargo-${{ runner.os }}-${{ hashFiles('packages/*/Cargo.lock') }} | |
| # All three crates, for the reason pm-gate spells out: a real install verifies | |
| # sha512 integrity and extracts .tgz tarballs. | |
| - name: Build the Node Wasm crates | |
| run: npm run build:vfs:node && npm run build:codec:node && npm run build:crypto:node | |
| # `react` was missing from this list until the template most users start from | |
| # turned out to be the one nothing ran. Each of these now boots its server the | |
| # way the studio does — through the manifest's own dev command — rather than by | |
| # calling the vite bin directly, which is the shortcut that let a broken shipped | |
| # path sit behind six green spikes. | |
| # | |
| # Anchored (`name$`) because the filters are a substring match by default, and | |
| # a bare `lit` also selects sqlite and pglite: this step was running two in-VM | |
| # database spikes it does not name, on a job whose failures are supposed to mean | |
| # "a shipped template stopped booting". Nine ran where seven were asked for. | |
| - name: framework templates must start their dev server | |
| run: node scripts/run-spikes.mjs --net react$ preact$ lit$ solid$ vue$ svelte$ qwik$ ember$ | |
| # The two the step above used to pick up by accident, kept blocking on purpose. | |
| # Anchoring `lit` would otherwise have moved them to spikes-net alone, which is | |
| # `continue-on-error: true` — so a broken in-VM database would have stopped being | |
| # able to turn the workflow red. They earn a step here on the same terms as the | |
| # templates: a WASM SQL engine running in the browser is a headline capability, | |
| # and at ~10s for the pair they are cheaper than anything else in this job. Their | |
| # own step, because a failure here means something different from a template that | |
| # will not boot — which was the whole problem with them arriving via `lit`. | |
| - name: the in-VM databases must work | |
| run: node scripts/run-spikes.mjs --net sqlite$ pglite$ | |
| # Nest's dev command is a watch supervisor rather than a dev server, so its gate | |
| # is that a SAVE reaches the browser: boot, edit, recompile, restart, new | |
| # response. Separate step because a failure here means something different. | |
| - name: the Nest template must survive a save | |
| run: node scripts/run-spikes.mjs --net nest-watch | |
| # Its own step rather than an extra filter above, because it proves something | |
| # different: that an interactive scaffolder can be ANSWERED, not that a template | |
| # serves. Needs the vendored npm, hence the net tier. | |
| - name: an interactive scaffolder must be answerable | |
| run: node scripts/run-spikes.mjs --net scaffolder | |
| # --- network tier: real template installs from the live registry ----------- | |
| # Manual (workflow_dispatch) or scheduled: slow and depends on | |
| # registry.npmjs.org being reachable. | |
| spikes-net: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 120 | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - uses: jetli/wasm-pack-action@v0.4.0 | |
| with: | |
| version: v0.13.1 | |
| - name: Cache cargo | |
| uses: actions/cache@v6 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| packages/*/target | |
| key: cargo-${{ runner.os }}-${{ hashFiles('packages/*/Cargo.lock') }} | |
| - name: Build Wasm crates for Node | |
| run: npm run build:vfs:node && npm run build:codec:node && npm run build:crypto:node | |
| - run: npm run spikes:net |