Repository: withastro/astro
File: packages/astro/src/vite-plugin-astro-server/plugin.ts (TypeScript)

Code before:
				loader,
				logger,
				manifest: devSSRManifest,
				settings,
			});
			const controller = createController({ loader });
			const localStorage = new AsyncLocalStorage();

			/** rebuild the route cache + manifest */
			async function rebuildManifest() {
				pipeline.clearRouteCache();
				routeManifest = injectDefaultDevRoutes(
					settings,
					devSSRManifest,
					await createRouteManifest({ settings, fsMod }, logger), // TODO: Handle partial updates to the manifest
				);
				warnMissingAdapter(logger, settings);
				pipeline.manifest.checkOrigin =
					settings.config.security.checkOrigin && settings.buildOutput === 'server';
				pipeline.setManifestData(routeManifest);
			}

			// Rebuild route manifest on file change
			viteServer.watcher.on('add', rebuildManifest.bind(null));
			viteServer.watcher.on('unlink', rebuildManifest.bind(null));
			viteServer.watcher.on('change', rebuildManifest.bind(null));

			function handleUnhandledRejection(rejection: any) {
				const error = new AstroError({
					...AstroErrorData.UnhandledRejection,
					message: AstroErrorData.UnhandledRejection.message(rejection?.stack || rejection),
				});
				const store = localStorage.getStore();
				if (store instanceof IncomingMessage) {
					const request = store;
					setRouteError(controller.state, request.url!, error);
				}
				const { errorWithMetadata } = recordServerError(loader, settings.config, pipeline, error);
				setTimeout(
					async () => loader.webSocketSend(await getViteErrorPayload(errorWithMetadata)),
					200,
				);
			}

			process.on('unhandledRejection', handleUnhandledRejection);
			viteServer.httpServer?.on('close', () => {
				process.off('unhandledRejection', handleUnhandledRejection);
			});

			return () => {
				// Push this middleware to the front of the stack so that it can intercept responses.

Review comment (performance):
I get why the optimization was removed, but isn't it too drastic?

The entire route manifest will be recomputed on every change anywhere. Even tho it will most likely not change anything in the routes.
- `add` changes routes, that's fine
- `unlink` changes routes, that's fine
- `change` only changes routes if the change adds, removes, or alters the `export const prerender` line.

Editing content will repeatedly recompute the routes, which includes reading all the files in the routes for the pretender parameter. That will make the dev server quite inefficient.

I think we should at least check to make sure that changes to files outside of the pages directory won't recompute the routes so that editing content doesn't consume that much extra resource on every save. I think the event value provided by the Chokidar API includes which file was changed

Code after:
		name: 'astro:server',
		configureServer(viteServer) {
			const loader = createViteLoader(viteServer);
			const pipeline = DevPipeline.create(routeManifest, {
				loader,
				logger,
				manifest: devSSRManifest,
				settings,
			});
			const controller = createController({ loader });
			const localStorage = new AsyncLocalStorage();

			/** rebuild the route cache + manifest */
			async function rebuildManifest(path: string | null = null) {
				pipeline.clearRouteCache();

				// If a route changes, we check if it's part of the manifest and check for its prerender value
				if (path !== null) {
					const route = routeManifest.routes.find(
						(r) =>
							normalizePath(path) ===
							normalizePath(fileURLToPath(new URL(r.component, settings.config.root))),
					);
					if (!route) {
						return;
					}
					if (route.type !== 'page' && route.type !== 'endpoint') return;

					const routePath = fileURLToPath(new URL(route.component, settings.config.root));
					try {
						const content = await fsMod.promises.readFile(routePath, 'utf-8');
						await getRoutePrerenderOption(content, route, settings, logger);
					} catch (_) {}
				} else {
					routeManifest = injectDefaultDevRoutes(
						settings,
						devSSRManifest,
						await createRouteManifest({ settings, fsMod }, logger, { dev: true }),
					);
				}
				await runHookRoutesResolved({ routes: routeManifest.routes, settings, logger });

				warnMissingAdapter(logger, settings);
				pipeline.manifest.checkOrigin =
					settings.config.security.checkOrigin && settings.buildOutput === 'server';
				pipeline.setManifestData(routeManifest);
			}

			// Rebuild route manifest on file change
			viteServer.watcher.on('add', rebuildManifest.bind(null, null));
			viteServer.watcher.on('unlink', rebuildManifest.bind(null, null));