133 lines
4.7 KiB
Plaintext
133 lines
4.7 KiB
Plaintext
|
import { fileURLToPath } from "node:url";
|
||
|
import * as vite from "vite";
|
||
|
import { eventCliSession, telemetry } from "../../events/index.js";
|
||
|
import { createNodeLogger, createSettings, resolveConfig } from "../config/index.js";
|
||
|
import { collectErrorMetadata } from "../errors/dev/utils.js";
|
||
|
import { isAstroConfigZodError } from "../errors/errors.js";
|
||
|
import { createSafeError } from "../errors/index.js";
|
||
|
import { formatErrorMessage } from "../messages.js";
|
||
|
import { createContainer, startContainer } from "./container.js";
|
||
|
async function createRestartedContainer(container, settings) {
|
||
|
const { logger, fs, inlineConfig } = container;
|
||
|
const newContainer = await createContainer({
|
||
|
isRestart: true,
|
||
|
logger,
|
||
|
settings,
|
||
|
inlineConfig,
|
||
|
fs
|
||
|
});
|
||
|
await startContainer(newContainer);
|
||
|
return newContainer;
|
||
|
}
|
||
|
const configRE = new RegExp(`.*astro.config.((mjs)|(cjs)|(js)|(ts))$`);
|
||
|
const preferencesRE = new RegExp(`.*.astro/settings.json$`);
|
||
|
function shouldRestartContainer({ settings, inlineConfig, restartInFlight }, changedFile) {
|
||
|
if (restartInFlight)
|
||
|
return false;
|
||
|
let shouldRestart = false;
|
||
|
if (inlineConfig.configFile) {
|
||
|
shouldRestart = vite.normalizePath(inlineConfig.configFile) === vite.normalizePath(changedFile);
|
||
|
} else {
|
||
|
const normalizedChangedFile = vite.normalizePath(changedFile);
|
||
|
shouldRestart = configRE.test(normalizedChangedFile) || preferencesRE.test(normalizedChangedFile);
|
||
|
}
|
||
|
if (!shouldRestart && settings.watchFiles.length > 0) {
|
||
|
shouldRestart = settings.watchFiles.some(
|
||
|
(path) => vite.normalizePath(path) === vite.normalizePath(changedFile)
|
||
|
);
|
||
|
}
|
||
|
return shouldRestart;
|
||
|
}
|
||
|
async function restartContainer(container) {
|
||
|
const { logger, close, settings: existingSettings } = container;
|
||
|
container.restartInFlight = true;
|
||
|
try {
|
||
|
const { astroConfig } = await resolveConfig(container.inlineConfig, "dev", container.fs);
|
||
|
const settings = await createSettings(astroConfig, fileURLToPath(existingSettings.config.root));
|
||
|
await close();
|
||
|
return await createRestartedContainer(container, settings);
|
||
|
} catch (_err) {
|
||
|
const error = createSafeError(_err);
|
||
|
if (!isAstroConfigZodError(_err)) {
|
||
|
logger.error(
|
||
|
"config",
|
||
|
formatErrorMessage(collectErrorMetadata(error), logger.level() === "debug") + "\n"
|
||
|
);
|
||
|
}
|
||
|
container.viteServer.ws.send({
|
||
|
type: "error",
|
||
|
err: {
|
||
|
message: error.message,
|
||
|
stack: error.stack || ""
|
||
|
}
|
||
|
});
|
||
|
container.restartInFlight = false;
|
||
|
logger.error(null, "Continuing with previous valid configuration\n");
|
||
|
return error;
|
||
|
}
|
||
|
}
|
||
|
async function createContainerWithAutomaticRestart({
|
||
|
inlineConfig,
|
||
|
fs
|
||
|
}) {
|
||
|
const logger = createNodeLogger(inlineConfig ?? {});
|
||
|
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, "dev", fs);
|
||
|
telemetry.record(eventCliSession("dev", userConfig));
|
||
|
const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root));
|
||
|
const initialContainer = await createContainer({ settings, logger, inlineConfig, fs });
|
||
|
let resolveRestart;
|
||
|
let restartComplete = new Promise((resolve) => {
|
||
|
resolveRestart = resolve;
|
||
|
});
|
||
|
let restart = {
|
||
|
container: initialContainer,
|
||
|
restarted() {
|
||
|
return restartComplete;
|
||
|
}
|
||
|
};
|
||
|
async function handleServerRestart(logMsg = "") {
|
||
|
logger.info(null, (logMsg + " Restarting...").trim());
|
||
|
const container = restart.container;
|
||
|
const result = await restartContainer(container);
|
||
|
if (result instanceof Error) {
|
||
|
resolveRestart(result);
|
||
|
} else {
|
||
|
restart.container = result;
|
||
|
setupContainer();
|
||
|
resolveRestart(null);
|
||
|
}
|
||
|
restartComplete = new Promise((resolve) => {
|
||
|
resolveRestart = resolve;
|
||
|
});
|
||
|
}
|
||
|
function handleChangeRestart(logMsg) {
|
||
|
return async function(changedFile) {
|
||
|
if (shouldRestartContainer(restart.container, changedFile)) {
|
||
|
handleServerRestart(logMsg);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
function setupContainer() {
|
||
|
const watcher = restart.container.viteServer.watcher;
|
||
|
watcher.on("change", handleChangeRestart("Configuration file updated."));
|
||
|
watcher.on("unlink", handleChangeRestart("Configuration file removed."));
|
||
|
watcher.on("add", handleChangeRestart("Configuration file added."));
|
||
|
restart.container.viteServer.restart = () => handleServerRestart();
|
||
|
restart.container.viteServer.bindCLIShortcuts({
|
||
|
customShortcuts: [
|
||
|
// Disable Vite's builtin "r" (restart server), "u" (print server urls) and "c" (clear console) shortcuts
|
||
|
{ key: "r", description: "" },
|
||
|
{ key: "u", description: "" },
|
||
|
{ key: "c", description: "" }
|
||
|
]
|
||
|
});
|
||
|
}
|
||
|
setupContainer();
|
||
|
return restart;
|
||
|
}
|
||
|
export {
|
||
|
createContainerWithAutomaticRestart,
|
||
|
restartContainer,
|
||
|
shouldRestartContainer
|
||
|
};
|