Skip to content

chore(oj): move the default dev server to oj 0.2.22 - #267

Merged
mikn merged 1 commit into
mainfrom
mikn/oj-0.2.19
Oct 10, 2026
Merged

mikn merged 1 commit into
mainfrom
mikn/oj-0.2.19

Conversation

@mikn

@mikn mikn commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

The pinned oj 0.2.16 dev server wastes upkeep on three local patches upstream now ships, and 0.2.22 still fails SSR calls under load and rebuilds the client bundle on every plugin restart.

Problem

Upstream shipped the fs.watch, plugin-file HMR and code-cache patches (oj#322, #325, #324). Two bugs remain in 0.2.22 (oj#347, #348).

Observed in production

Not observed in production: the ruleset builds development tooling. Found on a large app's dev server on remote runners.

Gain

Three fewer local patches and oj 0.2.22. Busy hosts no longer fail parked SSR calls, and a plugin restart restores the bundle in under a second instead of a two-minute rebuild.

What changes

  • oj and its forked crates move to 0.2.22. V8, deno_core and Cranelift keep their versions. The three upstreamed patches are dropped; upstream's code cache defaults to 128 MiB, where the patch allowed 1 GiB.
  • oj-server-scan-outside-plugin-host.patch stays: the time-sliced in-host scan (#338) still overruns the optimizer deadline on a large app.

Fix 1: parked watchdog (oj#347)

  • Root cause: call_job arms a parked call's watchdog for the same instant as its own timeout. When another call's JS holds the loop, the watchdog terminates that call, and every parked call fails with "execution terminated".
  • Patch: oj-js-parked-watchdog-grace.patch re-arms the watchdog a grace period past the deadline, clearing any termination the race leaves.
  • Evidence: //oj:parked_watchdog_test fails without the patch and passes with it.

Fix 2: restart restores the bundle (oj#348)

  • Root cause: oj's own start/manifest.ts, rewritten every boot, was in the cache key, because the filter missed its path under a symlinked bazel-bin. The restart also re-execed with config-set VITE_* values.
  • Patches: oj-cache-start-bundle-stable-key.patch and oj-server-restart-startup-env.patch.
  • Evidence: //oj:start_bundle_key_test fails without them and passes with them.

🤖 Generated with Claude Code

@mikn
mikn force-pushed the mikn/oj-0.2.19 branch 2 times, most recently from 201fa76 to ba3f92f Compare October 9, 2026 22:23
@mikn mikn changed the title chore(oj): move the default dev server to oj 0.2.19 chore(oj): move the default dev server to oj 0.2.22 Oct 9, 2026
oj 0.2.17 ships the fs.watch dispatch index and thread that
oj/oj-deno-fs-events-indexed.patch carried (lovablelabs/oj#322); 0.2.19
serves plugin-resolved app files through the module pipeline with graph
nodes keyed by served URL, which oj/oj-server-file-hmr.patch carried
(lovablelabs/oj#325); and 0.2.20 keys Vite's per-load
`.timestamp-<ms>-<hash>.mjs` config bundles by a stable name and trims the
V8 code cache at startup to OJ_CODE_CACHE_MAX_BYTES (lovablelabs/oj#324),
which oj/oj-js-code-cache-bounded.patch carried. All three patches are
dropped. Upstream's default code cache budget is 128 MiB where the patch
used 1 GiB.

oj 0.2.17 (lovablelabs/oj#312) runs the dependency scan inside the plugin
host and resolves each scanned import through the app's plugins. On a large
Cloudflare/TanStack Start app that kept the SSR plugin host from answering
any hook for 40 s; oj declared the host gone and every SSR request answered
500. 0.2.21 runs each plugin resolve of the scan as a unit of a fair queue
(lovablelabs/oj#338, #340), so other hooks run during the scan, but the scan
of that app still outlives the optimizer's 120 s deadline. oj_js enforces
the deadline with the isolate watchdog's terminate_execution, which stops
whatever JavaScript the shared plugin-host isolate is running: the SSR
request's transforms fail with "execution terminated" and the route never
renders. oj/oj-server-scan-outside-plugin-host.patch, re-cut against 0.2.22,
keeps leaving the scan to the optimizer job, which resolves with rolldown
alone; runtime discovery still picks up an import only a plugin resolves.

The remaining oj-crate patches apply to oj/build.rs, oj_deno_napi,
oj_deno_runtime and oj_deno_snapshots, whose sources are unchanged since
0.2.19; V8, deno_core, Cranelift and the other patched crates keep their
versions. oj_server 0.2.22 adds deno_signals 0.50.0, already in the
lockfile.

oj_js accepts oj_deno_runtime and oj_deno_snapshots ^0.2.12, so the lockfile
bumps all fourteen oj crates explicitly: a minimal update of oj alone leaves
older crates behind.

oj 0.2.17 also discovers and pre-bundles dependencies by default, as Vite
does, so a bare `zod` import in the oj behaviour tests now points at oj's
pre-bundle (`/@oj-deps/zod.mjs?v=…`); the tests accept it as they accept
Vite's dependency cache.

Three oj patches fix bugs the 0.2.22 dev server still has.

- oj/oj-js-parked-watchdog-grace.patch: a parked call's watchdog was armed
  for the same instant as its own timeout, so when the event loop was busy
  with another call's JS the watchdog terminated that call and every
  parked call failed with "execution terminated". It is re-armed a grace
  period past the deadline. //oj:parked_watchdog_test pins it.
- oj/oj-cache-start-bundle-stable-key.patch and
  oj/oj-server-restart-startup-env.patch: a plugin server.restart() never
  restored the cached client bundle, because oj's own rewritten
  start/manifest.ts was in the cache key (the build-dir filter missed its
  realpath under a symlinked bazel-bin) and the restart re-execed with the
  VITE_* values the config had written into the environment. The key now
  leaves out oj's own files, and a restart uses the launch environment.
  //oj:start_bundle_key_test pins the key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikn
mikn merged commit 0b456f9 into main Oct 10, 2026
11 checks passed
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