Skip to content

runner: migrate example installs to pnpm#41

Merged
demtario merged 16 commits into
feature/dev-2025-modernize-handsontable-18from
feature/runner-pnpm-installs
Jul 15, 2026
Merged

runner: migrate example installs to pnpm#41
demtario merged 16 commits into
feature/dev-2025-modernize-handsontable-18from
feature/runner-pnpm-installs

Conversation

@demtario

@demtario demtario commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Task: https://app.clickup.com/t/9015210959/DEV-2025

Summary

Migrates the runner's example installs to pnpm and unbreaks Tier-2 local preview. Diff vs base is runner-scoped only (27 files).

pnpm migration

  • All framework installCommands switch from npm install to pnpm install --frozen-lockfile (config/frameworks.json).
  • Tier-2/container dev servers launch via pnpm exec <binary> --flags instead of pnpm run dev -- --flags: pnpm (unlike npm) forwards the literal -- to the script's binary, which makes Vite's CLI treat --host 0.0.0.0 --port 5173 as inert positional args — the dev server bound to the wrong interface and "Booting preview…" hung forever.
  • Per-framework container images (angular/astro/next/next-shadcn/nuxt/remix Dockerfiles) are removed in favor of the single generic live image: sessions seed immutable baked node_modules per framework via hard links (cp -al /baked/<key>/node_modules), then run a fast frozen pnpm reconciliation. A dependency-metadata fingerprint (dependency-metadata.ts) gates fallback: custom package/lock metadata may retry non-frozen; generated starters refuse to mutate their lockfile. This replaces the previous mutable shared dependency cache.

Sandbox file-operation hardening

  • The session API validates every file path (rejects absolute paths, .., node_modules, backslashes, NULs) and validates full file maps before any write; the client runtime normalizes to relative POSIX paths.

Tier-2 local preview fixes (previously broken for ALL container frameworks)

  • routes moved out of wrangler.jsonc into deploy-time --routes flags (pnpm run deploy): with routes declared in config, wrangler dev rewrites every request's Host to the first route's host, destroying the <port>-<sandboxId>-<token>.* preview hostnames proxyToSandbox() routes by — no PREVIEW_HOST value could fix it. See ADR-0020 (also corrects ADR-0011's local-dev claim).
  • Local recipe documented in docs/run-and-deploy.md: .dev.vars needs PREVIEW_HOST="localhost:8787" (empty-string overrides are silently ignored by wrangler).
  • Fixed the stale "Vue and Angular examples run on the container engine…" error message in the authoring app.

⚠️ Not deployable alone — merge order

This branch intentionally excludes regenerated artifacts, so containers/live/Dockerfile here is still the old npm-based context while the boot script already runs pnpm (Bugbot correctly flagged this). The regenerated contexts (corepack+pnpm Dockerfile, baked pnpm-lock.yaml files, frameworks.generated.ts, catalog.json) live in #42 (feature/runner-pnpm-artifacts, stacked on this branch). Merge order: #42 → this branch → base. Do not deploy from this branch before the artifacts PR merges.

Verified locally (end-to-end, with the artifacts branch applied)

  • react-js + mui sessions booted concurrently via wrangler dev; preview URLs (http://5173-<id>-<token>.localhost:8787/) render through the same proxyToSandbox() path as production.
  • Vite HMR WebSocket connects; live file edits via POST /api/session/:id/file hot-update the open page without reload.
  • Invalid token / unexposed port correctly rejected locally (INVALID_TOKEN).
  • wrangler deploy --routes … --dry-run compiles with all bindings.

Remaining checks

  • First production deploy: --routes flags can't carry zone_name; wrangler infers the zone at upload (dry-run doesn't exercise this). Errors loudly if inference fails.
  • node scripts/prepare-container.mjs --all regenerates container contexts cleanly

🤖 Generated with Claude Code


Note

High Risk
Changes Tier-2 boot, deploy routing, and dependency install paths; production deploy relies on --routes zone inference and this branch is incomplete without regenerated container artifacts.

Overview
Moves the demo runner’s example and container installs from npm to pnpm (pnpm install --frozen-lockfile), switches Tier-2 dev commands to pnpm exec (avoids pnpm forwarding -- and breaking --host/--port), and drops per-framework container Dockerfiles in favor of one live image with baked deps plus frozen reconciliation.

Tier-2 local preview is fixed by removing routes from wrangler.jsonc and attaching them at deploy via pnpm run deploy --routes … (ADR-0020), with PREVIEW_HOST="localhost:8787" documented for .dev.vars. The API validates session file paths and the client sends relative POSIX paths only.

Container boot no longer uses the R2 node_modules cache; it seeds cp -al baked node_modules and runs pnpm with fingerprint-gated frozen vs non-frozen fallback. Pipeline/import keeps pnpm lockfiles; Remix example gets Vite optimizeDeps.include for Handsontable hydration.

Note: Regenerated container artifacts (Dockerfile, baked locks, frameworks.generated.ts) are expected from a stacked PR—do not deploy this branch alone until those land.

Reviewed by Cursor Bugbot for commit fc5263c. Bugbot is set up for automated code reviews on this repo. Configure here.

@demtario demtario self-assigned this Jul 14, 2026
@demtario demtario changed the base branch from master to feature/dev-2025-modernize-handsontable-18 July 14, 2026 12:47
@demtario demtario force-pushed the feature/runner-pnpm-installs branch from b51ae74 to f4277a3 Compare July 14, 2026 13:24
demtario added 5 commits July 14, 2026 17:01
The message named only Vue/Angular from when those were the only
container-engine examples; it now covers react-js, ant-design, mui,
and base-web too, and was masking real session-start errors behind
confusing wording.
pnpm (10.33-10.34), unlike npm, does not strip the -- separator when
the target script resolves to a real binary — it forwards a literal
"--" as the script's first argument. Vite's CLI treats that as "stop
parsing options," so --host/--port silently become inert positional
args instead of flags, and the dev server never actually binds where
the readiness probe expects it (stuck "Booting preview..." forever).

Switch react-js/ant-design/mui/base-web/remix to `pnpm exec <bin>
<flags>`, matching vue's already-correct invocation.
wrangler.jsonc sets PREVIEW_HOST to demos.handsontable.com unconditionally
(vars apply to both wrangler dev and wrangler deploy), a real public
wildcard that routes to the deployed worker, not the local one. Container
preview sessions started via local wrangler dev were getting a previewUrl
on that domain, so the iframe hit prod and got INVALID_TOKEN for a
session/token prod never issued. Overriding PREVIEW_HOST="" in .dev.vars
falls back to the request host, resolving as *.localhost:8787 (RFC 6761)
back to the local worker.
When routes are declared in wrangler.jsonc, wrangler dev simulates the
first route's host on every request (request.url and Host both become
demos.handsontable.com regardless of the actual request hostname; only
the pathname passes through). That destroys the
<port>-<sandboxId>-<token>.* preview hostnames the Sandbox SDK's
proxyToSandbox() routes by, so Tier-2 local preview could never work —
no PREVIEW_HOST value could fix it. There is no config key or CLI flag
to disable the simulation (wrangler gates it on inferOriginFromRoutes,
which only the programmatic startWorker API can set).

