Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
};
}
Loading