Skip to content

Brian B. Tung

[EmDash] Note `ssr.optimizeDeps.include` Fixes Vite 7's SSR Dep Optimizer Race Condition and Stale Chunk Crashes on Cloudflare Workers

When I migrated my personal site to Astro 6 + EmDash CMS on Cloudflare Workers, I hit a dev-server crash that took a while to diagnose. Every time I ran `pnpm dev:ui`, the first request would return many errors about missing chunk files. This post explains what was happening, what I tried that didn't work, and the fix that actually solved it.

The Stack

  • Astro 6.3.3
  • Vite 7.3.3 (pinned via `pnpm.overrides` — Astro 6's bundled rolldown-vite breaks `@cloudflare/vite-plugin`)
  • EmDash CMS 0.10.0 (`emdash` + `@emdash-cms/cloudflare`)
  • `@astrojs/cloudflare` adapter with `remoteBindings: true`
  • `@cloudflare/vite-plugin` 1.37.0
  • Miniflare 4.20260511.0 (embedded in the Cloudflare plugin)

The Error

[vite] ✨ new dependencies optimized: emdash/middleware, emdash/middleware/redirect,
       emdash/middleware/setup, emdash/middleware/auth, emdash/middleware/request-context
[vite] ✨ optimized dependencies changed. reloading
[vite] ✨ new dependencies optimized: @emdash-cms/cloudflare/db/d1, emdash/ui
[vite] ✨ optimized dependencies changed. reloading
[vite] ✨ new dependencies optimized: emdash/media/local-runtime
[vite] ✨ optimized dependencies changed. reloading
[vite] ✨ new dependencies optimized: @emdash-cms/cloudflare/storage/r2
[vite] ✨ optimized dependencies changed. reloading
[vite] An error happened during full reload
The file does not exist at
  ".../node_modules/.vite/deps_ssr/chunk-GGAS75JV.js?v=d3e10cf3"
which is in the optimize deps directory. The dependency might be
incompatible with the dep optimizer. Try adding it to `optimizeDeps.exclude`.

And from inside the EmDash admin, two follow-on warnings:

[emdash] Failed to hydrate bylines: The file does not exist at
  ".../deps_ssr/bylines-esI7ioa9-Z3OQX3NW.js?v=98f1f127"
[emdash] Failed to hydrate terms: The file does not exist at
  ".../deps_ssr/taxonomies-CTtewrSQ-Z5QGP4FL.js?v=98f1f127"

Understanding the Scene: Two Separate Optimizers

In Vite 5 and earlier, `optimizeDeps` settings were largely shared between browser and SSR environments. Vite 7 separates them completely.

  • `optimizeDeps` — controls pre-bundling for the browser/client environment
  • `ssr.optimizeDeps` — controls pre-bundling for the SSR environment

They're independent. Setting `optimizeDeps.exclude: ["emdash"]` only excluded EmDash from the client optimizer. The SSR optimizer was still free to lazily discover and re-optimize sub-paths at request time.

The Fix: `ssr.optimizeDeps.include`

The correct lever is `ssr.optimizeDeps.include`. This tells Vite to force-include specific packages in the initial SSR optimization scan — before any request is served.

vite: {
  plugins: [tailwindcss()],
  optimizeDeps: {
    exclude: ["emdash"],
  },
  ssr: {
    optimizeDeps: {
      include: [
        "emdash/middleware",
        "emdash/middleware/auth",
        "emdash/middleware/redirect",
        "emdash/middleware/request-context",
        "emdash/middleware/setup",
        "emdash/runtime",
        "emdash/ui",
        "emdash/media/local-runtime",
        "@emdash-cms/cloudflare/db/d1",
        "@emdash-cms/cloudflare/storage/r2",
        "astro/zod",
      ],
    },
  },
},

Why This Works

By listing the packages in `ssr.optimizeDeps.include`, Vite pulls them into the startup optimization pass before the dev server accepts requests. That eliminates lazy discovery rounds, stale chunk invalidations, and mid-request hash churn.

The SSR optimizer still performs its CJS→ESM transformation work — it just does it upfront in a single pass instead of reactively during requests.