diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index da446597fd68ba..f7291c03b01c91 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -173,6 +173,14 @@ export interface DevOptions { */ createEnvironment?: (server: ViteDevServer, name: string) => DevEnvironment + /** + * For environments that support a full-reload, like the client, we can short-circuit when + * restarting the server throwing early to stop processing current files. We avoided this for + * SSR requests. Maybe this is no longer needed. + * @experimental + */ + recoverable?: boolean + /** * Defaults to true for the client environment and false for others, following node permissive * security model. @@ -526,6 +534,7 @@ export type ResolvedConfig = Readonly< export function resolveDevOptions( dev: DevOptions | undefined, preserverSymlinks: boolean, + environmentName: string | undefined, ): ResolvedDevOptions { return { sourcemap: dev?.sourcemap ?? { js: true }, @@ -542,6 +551,7 @@ export function resolveDevOptions( preserverSymlinks, ), createEnvironment: dev?.createEnvironment, + recoverable: dev?.recoverable ?? environmentName === 'client', } } @@ -556,7 +566,11 @@ function resolveEnvironmentOptions( resolve, nodeCompatible: config.nodeCompatible ?? environmentName !== 'client', webCompatible: config.webCompatible ?? environmentName === 'client', - dev: resolveDevOptions(config.dev, resolve.preserveSymlinks), + dev: resolveDevOptions( + config.dev, + resolve.preserveSymlinks, + environmentName, + ), build: resolveBuildOptions( config.build, logger, @@ -890,9 +904,12 @@ export async function resolveConfig( }, } + // TODO: Deprecate and remove resolve, dev and build options at the root level of the resolved config + const resolvedDevOptions = resolveDevOptions( config.dev, resolvedDefaultEnvironmentResolve.preserveSymlinks, + undefined, // default environment ) const resolvedBuildOptions = resolveBuildOptions( diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts index 36be718aeba110..c1eef122fd0587 100644 --- a/packages/vite/src/node/server/pluginContainer.ts +++ b/packages/vite/src/node/server/pluginContainer.ts @@ -716,7 +716,8 @@ export async function createPluginContainer( let id: string | null = null const partial: Partial = {} for (const plugin of getSortedPlugins('resolveId')) { - if (closed && !ssr) throwClosedServerError() + if (closed && environment?.options.dev.recoverable) + throwClosedServerError() if (!plugin.resolveId) continue if (skip?.has(plugin)) continue @@ -779,7 +780,8 @@ export async function createPluginContainer( ctx.ssr = !!ssr ctx.environment = environment for (const plugin of getSortedPlugins('load')) { - if (closed && !ssr) throwClosedServerError() + if (closed && environment?.options.dev.recoverable) + throwClosedServerError() if (!plugin.load) continue ctx._activePlugin = plugin const handler = getHookHandler(plugin.load) @@ -810,7 +812,8 @@ export async function createPluginContainer( ctx.ssr = !!ssr ctx.environment = environment for (const plugin of getSortedPlugins('transform')) { - if (closed && !ssr) throwClosedServerError() + if (closed && environment?.options.dev.recoverable) + throwClosedServerError() if (!plugin.transform) continue ctx._activePlugin = plugin ctx._activeId = id diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index 6c5640f93f57c9..6e67a0e1ff829b 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -70,7 +70,8 @@ export function transformRequest( options = { ...options, ssr: environment.name !== 'client' } } - if (server._restartPromise && !options.ssr) throwClosedServerError() + if (server._restartPromise && environment?.options.dev.recoverable) + throwClosedServerError() // We could have a cache per environment instead of the global _pendingRequests const cacheKey = `${options.html ? 'html:' : ''}${environment.name}:${url}` @@ -343,7 +344,8 @@ async function loadAndTransform( throw err } - if (server._restartPromise && !ssr) throwClosedServerError() + if (server._restartPromise && environment.options.dev.recoverable) + throwClosedServerError() // ensure module in graph after successful load mod ??= await moduleGraph._ensureEntryFromUrl(url, undefined, resolved) @@ -416,7 +418,8 @@ async function loadAndTransform( } } - if (server._restartPromise && !ssr) throwClosedServerError() + if (server._restartPromise && environment.options.dev.recoverable) + throwClosedServerError() const result = ssr && !server.config.experimental.skipSsrTransform