Skip to content

Commit

Permalink
Fix tsconfig.json update causing the server to crash (#8736)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored Oct 3, 2023
1 parent f9477aa commit d1c75fe
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/red-masks-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix `tsconfig.json` update causing the server to crash
12 changes: 9 additions & 3 deletions packages/astro/src/content/vite-plugin-content-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,15 @@ export const _internal = {
hasContentFlag(modUrl, DATA_FLAG) ||
Boolean(getContentRendererByViteId(modUrl, settings))
) {
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
if (mod) {
viteServer.moduleGraph.invalidateModule(mod);
try {
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
if (mod) {
viteServer.moduleGraph.invalidateModule(mod);
}
} catch (e: any) {
// The server may be closed due to a restart caused by this file change
if (e.code === 'ERR_CLOSED_SERVER') break;
throw e;
}
}
}
Expand Down
51 changes: 38 additions & 13 deletions packages/astro/src/core/module-loader/vite.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
import { EventEmitter } from 'node:events';
import path from 'node:path';
import type * as vite from 'vite';
import type { ModuleLoader, ModuleLoaderEventEmitter } from './loader.js';

export function createViteLoader(viteServer: vite.ViteDevServer): ModuleLoader {
const events = new EventEmitter() as ModuleLoaderEventEmitter;

viteServer.watcher.on('add', (...args) => events.emit('file-add', args));
viteServer.watcher.on('unlink', (...args) => events.emit('file-unlink', args));
viteServer.watcher.on('change', (...args) => events.emit('file-change', args));
let isTsconfigUpdated = false;
function isTsconfigUpdate(filePath: string) {
const result = path.basename(filePath) === 'tsconfig.json';
if (result) isTsconfigUpdated = true;
return result;
}

wrapMethod(viteServer.ws, 'send', (msg) => {
// Skip event emit on tsconfig change as Vite restarts the server, and we don't
// want to trigger unnecessary work that will be invalidated shortly.
viteServer.watcher.on('add', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-add', args);
}
});
viteServer.watcher.on('unlink', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-unlink', args);
}
});
viteServer.watcher.on('change', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-change', args);
}
});

const _wsSend = viteServer.ws.send;
viteServer.ws.send = function (...args: any) {
// If the tsconfig changed, Vite will trigger a reload as it invalidates the module.
// However in Astro, the whole server is restarted when the tsconfig changes. If we
// do a restart and reload at the same time, the browser will refetch and the server
// is not ready yet, causing a blank page. Here we block that reload from happening.
if (isTsconfigUpdated) {
isTsconfigUpdated = false;
return;
}
const msg = args[0] as vite.HMRPayload;
if (msg?.type === 'error') {
events.emit('hmr-error', msg);
}
});
_wsSend.apply(this, args);
};

return {
import(src) {
Expand Down Expand Up @@ -56,11 +89,3 @@ export function createViteLoader(viteServer: vite.ViteDevServer): ModuleLoader {
events,
};
}

function wrapMethod(object: any, method: string, newFn: (...args: any[]) => void) {
const orig = object[method];
object[method] = function (...args: any[]) {
newFn.apply(this, args);
return orig.apply(this, args);
};
}

0 comments on commit d1c75fe

Please sign in to comment.