History

Pre-bundle late-discovered deps so the dev worker never program-reloads mid-suite

vite was discovering effect/Match, effect/Predicate, and js-yaml during test runs instead of at boot, forcing a re-optimize and full program reload on both the client and SSR (workerd) environments. Each reload strands the previous worker program's heap inside workerd, and a handful of them exhausts its heap limit and kills the dev server mid-shard. Adding these to optimizeDeps.include (client) and environments.ssr.optimizeDeps.include (SSR) in apps/cloud and apps/host-selfhost's vite configs makes vite bundle them at boot instead, so no mid-run discovery happens. js-yaml is a transitive dependency via @executor-js/plugin-openapi that bun's isolated install doesn't hoist into either app's node_modules, so a bare "js-yaml" specifier silently fails to resolve in optimizeDeps.include. Used vite's "<pkg> > <dep>" nested resolution syntax to resolve it from the owning package instead.

Rhys Sullivan committed 4 months ago

Commit a707e861 parent 8cc1e3f2 files · +65 −0Browse files

Unified · Split

2 files
  1. apps/cloud/vite.config.ts +42 −0
  2. apps/host-selfhost/vite.config.ts +23 −0
apps/cloud/vite.config.ts+42−0
@@ -65,6 +65,32 @@ export default defineConfig(({ command, mode }) => { · 64 unmodified lines
65 delete (publicEnv as Record<string, string | undefined>).VITE_PUBLIC_OTLP_TRACES_URL;65 delete (publicEnv as Record<string, string | undefined>).VITE_PUBLIC_OTLP_TRACES_URL;
66 }66 }
67 67
68 // Deps vite only discovers once a lazy-loaded React chunk actually renders
69 // (e.g. opening the MCP/OpenAPI "add source" flow). Discovering them mid-run
70 // forces a re-optimize + full program reload; in workerd (apps/cloud's SSR
71 // worker) each reload stacks a new isolate's heap on top of the last one
72 // without freeing it, so a handful of reloads exhausts the worker's heap
73 // limit and crashes the dev server. Pre-bundling them at boot means vite
74 // never discovers them mid-run, so it never reloads. Keep this list scoped
75 // to deps actually imported by UI code (grep `from "effect/` under
76 // packages/react/src and packages/plugins/*/src/react, plus js-yaml pulled
77 // in via packages/plugins/openapi/src/sdk) rather than including the world.
78 // js-yaml is a transitive dep (via @executor-js/plugin-openapi), not hoisted
79 // into apps/cloud/node_modules under bun's isolated install, so a plain
80 // "js-yaml" specifier fails to resolve here and silently falls out of the
81 // pre-bundle. The "<pkg> > <dep>" syntax resolves it starting from that
82 // package's own node_modules instead.
83 const lateDiscoveredDeps = [
84 "effect/Match",
85 "effect/Predicate",
86 "effect/Exit",
87 "effect/Option",
88 "effect/Cause",
89 "effect/Data",
90 "effect/Schema",
91 "@executor-js/plugin-openapi > js-yaml",
92 ];
93
68 return {94 return {
69 define: Object.fromEntries(95 define: Object.fromEntries(
70 Object.entries(publicEnv)96 Object.entries(publicEnv)
@@ -81,6 +107,22 @@ export default defineConfig(({ command, mode }) => { · 10 unmodified lines
81 },107 },
82 },108 },
83 resolve: { tsconfigPaths: true },109 resolve: { tsconfigPaths: true },
110 // Client-side pre-bundle. See lateDiscoveredDeps comment above.
111 optimizeDeps: {
112 include: lateDiscoveredDeps,
113 },
114 // SSR/worker-side pre-bundle for the same deps, keyed under the "ssr"
115 // environment name that `cloudflare({ viteEnvironment: { name: "ssr" } })`
116 // below uses. The cloudflare plugin sets its own environments.ssr.optimizeDeps
117 // (entries/exclude for worker externals); vite merges include arrays rather
118 // than replacing them, so this only adds to that, it doesn't fight it.
119 environments: {
120 ssr: {
121 optimizeDeps: {
122 include: lateDiscoveredDeps,
123 },
124 },
125 },
84 plugins: [126 plugins: [
85 devCrashGuard(),127 devCrashGuard(),
86 tailwindcss(),128 tailwindcss(),
apps/host-selfhost/vite.config.ts+23−0
@@ -190,6 +190,29 @@ export default defineConfig({ · 189 unmodified lines
190 alias: { "@executor-app": APP_ROOT },190 alias: { "@executor-app": APP_ROOT },
191 dedupe: ["react", "react-dom"],191 dedupe: ["react", "react-dom"],
192 },192 },
193 // This SPA shares packages/app's shell and packages/react's lazy-loaded
194 // "add source" UI with apps/cloud, so the same deps only surface once a
195 // lazy chunk actually renders (e.g. opening the MCP/OpenAPI add-source
196 // flow). Pre-bundle them at boot so vite never discovers them mid-run and
197 // never has to re-optimize + reload. No SSR/worker environment here (this
198 // app has no cloudflare plugin, it's a plain SPA build), so only the
199 // client optimizeDeps applies. Keep in sync with apps/cloud/vite.config.ts.
200 // js-yaml is a transitive dep (via @executor-js/plugin-openapi) that isn't
201 // hoisted into this app's node_modules under bun's isolated install, so a
202 // plain "js-yaml" specifier fails to resolve; "<pkg> > <dep>" resolves it
203 // from that package's own node_modules instead.
204 optimizeDeps: {
205 include: [
206 "effect/Match",
207 "effect/Predicate",
208 "effect/Exit",
209 "effect/Option",
210 "effect/Cause",
211 "effect/Data",
212 "effect/Schema",
213 "@executor-js/plugin-openapi > js-yaml",
214 ],
215 },
193 define: {216 define: {
194 "import.meta.env.VITE_APP_VERSION": JSON.stringify(EXECUTOR_VERSION ?? "0.0.0"),217 "import.meta.env.VITE_APP_VERSION": JSON.stringify(EXECUTOR_VERSION ?? "0.0.0"),
195 // Self-host upgrades by pulling/rebuilding the image (or git + rebuild), not218 // Self-host upgrades by pulling/rebuilding the image (or git + rebuild), not