On first dev start Vite crawls the entry HTML and source to find bare imports, converts each dependency to ESM with esbuild, and caches the result under node_modules/.vite. This is what makes the unbundled dev server fast: one request per dependency instead of hundreds.
When a dependency is only reachable through a dynamic import, a conditional branch, or a linked workspace package, the crawl misses it. Vite discovers it at request time, logs new dependencies optimized: <name> and forces a full page reload, losing hot module replacement state. In a large app this can happen repeatedly during the first minutes of a session.
List the stragglers in optimizeDeps.include so they are bundled up front. Linked packages are excluded from pre-bundling by default because they are expected to change, which is why a monorepo sibling often needs an explicit include entry. When the cache goes stale after a dependency change, vite --force rebuilds it; deleting node_modules/.vite does the same thing.