astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
123 lines (122 loc) • 4.15 kB
JavaScript
import nodeFs from "node:fs";
import * as vite from "vite";
import { runHookConfigDone, runHookConfigSetup, runHookServerDone, runHookServerStart } from "../../integrations/hooks.js";
import { devServerAppReadySymbol } from "../constants.js";
import { createVite } from "../create-vite.js";
import { createRoutesList } from "../routing/create-manifest.js";
import { getPrerenderDefault } from "../../prerender/utils.js";
import { syncInternal } from "../sync/index.js";
import { warnMissingAdapter } from "./adapter-validation.js";
export async function createContainer({ isRestart = false, logger, inlineConfig, settings, fs = nodeFs }) {
// Initialize
settings = await runHookConfigSetup({
settings,
command: "dev",
logger,
isRestart
});
const { base, server: { host, headers, open: serverOpen, allowedHosts, port } } = settings.config;
// serverOpen = true, isRestart = false
// when astro dev --open command is run the first time
// expected behavior: spawn a new tab
// ------------------------------------------------------
// serverOpen = true, isRestart = true
// when config file is saved
// expected behavior: do not spawn a new tab
// ------------------------------------------------------
// Non-config files don't reach this point
const isServerOpenURL = typeof serverOpen === "string" && !isRestart;
const isServerOpenBoolean = serverOpen && !isRestart;
// Open server to the correct path. We pass the `base` here as we didn't pass the
// base to the initial Vite config
const open = isServerOpenURL ? serverOpen : isServerOpenBoolean ? base : false;
// The client entrypoint for renderers. Since these are imported dynamically
// we need to tell Vite to preoptimize them.
const rendererClientEntries = settings.renderers.map((r) => r.clientEntrypoint).filter(Boolean);
// Set the initial buildOutput default before runHookConfigDone, so that
// setAdapter() inside astro:config:done can upgrade it to 'server'.
// This matches the ordering in the build path (packages/astro/src/core/build/index.ts).
if (!settings.adapter?.adapterFeatures?.buildOutput) {
settings.buildOutput = getPrerenderDefault(settings.config) ? "static" : "server";
}
// Create the route manifest already outside of Vite so that `runHookConfigDone` can use it to inform integrations of the build output
await runHookConfigDone({
settings,
logger,
command: "dev"
});
warnMissingAdapter(logger, settings);
const mode = inlineConfig?.mode ?? "development";
const initialRoutesList = await createRoutesList({
settings,
fsMod: nodeFs
}, logger, { dev: true });
const viteConfig = await createVite({
server: {
host,
headers,
open,
allowedHosts,
port
},
optimizeDeps: { include: rendererClientEntries }
}, {
settings,
logger,
mode,
command: "dev",
fs,
sync: false,
routesList: initialRoutesList
});
const viteServer = await vite.createServer(viteConfig);
await syncInternal({
settings,
mode,
logger,
skip: {
content: !isRestart,
cleanup: true
},
force: inlineConfig?.force,
command: "dev",
watcher: viteServer.watcher
});
const container = {
inlineConfig: inlineConfig ?? {},
fs,
logger,
restartInFlight: false,
settings,
viteServer,
handle(req, res) {
viteServer.middlewares.handle(req, res, Function.prototype);
},
close() {
return closeContainer(container);
}
};
return container;
}
async function closeContainer({ viteServer, settings, logger }) {
// Background app setup uses the runnable environment's module runner. Let it
// settle before Vite disconnects that runner so shutdown cannot strand an
// in-flight module import.
await viteServer[devServerAppReadySymbol];
await viteServer.close();
await runHookServerDone({
config: settings.config,
logger
});
}
export async function startContainer({ settings, viteServer, logger }) {
const { port } = settings.config.server;
await viteServer.listen(port);
const devServerAddressInfo = viteServer.httpServer.address();
await runHookServerStart({
config: settings.config,
address: devServerAddressInfo,
logger
});
return devServerAddressInfo;
}