Skip to content

Commit

Permalink
fix: track compile errors in cache and send hmr update when returning…
Browse files Browse the repository at this point in the history
… to last working state (#371)
  • Loading branch information
dominikg committed Jun 9, 2022
1 parent 1e55af3 commit 696e2e1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .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
24 changes: 15 additions & 9 deletions packages/vite-plugin-svelte/src/handle-hot-update.ts
Expand Up @@ -15,33 +15,39 @@ export async function handleHotUpdate(
cache: VitePluginSvelteCache,
options: ResolvedOptions
): Promise<ModuleNode[] | void> {
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<ModuleNode | undefined>();

const cssModule = server.moduleGraph.getModuleById(svelteRequest.cssId);
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);
}

Expand Down
7 changes: 6 additions & 1 deletion packages/vite-plugin-svelte/src/index.ts
Expand Up @@ -183,6 +183,7 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin[] {
try {
compileData = await compileSvelte(svelteRequest, code, options);
} catch (e) {
cache.setError(svelteRequest, e);
throw toRollupError(e, options);
}
logCompilerWarnings(compileData.compiled.warnings, options);
Expand All @@ -209,7 +210,11 @@ export function svelte(inlineOptions?: Partial<Options>): 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);
}
}
}
}
Expand Down
46 changes: 35 additions & 11 deletions packages/vite-plugin-svelte/src/utils/vite-plugin-svelte-cache.ts
Expand Up @@ -7,13 +7,27 @@ export class VitePluginSvelteCache {
private _dependencies = new Map<string, string[]>();
private _dependants = new Map<string, Set<string>>();
private _resolvedSvelteFields = new Map<string, string>();
private _errors = new Map<string, any>();

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);
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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] : [];
Expand Down

0 comments on commit 696e2e1

Please sign in to comment.