diff --git a/.changeset/vite-cache-dir.md b/.changeset/vite-cache-dir.md new file mode 100644 index 000000000..7c4152edf --- /dev/null +++ b/.changeset/vite-cache-dir.md @@ -0,0 +1,5 @@ +--- +'@open-slide/core': patch +--- + +Store Vite's optimize-deps cache at the project root and clear it on in-app update, so upgrading no longer leaves the dev server failing on missing `.vite/deps` chunks. diff --git a/packages/core/src/vite/cache-dir.test.ts b/packages/core/src/vite/cache-dir.test.ts new file mode 100644 index 000000000..700098747 --- /dev/null +++ b/packages/core/src/vite/cache-dir.test.ts @@ -0,0 +1,10 @@ +import path from 'node:path'; +import { describe, expect, it } from 'vitest'; +import { resolveViteCacheDir } from './cache-dir.ts'; + +describe('resolveViteCacheDir', () => { + it('points at the user project root, not the installed core package', () => { + const cwd = path.join(path.sep, 'Users', 'david', 'slides'); + expect(resolveViteCacheDir(cwd)).toBe(path.join(cwd, 'node_modules', '.vite')); + }); +}); diff --git a/packages/core/src/vite/cache-dir.ts b/packages/core/src/vite/cache-dir.ts new file mode 100644 index 000000000..d2a8cfde0 --- /dev/null +++ b/packages/core/src/vite/cache-dir.ts @@ -0,0 +1,10 @@ +import path from 'node:path'; + +// Vite defaults its optimize-deps cache to `/node_modules/.vite`. +// Our `root` points inside the installed @open-slide/core package, so that default +// lands the cache under node_modules/@open-slide/core/node_modules/.vite — inside the +// very directory the in-app updater swaps out on upgrade, leaving Vite referencing +// chunks that no longer exist. Pin it to the user's project root instead. +export function resolveViteCacheDir(userCwd: string): string { + return path.join(userCwd, 'node_modules', '.vite'); +} diff --git a/packages/core/src/vite/config.ts b/packages/core/src/vite/config.ts index ac0286a83..e47c9a6b4 100644 --- a/packages/core/src/vite/config.ts +++ b/packages/core/src/vite/config.ts @@ -5,6 +5,7 @@ import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import type { InlineConfig } from 'vite'; import { apiPlugin } from './api-plugin.ts'; +import { resolveViteCacheDir } from './cache-dir.ts'; import { currentPlugin } from './current-plugin.ts'; import { designPlugin } from './design-plugin.ts'; import { locTagsPlugin } from './loc-tags-plugin.ts'; @@ -54,6 +55,7 @@ export async function createViteConfig(opts: CreateViteConfigOptions): Promise { }); } +// Drop Vite's optimize-deps cache so the post-update restart re-bundles against the +// freshly installed version. Vite keys that cache off a dep hash that doesn't reflect +// an @open-slide/core version bump (notably it can't read bun's text lockfile), so +// without this it keeps serving the previous version's deps. Best-effort: on Windows +// the outgoing server may still hold the files, and a stale cache only costs a manual +// restart, never correctness. +async function clearViteCache(cwd: string): Promise { + try { + await fs.rm(resolveViteCacheDir(cwd), { recursive: true, force: true }); + } catch {} +} + async function updatePackage(ctx: ApiContext): Promise { const packageManager = await detectPackageManager(ctx.userCwd); const updateCommand = updateCommandFor(packageManager); @@ -150,6 +163,7 @@ async function updatePackage(ctx: ApiContext): Promise { await runCommand(updateCommand, ctx.userCwd); await runCommand(syncCommand, ctx.userCwd); + await clearViteCache(ctx.userCwd); cache = null; const latest = await fetchLatest(Date.now());