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.
Unified · Split
| @@ -65,6 +65,32 @@ export default defineConfig(({ command, mode }) => { · 64 unmodified lines | ||
| 65 | 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 | 94 | return { |
| 69 | 95 | define: Object.fromEntries( |
| 70 | 96 | Object.entries(publicEnv) |
| @@ -81,6 +107,22 @@ export default defineConfig(({ command, mode }) => { · 10 unmodified lines | ||
| 81 | 107 | }, |
| 82 | 108 | }, |
| 83 | 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 | 126 | plugins: [ |
| 85 | 127 | devCrashGuard(), |
| 86 | 128 | tailwindcss(), |
| @@ -190,6 +190,29 @@ export default defineConfig({ · 189 unmodified lines | ||
| 190 | 190 | alias: { "@executor-app": APP_ROOT }, |
| 191 | 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 | 216 | define: { |
| 194 | 217 | "import.meta.env.VITE_APP_VERSION": JSON.stringify(EXECUTOR_VERSION ?? "0.0.0"), |
| 195 | 218 | // Self-host upgrades by pulling/rebuilding the image (or git + rebuild), not |