From 0c026056036a0a504d065bd115f5bafc57261a1f Mon Sep 17 00:00:00 2001 From: dominikg Date: Thu, 9 Jun 2022 11:02:15 +0200 Subject: [PATCH] fix: track compile errors in cache and send hmr update when returning to last working state --- .changeset/nervous-jobs-remain.md | 5 ++ .../src/handle-hot-update.ts | 24 ++++++---- packages/vite-plugin-svelte/src/index.ts | 7 ++- .../src/utils/vite-plugin-svelte-cache.ts | 46 ++++++++++++++----- 4 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 .changeset/nervous-jobs-remain.md diff --git a/.changeset/nervous-jobs-remain.md b/.changeset/nervous-jobs-remain.md new file mode 100644 index 000000000..bf8014c12 --- /dev/null +++ b/.changeset/nervous-jobs-remain.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': patch +--- + +fix hmr not updating a component when returning to the last working state from an error state diff --git a/packages/vite-plugin-svelte/src/handle-hot-update.ts b/packages/vite-plugin-svelte/src/handle-hot-update.ts index b23788b7a..cfe2f7754 100644 --- a/packages/vite-plugin-svelte/src/handle-hot-update.ts +++ b/packages/vite-plugin-svelte/src/handle-hot-update.ts @@ -15,19 +15,25 @@ export async function handleHotUpdate( cache: VitePluginSvelteCache, options: ResolvedOptions ): Promise { - const { read, server } = ctx; - - const cachedJS = cache.getJS(svelteRequest); - if (!cachedJS) { + if (!cache.has(svelteRequest)) { // file hasn't been requested yet (e.g. async component) - log.debug(`handleHotUpdate first call ${svelteRequest.id}`); + log.debug(`handleHotUpdate called before initial transform for ${svelteRequest.id}`); return; } + const { read, server } = ctx; + + const cachedJS = cache.getJS(svelteRequest); const cachedCss = cache.getCSS(svelteRequest); const content = await read(); - const compileData: CompileData = await compileSvelte(svelteRequest, content, options); - cache.update(compileData); + let compileData: CompileData; + try { + compileData = await compileSvelte(svelteRequest, content, options); + cache.update(compileData); + } catch (e) { + cache.setError(svelteRequest, e); + throw e; + } const affectedModules = new Set(); @@ -35,13 +41,13 @@ export async function handleHotUpdate( const mainModule = server.moduleGraph.getModuleById(svelteRequest.id); const cssUpdated = cssModule && cssChanged(cachedCss, compileData.compiled.css); if (cssUpdated) { - log.debug('handleHotUpdate css changed'); + log.debug(`handleHotUpdate css changed for ${svelteRequest.cssId}`); affectedModules.add(cssModule); } const jsUpdated = mainModule && jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename); if (jsUpdated) { - log.debug('handleHotUpdate js changed'); + log.debug(`handleHotUpdate js changed for ${svelteRequest.id}`); affectedModules.add(mainModule); } diff --git a/packages/vite-plugin-svelte/src/index.ts b/packages/vite-plugin-svelte/src/index.ts index 09f8eb717..3aad3ba7b 100644 --- a/packages/vite-plugin-svelte/src/index.ts +++ b/packages/vite-plugin-svelte/src/index.ts @@ -183,6 +183,7 @@ export function svelte(inlineOptions?: Partial): Plugin[] { try { compileData = await compileSvelte(svelteRequest, code, options); } catch (e) { + cache.setError(svelteRequest, e); throw toRollupError(e, options); } logCompilerWarnings(compileData.compiled.warnings, options); @@ -209,7 +210,11 @@ export function svelte(inlineOptions?: Partial): Plugin[] { } const svelteRequest = requestParser(ctx.file, false, ctx.timestamp); if (svelteRequest) { - return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options); + try { + return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options); + } catch (e) { + throw toRollupError(e, options); + } } } } diff --git a/packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-cache.ts b/packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-cache.ts index 030b9bcd4..167bbddea 100644 --- a/packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-cache.ts +++ b/packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-cache.ts @@ -7,13 +7,27 @@ export class VitePluginSvelteCache { private _dependencies = new Map(); private _dependants = new Map>(); private _resolvedSvelteFields = new Map(); + private _errors = new Map(); public update(compileData: CompileData) { + this._errors.delete(compileData.normalizedFilename); this.updateCSS(compileData); this.updateJS(compileData); this.updateDependencies(compileData); } + public has(svelteRequest: SvelteRequest) { + const id = svelteRequest.normalizedFilename; + return this._errors.has(id) || this._js.has(id) || this._css.has(id); + } + + public setError(svelteRequest: SvelteRequest, error: any) { + // keep dependency info, otherwise errors in dependants would not trigger an update after fixing + // because they are no longer watched + this.remove(svelteRequest, true); + this._errors.set(svelteRequest.normalizedFilename, error); + } + private updateCSS(compileData: CompileData) { this._css.set(compileData.normalizedFilename, compileData.compiled.css); } @@ -43,26 +57,32 @@ export class VitePluginSvelteCache { }); } - public remove(svelteRequest: SvelteRequest): boolean { + public remove(svelteRequest: SvelteRequest, keepDependencies: boolean = false): boolean { const id = svelteRequest.normalizedFilename; let removed = false; + if (this._errors.delete(id)) { + removed = true; + } if (this._js.delete(id)) { removed = true; } if (this._css.delete(id)) { removed = true; } - const dependencies = this._dependencies.get(id); - if (dependencies) { - removed = true; - dependencies.forEach((d) => { - const dependants = this._dependants.get(d); - if (dependants && dependants.has(svelteRequest.filename)) { - dependants.delete(svelteRequest.filename); - } - }); - this._dependencies.delete(id); + if (!keepDependencies) { + const dependencies = this._dependencies.get(id); + if (dependencies) { + removed = true; + dependencies.forEach((d) => { + const dependants = this._dependants.get(d); + if (dependants && dependants.has(svelteRequest.filename)) { + dependants.delete(svelteRequest.filename); + } + }); + this._dependencies.delete(id); + } } + return removed; } @@ -77,6 +97,10 @@ export class VitePluginSvelteCache { } } + public getError(svelteRequest: SvelteRequest) { + return this._errors.get(svelteRequest.normalizedFilename); + } + public getDependants(path: string): string[] { const dependants = this._dependants.get(path); return dependants ? [...dependants] : [];