Fix tsconfig.json update causing the server to crash (#8736)

This commit is contained in:
Bjorn Lu 2023-10-03 21:36:38 +08:00 committed by Martin Trapp
parent d125095d09
commit cb62f02ea1
3 changed files with 52 additions and 16 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix `tsconfig.json` update causing the server to crash

View file

@ -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;
}
}
}

View file

@ -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) {
@ -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);
};
}