UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

96 lines (95 loc) • 4.78 kB
import { manifest } from "virtual:astro:manifest"; import { clearActions } from "../actions/load.js"; import { getPackageManager } from "../cli/info/core/get-package-manager.js"; import { DevDebugInfoProvider } from "../cli/info/infra/dev-debug-info-provider.js"; import { ProcessNodeVersionProvider } from "../cli/info/infra/process-node-version-provider.js"; import { ProcessPackageManagerUserAgentProvider } from "../cli/info/infra/process-package-manager-user-agent-provider.js"; import { StyledDebugInfoFormatter } from "../cli/info/infra/styled-debug-info-formatter.js"; import { BuildTimeAstroVersionProvider } from "../cli/infra/build-time-astro-version-provider.js"; import { PassthroughTextStyler } from "../cli/infra/passthrough-text-styler.js"; import { ProcessOperatingSystemProvider } from "../cli/infra/process-operating-system-provider.js"; import { TinyexecCommandExecutor } from "../cli/infra/tinyexec-command-executor.js"; import { DevFacadeApp } from "../core/app/dev-facade.js"; import { setEnvironment } from "../core/environment/index.js"; import { createNodeLoggerFromFlags } from "../core/logger/impls/node.js"; import { setLogger } from "../core/logger/manifest-logger.js"; import { clearMiddleware } from "../core/middleware/load.js"; import { getRouteCache } from "../core/render/route-cache.js"; import { updateRouteTable } from "../core/routing/route-table.js"; import { createRunnableEnvironment } from "./environment.js"; import { handleDevRequest } from "./handle-request.js"; export default async function createAstroServerApp(controller, settings, loader, logger) { const actualLogger = logger ?? createNodeLoggerFromFlags({}); const debugInfoProvider = new DevDebugInfoProvider({ config: settings.config, astroVersionProvider: new BuildTimeAstroVersionProvider(), operatingSystemProvider: new ProcessOperatingSystemProvider(), packageManager: await getPackageManager({ packageManagerUserAgentProvider: new ProcessPackageManagerUserAgentProvider(), commandExecutor: new TinyexecCommandExecutor() }), nodeVersionProvider: new ProcessNodeVersionProvider() }); const debugInfoFormatter = new StyledDebugInfoFormatter({ textStyler: new PassthroughTextStyler() }); const debugInfo = debugInfoFormatter.format(await debugInfoProvider.get()); // Composition order: logger → environment → facade ctor // (which warms the route table from `manifest.routes` — in dev that IS the // live array behind `virtual:astro:routes`, so no separate routes import // is needed) → HMR wiring. The ModuleLoader and AstroSettings are captured // in the environment closure and in `deps`; they are unreachable from // requests/states. setLogger(manifest, actualLogger); setEnvironment(manifest, createRunnableEnvironment({ loader, settings, getDebugInfo: async () => debugInfo })); const app = new DevFacadeApp(manifest, true); const deps = { loader, settings, controller }; // The HMR listeners target the MANIFEST via the functional core: one // atomic route-table replacement is visible to every consumer — matcher, // custom-404 fallback, rewrites, error-page lookups, and the // `manifestData` accessors — at once. if (import.meta.hot) { import.meta.hot.on("astro:routes-updated", async () => { try { // Re-import the routes module to get fresh routes const { routes: newRoutes } = await import("virtual:astro:routes"); updateRouteTable(manifest, newRoutes.map((route) => route.routeData)); actualLogger.debug("router", "Routes updated via HMR"); } catch (e) { actualLogger.error("router", `Failed to update routes via HMR:\n ${e}`); } }); // Listen for content collection changes via HMR. // Clear the route cache so getStaticPaths() is re-evaluated with fresh data. import.meta.hot.on("astro:content-changed", () => { getRouteCache(manifest).clearAll(); actualLogger.debug("router", "Route cache cleared due to content change"); }); // Listen for middleware file changes via HMR. // Clear the cached middleware so it is re-resolved on the next request. import.meta.hot.on("astro:middleware-updated", () => { clearMiddleware(manifest); actualLogger.debug("router", "Middleware cache cleared due to file change"); }); // Listen for action file changes via HMR. // Clear the cached actions so they are re-resolved on the next request. import.meta.hot.on("astro:actions-updated", () => { clearActions(manifest); actualLogger.debug("router", "Actions cache cleared due to file change"); }); } return { handler(incomingRequest, incomingResponse, options) { return handleDevRequest(app, deps, { incomingRequest, incomingResponse, isHttps: loader?.isHttps() ?? false, prerenderOnly: options?.prerenderOnly }); } }; }