Declare no routes in wrangler.jsonc and attach the production routes
via `wrangler deploy --routes …` in the deploy script instead. With no
routes, wrangler dev passes the real Host through verbatim, so
*.localhost:8787 preview URLs (PREVIEW_HOST="localhost:8787" in
.dev.vars) flow through the exact same proxyToSandbox() path as
production — HTML, assets, and the HMR WebSocket all verified working
locally, including two concurrent sessions and token rejection.

Also corrects the local-dev docs from the previous commit: an
empty-string PREVIEW_HOST override is silently ignored by wrangler; it
must be set to a real value, and removing routes from the dev config is
the other required half of the recipe.

Caveat: the --routes flags cannot carry zone_name; wrangler infers the
zone on real deploys (dry-run validated the flags but not inference) —
watch the first production deploy.
Records why wrangler.jsonc must not declare routes (wrangler dev
simulates the first route's host on every request, destroying the
preview hostnames proxyToSandbox routes by), corrects ADR-0011's
local-dev claim, and documents the rejected path-based-proxy
alternative and the deploy-time zone-inference caveat.
@demtario demtario force-pushed the feature/runner-pnpm-installs branch from f85528c to f544a0c Compare July 14, 2026 15:02
@demtario demtario marked this pull request as ready for review July 15, 2026 06:49
Comment thread runner/workers/api/src/index.ts
demtario and others added 4 commits July 15, 2026 09:18
nuxt's CLI has no -H alias (host is --host/-h), so `nuxt dev -H 0.0.0.0`
made citty treat -H as a boolean flag and swallow 0.0.0.0 as the
positional rootDir: the dev server served an empty auto-created
/app/0.0.0.0 project — Nuxt's default welcome page instead of the demo.
Present since the original scaffold (ee4110f) but never observable
until local preview started working. Next.js keeps -H; that alias is
valid there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On a fresh Tier-2 session's first load, the Remix vite plugin discovers
handsontable/plugins, handsontable/cellTypes and
@handsontable/react-wrapper one-by-one during hydration; each discovery
re-runs the dep optimizer, and the page ends up importing chunks from
mixed optimizer generations — two React copies, "Invalid hook call",
and a hydration crash (reload recovered, but every new session crashed
on first load). Prebundling the three imports keeps the first optimizer
pass complete, so first loads are clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
examples/angular had a local .angular/ CLI build cache on disk, and the
catalog importer's EXCLUDE_DIRS (.next/.nuxt/.output/.astro/...) did
not cover it, so 12 .angular/cache/** files leaked into the angular
starter — visible in the authoring editor's file tree and written into
every session container. Add .angular and .vite to the exclusions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
019d267 ("chore: Updated pnpm version to latest v10") deleted the
runner workspace lockfile, leaving runner installs non-deterministic.
The restored file is byte-identical to the pre-deletion version.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@demtario demtario force-pushed the feature/runner-pnpm-installs branch from ba9be44 to 728b940 Compare July 15, 2026 07:48
@demtario demtario requested review from budnix and qunabu July 15, 2026 07:49

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 728b940. Configure here.

Comment thread runner/config/frameworks.json Outdated
The angular devCommand in frameworks.json and import-docs.mjs still
carried the `pnpm run start -- --flags` pattern this branch documents
as broken (pnpm forwards the literal `--`, so --host/--port go inert).
Nothing executes devCommand — container sessions run the generated
FRAMEWORK_DEV cmd from prepare-container.mjs — but catalog and
docs-example metadata shouldn't advertise a known-broken invocation.
Flagged by Bugbot on #41.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@demtario demtario merged commit 0b4545d into feature/dev-2025-modernize-handsontable-18 Jul 15, 2026
1 check passed
@demtario

Copy link
Copy Markdown
Contributor Author

Merged to master in commit 4ade4fd4b5761c64c22c955f53ecc673e4decdd5

@demtario demtario deleted the feature/runner-pnpm-installs branch July 15, 2026 08:05
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.

2 participants