Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-config-reload-cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@zpress/cli': patch
---

Fix config changes not propagating during dev

Disable Rspress's persistent build cache on config-reload restarts. The cache's digest only tracks sidebar/nav structure, so changes to title, theme, colors, and other `source.define` values were invisible to it, causing stale output to be served after a restart.
44 changes: 40 additions & 4 deletions packages/cli/src/lib/rspress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ interface ServerInstance {
readonly close: () => Promise<void>
}

/**
* Internal options for `startServer` that control rebuild behaviour.
*/
interface StartServerOptions {
/** When true, disables the persistent build cache for this invocation. */
readonly skipBuildCache: boolean
}

/**
* Callback invoked when the dev server should restart due to config changes.
*/
Expand All @@ -66,7 +74,10 @@ export async function startDevServer(
// oxlint-disable-next-line functional/no-let -- mutable server instance for restart capability
let serverInstance: ServerInstance | null = null

async function startServer(config: ZpressConfig): Promise<boolean> {
async function startServer(
config: ZpressConfig,
internalOptions: StartServerOptions
): Promise<boolean> {
const rspressConfig = createRspressConfig({
config,
paths,
Expand All @@ -85,6 +96,11 @@ export async function startDevServer(
port,
strictPort: true,
},
// Disable persistent build cache on config-reload restarts.
// Rspress's cacheDigest only covers sidebar/nav structure,
// so changes to title, theme, colors, source.define values
// etc. would serve stale cached output without this.
...buildCacheOverride(internalOptions),
},
})
return true
Expand All @@ -95,7 +111,7 @@ export async function startDevServer(
}

// Start initial server — exit if it fails on first boot
const started = await startServer(options.config)
const started = await startServer(options.config, { skipBuildCache: false })
if (!started) {
process.exit(1)
}
Expand Down Expand Up @@ -128,8 +144,8 @@ export async function startDevServer(
serverInstance = null
}

// Start new server with fresh config
const restarted = await startServer(newConfig)
// Start new server with fresh config (bypass persistent cache)
const restarted = await startServer(newConfig, { skipBuildCache: true })
if (restarted) {
process.stdout.write('✅ Dev server restarted\n\n')
} else {
Expand Down Expand Up @@ -233,6 +249,26 @@ function createCloseEvent(httpServer: Server | null): Promise<unknown[]> | null
return once(httpServer, 'close')
}

/**
* Return a performance config override that disables persistent build cache
* on config-reload restarts.
*
* Rspress's persistent cache (`buildCache.cacheDigest`) only tracks sidebar/nav
* structure. Changes to title, theme, colors, and `source.define` values are
* invisible to it, causing stale cached output. Disabling the cache on restart
* forces a fresh Rsbuild compilation with the updated config values.
*
* @private
* @param options - Internal server options
* @returns Partial Rsbuild config with cache override, or empty object
*/
function buildCacheOverride(options: StartServerOptions): Record<string, unknown> {
if (options.skipBuildCache) {
return { performance: { buildCache: false } }
}
return {}
}

/**
* Extract the underlying HTTP server from a Rspress/Rsbuild server instance.
*
Expand Down
Loading