Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
import type { Rollup } from 'vite';
export declare function addRollupInput(inputOptions: Rollup.InputOptions, newInputs: string[]): Rollup.InputOptions;

37
node_modules/astro/dist/core/build/add-rollup-input.js generated vendored Normal file
View File

@@ -0,0 +1,37 @@
function fromEntries(entries) {
const obj = {};
for (const [k, v] of entries) {
obj[k] = v;
}
return obj;
}
function addRollupInput(inputOptions, newInputs) {
if (!inputOptions.input) {
return { ...inputOptions, input: newInputs };
}
if (typeof inputOptions.input === "string") {
return {
...inputOptions,
input: [inputOptions.input, ...newInputs]
};
}
if (Array.isArray(inputOptions.input)) {
return {
...inputOptions,
input: [...inputOptions.input, ...newInputs]
};
}
if (typeof inputOptions.input === "object") {
return {
...inputOptions,
input: {
...inputOptions.input,
...fromEntries(newInputs.map((i) => [i.split("/").slice(-1)[0].split(".")[0], i]))
}
};
}
throw new Error(`Unknown rollup input type. Supported inputs are string, array and object.`);
}
export {
addRollupInput
};

9
node_modules/astro/dist/core/build/common.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import type { AstroConfig, RouteData } from '../../@types/astro.js';
export declare function getOutFolder(astroConfig: AstroConfig, pathname: string, routeData: RouteData): URL;
export declare function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: string, routeData: RouteData): URL;
/**
* Ensures the `outDir` is within `process.cwd()`. If not it will fallback to `<cwd>/.astro`.
* This is used for static `ssrBuild` so the output can access node_modules when we import
* the output files. A hardcoded fallback dir is fine as it would be cleaned up after build.
*/
export declare function getOutDirWithinCwd(outDir: URL): URL;

86
node_modules/astro/dist/core/build/common.js generated vendored Normal file
View File

@@ -0,0 +1,86 @@
import npath from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { appendForwardSlash } from "../../core/path.js";
const STATUS_CODE_PAGES = /* @__PURE__ */ new Set(["/404", "/500"]);
const FALLBACK_OUT_DIR_NAME = "./.astro/";
function getOutRoot(astroConfig) {
if (astroConfig.output === "static") {
return new URL("./", astroConfig.outDir);
} else {
return new URL("./", astroConfig.build.client);
}
}
function getOutFolder(astroConfig, pathname, routeData) {
const outRoot = getOutRoot(astroConfig);
const routeType = routeData.type;
switch (routeType) {
case "endpoint":
return new URL("." + appendForwardSlash(npath.dirname(pathname)), outRoot);
case "fallback":
case "page":
case "redirect":
switch (astroConfig.build.format) {
case "directory": {
if (STATUS_CODE_PAGES.has(pathname)) {
return new URL("." + appendForwardSlash(npath.dirname(pathname)), outRoot);
}
return new URL("." + appendForwardSlash(pathname), outRoot);
}
case "file": {
const d = pathname === "" ? pathname : npath.dirname(pathname);
return new URL("." + appendForwardSlash(d), outRoot);
}
case "preserve": {
let dir;
if (pathname === "" || routeData.isIndex) {
dir = pathname;
} else {
dir = npath.dirname(pathname);
}
return new URL("." + appendForwardSlash(dir), outRoot);
}
}
}
}
function getOutFile(astroConfig, outFolder, pathname, routeData) {
const routeType = routeData.type;
switch (routeType) {
case "endpoint":
return new URL(npath.basename(pathname), outFolder);
case "page":
case "fallback":
case "redirect":
switch (astroConfig.build.format) {
case "directory": {
if (STATUS_CODE_PAGES.has(pathname)) {
const baseName = npath.basename(pathname);
return new URL("./" + (baseName || "index") + ".html", outFolder);
}
return new URL("./index.html", outFolder);
}
case "file": {
const baseName = npath.basename(pathname);
return new URL("./" + (baseName || "index") + ".html", outFolder);
}
case "preserve": {
let baseName = npath.basename(pathname);
if (!baseName || routeData.isIndex) {
baseName = "index";
}
return new URL(`./${baseName}.html`, outFolder);
}
}
}
}
function getOutDirWithinCwd(outDir) {
if (fileURLToPath(outDir).startsWith(process.cwd())) {
return outDir;
} else {
return new URL(FALLBACK_OUT_DIR_NAME, pathToFileURL(process.cwd() + npath.sep));
}
}
export {
getOutDirWithinCwd,
getOutFile,
getOutFolder
};

2
node_modules/astro/dist/core/build/consts.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare const CHUNKS_PATH = "chunks/";
export declare const CONTENT_PATH = "content/";

6
node_modules/astro/dist/core/build/consts.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
const CHUNKS_PATH = "chunks/";
const CONTENT_PATH = "content/";
export {
CHUNKS_PATH,
CONTENT_PATH
};

View File

@@ -0,0 +1,9 @@
import type { GetModuleInfo } from 'rollup';
import type { AstroSettings } from '../../@types/astro.js';
export declare function shortHashedName(settings: AstroSettings): (id: string, ctx: {
getModuleInfo: GetModuleInfo;
}) => string;
export declare function createNameHash(baseId: string | undefined, hashIds: string[], settings: AstroSettings): string;
export declare function createSlugger(settings: AstroSettings): (id: string, ctx: {
getModuleInfo: GetModuleInfo;
}) => string;

89
node_modules/astro/dist/core/build/css-asset-name.js generated vendored Normal file
View File

@@ -0,0 +1,89 @@
import crypto from "node:crypto";
import npath from "node:path";
import { fileURLToPath } from "node:url";
import { normalizePath } from "vite";
import { viteID } from "../util.js";
import { getTopLevelPageModuleInfos } from "./graph.js";
const confusingBaseNames = ["404", "500"];
function shortHashedName(settings) {
return function(id, ctx) {
const parents = getTopLevelPageModuleInfos(id, ctx);
return createNameHash(
getFirstParentId(parents),
parents.map((page) => page.id),
settings
);
};
}
function createNameHash(baseId, hashIds, settings) {
const baseName = baseId ? prettifyBaseName(npath.parse(baseId).name) : "index";
const hash = crypto.createHash("sha256");
const root = fileURLToPath(settings.config.root);
for (const id of hashIds) {
const relativePath = npath.relative(root, id);
hash.update(normalizePath(relativePath), "utf-8");
}
const h = hash.digest("hex").slice(0, 8);
const proposedName = baseName + "." + h;
return proposedName;
}
function createSlugger(settings) {
const pagesDir = viteID(new URL("./pages", settings.config.srcDir));
const indexPage = viteID(new URL("./pages/index", settings.config.srcDir));
const map = /* @__PURE__ */ new Map();
const sep = "-";
return function(id, ctx) {
const parents = Array.from(getTopLevelPageModuleInfos(id, ctx));
const allParentsKey = parents.map((page) => page.id).sort().join("-");
const firstParentId = getFirstParentId(parents) || indexPage;
let dir = firstParentId;
let key = "";
let i = 0;
while (i < 2) {
if (dir === pagesDir) {
break;
}
const name2 = prettifyBaseName(npath.parse(npath.basename(dir)).name);
key = key.length ? name2 + sep + key : name2;
dir = npath.dirname(dir);
i++;
}
let name = key;
if (!map.has(key)) {
map.set(key, /* @__PURE__ */ new Map([[allParentsKey, 0]]));
} else {
const inner = map.get(key);
if (inner.has(allParentsKey)) {
const num = inner.get(allParentsKey);
if (num > 0) {
name = name + sep + num;
}
} else {
const num = inner.size;
inner.set(allParentsKey, num);
name = name + sep + num;
}
}
return name;
};
}
function getFirstParentId(parents) {
for (const parent of parents) {
const id = parent.id;
const baseName = npath.parse(id).name;
if (!confusingBaseNames.includes(baseName)) {
return id;
}
}
return parents[0]?.id;
}
const charsToReplaceRe = /[.[\]]/g;
const underscoresRe = /_+/g;
function prettifyBaseName(str) {
return str.replace(charsToReplaceRe, "_").replace(underscoresRe, "_");
}
export {
createNameHash,
createSlugger,
shortHashedName
};

3
node_modules/astro/dist/core/build/generate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { type BuildInternals } from '../../core/build/internal.js';
import type { StaticBuildOptions } from './types.js';
export declare function generatePages(options: StaticBuildOptions, internals: BuildInternals): Promise<void>;

416
node_modules/astro/dist/core/build/generate.js generated vendored Normal file
View File

@@ -0,0 +1,416 @@
import fs from "node:fs";
import os from "node:os";
import { bgGreen, black, blue, bold, dim, green, magenta, red } from "kleur/colors";
import PLimit from "p-limit";
import PQueue from "p-queue";
import {
generateImagesForPath,
getStaticImageList,
prepareAssetsGenerationEnv
} from "../../assets/build/generate.js";
import { hasPrerenderedPages } from "../../core/build/internal.js";
import {
isRelativePath,
joinPaths,
removeLeadingForwardSlash,
removeTrailingForwardSlash
} from "../../core/path.js";
import { toFallbackType, toRoutingStrategy } from "../../i18n/utils.js";
import { runHookBuildGenerated } from "../../integrations/hooks.js";
import { getOutputDirectory } from "../../prerender/utils.js";
import { NoPrerenderedRoutesWithDomains } from "../errors/errors-data.js";
import { AstroError, AstroErrorData } from "../errors/index.js";
import { NOOP_MIDDLEWARE_FN } from "../middleware/noop-middleware.js";
import { getRedirectLocationOrThrow, routeIsRedirect } from "../redirects/index.js";
import { RenderContext } from "../render-context.js";
import { callGetStaticPaths } from "../render/route-cache.js";
import { createRequest } from "../request.js";
import { matchRoute } from "../routing/match.js";
import { stringifyParams } from "../routing/params.js";
import { getOutputFilename, isServerLikeOutput } from "../util.js";
import { getOutDirWithinCwd, getOutFile, getOutFolder } from "./common.js";
import { cssOrder, mergeInlineCss } from "./internal.js";
import { BuildPipeline } from "./pipeline.js";
import { getTimeStat, shouldAppendForwardSlash } from "./util.js";
function createEntryURL(filePath, outFolder) {
return new URL("./" + filePath + `?time=${Date.now()}`, outFolder);
}
async function generatePages(options, internals) {
const generatePagesTimer = performance.now();
const ssr = isServerLikeOutput(options.settings.config);
let manifest;
if (ssr) {
manifest = await BuildPipeline.retrieveManifest(options, internals);
} else {
const baseDirectory = getOutputDirectory(options.settings.config);
const renderersEntryUrl = new URL("renderers.mjs", baseDirectory);
const renderers = await import(renderersEntryUrl.toString());
const middleware = internals.middlewareEntryPoint ? await import(internals.middlewareEntryPoint.toString()).then((mod) => mod.onRequest) : NOOP_MIDDLEWARE_FN;
manifest = createBuildManifest(
options.settings,
internals,
renderers.renderers,
middleware,
options.key
);
}
const pipeline = BuildPipeline.create({ internals, manifest, options });
const { config, logger } = pipeline;
const outFolder = ssr ? options.settings.config.build.server : getOutDirWithinCwd(options.settings.config.outDir);
if (ssr && !hasPrerenderedPages(internals)) {
delete globalThis?.astroAsset?.addStaticImage;
return;
}
const verb = ssr ? "prerendering" : "generating";
logger.info("SKIP_FORMAT", `
${bgGreen(black(` ${verb} static routes `))}`);
const builtPaths = /* @__PURE__ */ new Set();
const pagesToGenerate = pipeline.retrieveRoutesToGenerate();
if (ssr) {
for (const [pageData, filePath] of pagesToGenerate) {
if (pageData.route.prerender) {
if (config.i18n?.domains && Object.keys(config.i18n.domains).length > 0) {
throw new AstroError({
...NoPrerenderedRoutesWithDomains,
message: NoPrerenderedRoutesWithDomains.message(pageData.component)
});
}
const ssrEntryPage = await pipeline.retrieveSsrEntry(pageData.route, filePath);
if (options.settings.adapter?.adapterFeatures?.functionPerRoute) {
const ssrEntry = ssrEntryPage?.pageModule;
if (ssrEntry) {
await generatePage(pageData, ssrEntry, builtPaths, pipeline);
} else {
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
throw new Error(
`Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.`
);
}
} else {
const ssrEntry = ssrEntryPage;
await generatePage(pageData, ssrEntry, builtPaths, pipeline);
}
}
}
} else {
for (const [pageData, filePath] of pagesToGenerate) {
const entry = await pipeline.retrieveSsrEntry(pageData.route, filePath);
await generatePage(pageData, entry, builtPaths, pipeline);
}
}
logger.info(
null,
green(`\u2713 Completed in ${getTimeStat(generatePagesTimer, performance.now())}.
`)
);
const staticImageList = getStaticImageList();
if (staticImageList.size) {
logger.info("SKIP_FORMAT", `${bgGreen(black(` generating optimized images `))}`);
const totalCount = Array.from(staticImageList.values()).map((x) => x.transforms.size).reduce((a, b) => a + b, 0);
const cpuCount = os.cpus().length;
const assetsCreationPipeline = await prepareAssetsGenerationEnv(pipeline, totalCount);
const queue = new PQueue({ concurrency: Math.max(cpuCount, 1) });
const assetsTimer = performance.now();
for (const [originalPath, transforms] of staticImageList) {
await generateImagesForPath(originalPath, transforms, assetsCreationPipeline, queue);
}
await queue.onIdle();
const assetsTimeEnd = performance.now();
logger.info(null, green(`\u2713 Completed in ${getTimeStat(assetsTimer, assetsTimeEnd)}.
`));
delete globalThis?.astroAsset?.addStaticImage;
}
await runHookBuildGenerated({ config, logger });
}
const THRESHOLD_SLOW_RENDER_TIME_MS = 500;
async function generatePage(pageData, ssrEntry, builtPaths, pipeline) {
const { config, logger } = pipeline;
const pageModulePromise = ssrEntry.page;
const styles = pageData.styles.sort(cssOrder).map(({ sheet }) => sheet).reduce(mergeInlineCss, []);
const linkIds = [];
const scripts = pageData.hoistedScript ?? null;
if (!pageModulePromise) {
throw new Error(
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`
);
}
const pageModule = await pageModulePromise();
const generationOptions = {
pageData,
linkIds,
scripts,
styles,
mod: pageModule
};
async function generatePathWithLogs(path, route, index, paths, isConcurrent) {
const timeStart = performance.now();
pipeline.logger.debug("build", `Generating: ${path}`);
const filePath = getOutputFilename(config, path, pageData.route.type);
const lineIcon = index === paths.length - 1 && !isConcurrent || paths.length === 1 ? "\u2514\u2500" : "\u251C\u2500";
if (!isConcurrent) {
logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)}`, false);
}
await generatePath(path, pipeline, generationOptions, route);
const timeEnd = performance.now();
const isSlow = timeEnd - timeStart > THRESHOLD_SLOW_RENDER_TIME_MS;
const timeIncrease = (isSlow ? red : dim)(`(+${getTimeStat(timeStart, timeEnd)})`);
if (isConcurrent) {
logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)} ${timeIncrease}`);
} else {
logger.info("SKIP_FORMAT", ` ${timeIncrease}`);
}
}
for (const route of eachRouteInRouteData(pageData)) {
const icon = route.type === "page" || route.type === "redirect" || route.type === "fallback" ? green("\u25B6") : magenta("\u03BB");
logger.info(null, `${icon} ${getPrettyRouteName(route)}`);
const paths = await getPathsForRoute(route, pageModule, pipeline, builtPaths);
if (config.build.concurrency > 1) {
const limit = PLimit(config.build.concurrency);
const promises = [];
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
promises.push(limit(() => generatePathWithLogs(path, route, i, paths, true)));
}
await Promise.allSettled(promises);
} else {
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
await generatePathWithLogs(path, route, i, paths, false);
}
}
}
}
function* eachRouteInRouteData(data) {
yield data.route;
for (const fallbackRoute of data.route.fallbackRoutes) {
yield fallbackRoute;
}
}
async function getPathsForRoute(route, mod, pipeline, builtPaths) {
const { logger, options, routeCache, serverLike } = pipeline;
let paths = [];
if (route.pathname) {
paths.push(route.pathname);
builtPaths.add(removeTrailingForwardSlash(route.pathname));
} else {
const staticPaths = await callGetStaticPaths({
mod,
route,
routeCache,
logger,
ssr: serverLike
}).catch((err) => {
logger.error("build", `Failed to call getStaticPaths for ${route.component}`);
throw err;
});
const label = staticPaths.length === 1 ? "page" : "pages";
logger.debug(
"build",
`\u251C\u2500\u2500 ${bold(green("\u221A"))} ${route.component} \u2192 ${magenta(`[${staticPaths.length} ${label}]`)}`
);
paths = staticPaths.map((staticPath) => {
try {
return stringifyParams(staticPath.params, route);
} catch (e) {
if (e instanceof TypeError) {
throw getInvalidRouteSegmentError(e, route, staticPath);
}
throw e;
}
}).filter((staticPath) => {
if (!builtPaths.has(removeTrailingForwardSlash(staticPath))) {
return true;
}
const matchedRoute = matchRoute(staticPath, options.manifest);
return matchedRoute === route;
});
for (const staticPath of paths) {
builtPaths.add(removeTrailingForwardSlash(staticPath));
}
}
return paths;
}
function getInvalidRouteSegmentError(e, route, staticPath) {
const invalidParam = /^Expected "([^"]+)"/.exec(e.message)?.[1];
const received = invalidParam ? staticPath.params[invalidParam] : void 0;
let hint = "Learn about dynamic routes at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes";
if (invalidParam && typeof received === "string") {
const matchingSegment = route.segments.find(
(segment) => segment[0]?.content === invalidParam
)?.[0];
const mightBeMissingSpread = matchingSegment?.dynamic && !matchingSegment?.spread;
if (mightBeMissingSpread) {
hint = `If the param contains slashes, try using a rest parameter: **[...${invalidParam}]**. Learn more at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes`;
}
}
return new AstroError({
...AstroErrorData.InvalidDynamicRoute,
message: invalidParam ? AstroErrorData.InvalidDynamicRoute.message(
route.route,
JSON.stringify(invalidParam),
JSON.stringify(received)
) : `Generated path for ${route.route} is invalid.`,
hint
});
}
function addPageName(pathname, opts) {
const trailingSlash = opts.settings.config.trailingSlash;
const buildFormat = opts.settings.config.build.format;
const pageName = shouldAppendForwardSlash(trailingSlash, buildFormat) ? pathname.replace(/\/?$/, "/").replace(/^\//, "") : pathname.replace(/^\//, "");
opts.pageNames.push(pageName);
}
function getUrlForPath(pathname, base, origin, format, trailingSlash, routeType) {
let ending;
switch (format) {
case "directory":
case "preserve": {
ending = trailingSlash === "never" ? "" : "/";
break;
}
case "file":
default: {
ending = ".html";
break;
}
}
let buildPathname;
if (pathname === "/" || pathname === "") {
buildPathname = base;
} else if (routeType === "endpoint") {
const buildPathRelative = removeLeadingForwardSlash(pathname);
buildPathname = joinPaths(base, buildPathRelative);
} else {
const buildPathRelative = removeTrailingForwardSlash(removeLeadingForwardSlash(pathname)) + ending;
buildPathname = joinPaths(base, buildPathRelative);
}
const url = new URL(buildPathname, origin);
return url;
}
async function generatePath(pathname, pipeline, gopts, route) {
const { mod } = gopts;
const { config, logger, options } = pipeline;
logger.debug("build", `Generating: ${pathname}`);
if (route.type === "page") {
addPageName(pathname, options);
}
if (route.type === "fallback" && // If route is index page, continue rendering. The index page should
// always be rendered
route.pathname !== "/" && // Check if there is a translated page with the same path
Object.values(options.allPages).some((val) => val.route.pattern.test(pathname))) {
return;
}
const url = getUrlForPath(
pathname,
config.base,
options.origin,
config.build.format,
config.trailingSlash,
route.type
);
const request = createRequest({
base: config.base,
url,
headers: new Headers(),
logger,
staticLike: true
});
const renderContext = await RenderContext.create({
pipeline,
pathname,
request,
routeData: route
});
let body;
let response;
try {
response = await renderContext.render(mod);
} catch (err) {
if (!AstroError.is(err) && !err.id && typeof err === "object") {
err.id = route.component;
}
throw err;
}
if (response.status >= 300 && response.status < 400) {
if (routeIsRedirect(route) && !config.build.redirects) {
return;
}
const locationSite = getRedirectLocationOrThrow(response.headers);
const siteURL = config.site;
const location = siteURL ? new URL(locationSite, siteURL) : locationSite;
const fromPath = new URL(request.url).pathname;
const delay = response.status === 302 ? 2 : 0;
body = `<!doctype html>
<title>Redirecting to: ${location}</title>
<meta http-equiv="refresh" content="${delay};url=${location}">
<meta name="robots" content="noindex">
<link rel="canonical" href="${location}">
<body>
<a href="${location}">Redirecting from <code>${fromPath}</code> to <code>${location}</code></a>
</body>`;
if (config.compressHTML === true) {
body = body.replaceAll("\n", "");
}
if (route.type !== "redirect") {
route.redirect = location.toString();
}
} else {
if (!response.body) return;
body = Buffer.from(await response.arrayBuffer());
}
const outFolder = getOutFolder(config, pathname, route);
const outFile = getOutFile(config, outFolder, pathname, route);
route.distURL = outFile;
await fs.promises.mkdir(outFolder, { recursive: true });
await fs.promises.writeFile(outFile, body);
}
function getPrettyRouteName(route) {
if (isRelativePath(route.component)) {
return route.route;
} else if (route.component.includes("node_modules/")) {
return /.*node_modules\/(.+)/.exec(route.component)?.[1] ?? route.component;
} else {
return route.component;
}
}
function createBuildManifest(settings, internals, renderers, middleware, key) {
let i18nManifest = void 0;
if (settings.config.i18n) {
i18nManifest = {
fallback: settings.config.i18n.fallback,
fallbackType: toFallbackType(settings.config.i18n.routing),
strategy: toRoutingStrategy(settings.config.i18n.routing, settings.config.i18n.domains),
defaultLocale: settings.config.i18n.defaultLocale,
locales: settings.config.i18n.locales,
domainLookupTable: {}
};
}
return {
hrefRoot: settings.config.root.toString(),
trailingSlash: settings.config.trailingSlash,
assets: /* @__PURE__ */ new Set(),
entryModules: Object.fromEntries(internals.entrySpecifierToBundleMap.entries()),
inlinedScripts: internals.inlinedScripts,
routes: [],
adapterName: "",
clientDirectives: settings.clientDirectives,
compressHTML: settings.config.compressHTML,
renderers,
base: settings.config.base,
assetsPrefix: settings.config.build.assetsPrefix,
site: settings.config.site,
componentMetadata: internals.componentMetadata,
i18n: i18nManifest,
buildFormat: settings.config.build.format,
middleware() {
return {
onRequest: middleware
};
},
checkOrigin: settings.config.security?.checkOrigin ?? false,
key,
experimentalEnvGetSecretEnabled: false
};
}
export {
generatePages
};

17
node_modules/astro/dist/core/build/graph.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import type { GetModuleInfo, ModuleInfo } from 'rollup';
interface ExtendedModuleInfo {
info: ModuleInfo;
depth: number;
order: number;
}
export declare function getParentExtendedModuleInfos(id: string, ctx: {
getModuleInfo: GetModuleInfo;
}, until?: (importer: string) => boolean, depth?: number, order?: number, childId?: string, seen?: Set<string>, accumulated?: ExtendedModuleInfo[]): ExtendedModuleInfo[];
export declare function getParentModuleInfos(id: string, ctx: {
getModuleInfo: GetModuleInfo;
}, until?: (importer: string) => boolean, seen?: Set<string>, accumulated?: ModuleInfo[]): ModuleInfo[];
export declare function moduleIsTopLevelPage(info: ModuleInfo): boolean;
export declare function getTopLevelPageModuleInfos(id: string, ctx: {
getModuleInfo: GetModuleInfo;
}): ModuleInfo[];
export {};

54
node_modules/astro/dist/core/build/graph.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
import { ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugins/plugin-pages.js";
function getParentExtendedModuleInfos(id, ctx, until, depth = 0, order = 0, childId = "", seen = /* @__PURE__ */ new Set(), accumulated = []) {
seen.add(id);
const info = ctx.getModuleInfo(id);
if (info) {
if (childId) {
const idx = info.importedIds.indexOf(childId);
if (idx === -1) {
order += info.importedIds.length;
order += info.dynamicallyImportedIds.indexOf(childId);
} else {
order += idx;
}
}
accumulated.push({ info, depth, order });
}
if (info && !until?.(id)) {
const importers = info.importers.concat(info.dynamicImporters);
for (const imp of importers) {
if (!seen.has(imp)) {
getParentExtendedModuleInfos(imp, ctx, until, depth + 1, order, id, seen, accumulated);
}
}
}
return accumulated;
}
function getParentModuleInfos(id, ctx, until, seen = /* @__PURE__ */ new Set(), accumulated = []) {
seen.add(id);
const info = ctx.getModuleInfo(id);
if (info) {
accumulated.push(info);
}
if (info && !until?.(id)) {
const importers = info.importers.concat(info.dynamicImporters);
for (const imp of importers) {
if (!seen.has(imp)) {
getParentModuleInfos(imp, ctx, until, seen, accumulated);
}
}
}
return accumulated;
}
function moduleIsTopLevelPage(info) {
return info.importers[0]?.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) || info.dynamicImporters[0]?.includes(ASTRO_PAGE_RESOLVED_MODULE_ID);
}
function getTopLevelPageModuleInfos(id, ctx) {
return getParentModuleInfos(id, ctx).filter(moduleIsTopLevelPage);
}
export {
getParentExtendedModuleInfos,
getParentModuleInfos,
getTopLevelPageModuleInfos,
moduleIsTopLevelPage
};

10
node_modules/astro/dist/core/build/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import type { AstroInlineConfig } from '../../@types/astro.js';
export interface BuildOptions {
}
/**
* Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory.
* If SSR is enabled, this will generate the necessary server files to serve your site.
*
* @experimental The JavaScript API is experimental
*/
export default function build(inlineConfig: AstroInlineConfig, options?: BuildOptions): Promise<void>;

218
node_modules/astro/dist/core/build/index.js generated vendored Normal file
View File

@@ -0,0 +1,218 @@
import fs from "node:fs";
import { performance } from "node:perf_hooks";
import { fileURLToPath } from "node:url";
import { blue, bold, green } from "kleur/colors";
import { injectImageEndpoint } from "../../assets/endpoint/config.js";
import { telemetry } from "../../events/index.js";
import { eventCliSession } from "../../events/session.js";
import {
runHookBuildDone,
runHookBuildStart,
runHookConfigDone,
runHookConfigSetup
} from "../../integrations/hooks.js";
import { resolveConfig } from "../config/config.js";
import { createNodeLogger } from "../config/logging.js";
import { createSettings } from "../config/settings.js";
import { createVite } from "../create-vite.js";
import { createKey, getEnvironmentKey, hasEnvironmentKey } from "../encryption.js";
import { levels, timerMessage } from "../logger/core.js";
import { apply as applyPolyfill } from "../polyfill.js";
import { createRouteManifest } from "../routing/index.js";
import { getServerIslandRouteData } from "../server-islands/endpoint.js";
import { clearContentLayerCache } from "../sync/index.js";
import { ensureProcessNodeEnv, isServerLikeOutput } from "../util.js";
import { collectPagesData } from "./page-data.js";
import { staticBuild, viteBuild } from "./static-build.js";
import { getTimeStat } from "./util.js";
async function build(inlineConfig, options = {}) {
ensureProcessNodeEnv("production");
applyPolyfill();
const logger = createNodeLogger(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig, "build");
telemetry.record(eventCliSession("build", userConfig));
const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root));
if (inlineConfig.force) {
if (astroConfig.experimental.contentCollectionCache) {
const contentCacheDir = new URL("./content/", astroConfig.cacheDir);
if (fs.existsSync(contentCacheDir)) {
logger.debug("content", "clearing content cache");
await fs.promises.rm(contentCacheDir, { force: true, recursive: true });
logger.warn("content", "content cache cleared (force)");
}
}
await clearContentLayerCache({ settings, logger, fs });
}
const builder = new AstroBuilder(settings, {
...options,
logger,
mode: inlineConfig.mode
});
await builder.run();
}
class AstroBuilder {
settings;
logger;
mode = "production";
origin;
manifest;
timer;
teardownCompiler;
constructor(settings, options) {
if (options.mode) {
this.mode = options.mode;
}
this.settings = settings;
this.logger = options.logger;
this.teardownCompiler = options.teardownCompiler ?? true;
this.origin = settings.config.site ? new URL(settings.config.site).origin : `http://localhost:${settings.config.server.port}`;
this.manifest = { routes: [] };
this.timer = {};
}
/** Setup Vite and run any async setup logic that couldn't run inside of the constructor. */
async setup() {
this.logger.debug("build", "Initial setup...");
const { logger } = this;
this.timer.init = performance.now();
this.settings = await runHookConfigSetup({
settings: this.settings,
command: "build",
logger
});
if (isServerLikeOutput(this.settings.config)) {
this.settings = injectImageEndpoint(this.settings, "build");
}
this.manifest = createRouteManifest({ settings: this.settings }, this.logger);
const viteConfig = await createVite(
{
mode: this.mode,
server: {
hmr: false,
middlewareMode: true
}
},
{
settings: this.settings,
logger: this.logger,
mode: "build",
command: "build",
sync: false
}
);
await runHookConfigDone({ settings: this.settings, logger });
const { syncInternal } = await import("../sync/index.js");
await syncInternal({
settings: this.settings,
logger,
fs
});
return { viteConfig };
}
/** Run the build logic. build() is marked private because usage should go through ".run()" */
async build({ viteConfig }) {
await runHookBuildStart({ config: this.settings.config, logging: this.logger });
this.validateConfig();
this.logger.info("build", `output: ${blue('"' + this.settings.config.output + '"')}`);
this.logger.info("build", `directory: ${blue(fileURLToPath(this.settings.config.outDir))}`);
if (this.settings.adapter) {
this.logger.info("build", `adapter: ${green(this.settings.adapter.name)}`);
}
this.logger.info("build", "Collecting build info...");
this.timer.loadStart = performance.now();
const { assets, allPages } = collectPagesData({
settings: this.settings,
logger: this.logger,
manifest: this.manifest
});
this.logger.debug("build", timerMessage("All pages loaded", this.timer.loadStart));
const pageNames = [];
this.timer.buildStart = performance.now();
this.logger.info(
"build",
green(`\u2713 Completed in ${getTimeStat(this.timer.init, performance.now())}.`)
);
const hasKey = hasEnvironmentKey();
const keyPromise = hasKey ? getEnvironmentKey() : createKey();
const opts = {
allPages,
settings: this.settings,
logger: this.logger,
manifest: this.manifest,
mode: this.mode,
origin: this.origin,
pageNames,
teardownCompiler: this.teardownCompiler,
viteConfig,
key: keyPromise
};
const { internals, ssrOutputChunkNames } = await viteBuild(opts);
await staticBuild(opts, internals, ssrOutputChunkNames);
this.timer.assetsStart = performance.now();
Object.keys(assets).map((k) => {
if (!assets[k]) return;
const filePath = new URL(`file://${k}`);
fs.mkdirSync(new URL("./", filePath), { recursive: true });
fs.writeFileSync(filePath, assets[k], "utf8");
delete assets[k];
});
this.logger.debug("build", timerMessage("Additional assets copied", this.timer.assetsStart));
await runHookBuildDone({
config: this.settings.config,
pages: pageNames,
routes: Object.values(allPages).flat().map((pageData) => pageData.route).concat(
this.settings.config.experimental.serverIslands ? [getServerIslandRouteData(this.settings.config)] : []
),
logging: this.logger,
cacheManifest: internals.cacheManifestUsed
});
if (this.logger.level && levels[this.logger.level()] <= levels["info"]) {
await this.printStats({
logger: this.logger,
timeStart: this.timer.init,
pageCount: pageNames.length,
buildMode: this.settings.config.output
});
}
}
/** Build the given Astro project. */
async run() {
this.settings.timer.start("Total build");
const setupData = await this.setup();
try {
await this.build(setupData);
} catch (_err) {
throw _err;
} finally {
this.settings.timer.end("Total build");
this.settings.timer.writeStats();
}
}
validateConfig() {
const { config } = this.settings;
if (config.outDir.toString() === config.root.toString()) {
throw new Error(
`the outDir cannot be the root folder. Please build to a folder such as dist.`
);
}
}
/** Stats */
async printStats({
logger,
timeStart,
pageCount,
buildMode
}) {
const total = getTimeStat(timeStart, performance.now());
let messages = [];
if (buildMode === "static") {
messages = [`${pageCount} page(s) built in`, bold(total)];
} else {
messages = ["Server built in", bold(total)];
}
logger.info("build", messages.join(" "));
logger.info("build", `${bold("Complete!")}`);
}
}
export {
build as default
};

139
node_modules/astro/dist/core/build/internal.d.ts generated vendored Normal file
View File

@@ -0,0 +1,139 @@
import type { Rollup } from 'vite';
import type { RouteData, SSRResult } from '../../@types/astro.js';
import type { PageBuildData, StylesheetAsset, ViteID } from './types.js';
export interface BuildInternals {
/**
* Each CSS module is named with a chunk id derived from the Astro pages they
* are used in by default. It's easy to crawl this relation in the SSR build as
* the Astro pages are the entrypoint, but not for the client build as hydratable
* components are the entrypoint instead. This map is used as a cache from the SSR
* build so the client can pick up the same information and use the same chunk ids.
*/
cssModuleToChunkIdMap: Map<string, string>;
hoistedScriptIdToHoistedMap: Map<string, Set<string>>;
hoistedScriptIdToPagesMap: Map<string, Set<string>>;
/**
* Used by the `directRenderScript` option. If script is inlined, its id and
* inlined code is mapped here. The resolved id is an URL like "/_astro/something.js"
* but will no longer exist as the content is now inlined in this map.
*/
inlinedScripts: Map<string, string>;
entrySpecifierToBundleMap: Map<string, string>;
/**
* A map for page-specific information.
*/
pagesByKeys: Map<string, PageBuildData>;
/**
* A map for page-specific information by Vite ID (a path-like string)
*/
pagesByViteID: Map<ViteID, PageBuildData>;
/**
* A map for page-specific information by a client:only component
*/
pagesByClientOnly: Map<string, Set<PageBuildData>>;
/**
* A map for page-specific information by a script in an Astro file
*/
pagesByScriptId: Map<string, Set<PageBuildData>>;
/**
* A map of hydrated components to export names that are discovered during the SSR build.
* These will be used as the top-level entrypoints for the client build.
*
* @example
* '/project/Component1.jsx' => ['default']
* '/project/Component2.jsx' => ['Counter', 'Timer']
* '/project/Component3.jsx' => ['*']
*/
discoveredHydratedComponents: Map<string, string[]>;
/**
* A list of client:only components to export names that are discovered during the SSR build.
* These will be used as the top-level entrypoints for the client build.
*
* @example
* '/project/Component1.jsx' => ['default']
* '/project/Component2.jsx' => ['Counter', 'Timer']
* '/project/Component3.jsx' => ['*']
*/
discoveredClientOnlyComponents: Map<string, string[]>;
/**
* A list of hoisted scripts that are discovered during the SSR build
* These will be used as the top-level entrypoints for the client build.
*/
discoveredScripts: Set<string>;
cachedClientEntries: string[];
cacheManifestUsed: boolean;
/**
* Map of propagated module ids (usually something like `/Users/...blog.mdx?astroPropagatedAssets`)
* to a set of stylesheets that it uses.
*/
propagatedStylesMap: Map<string, Set<StylesheetAsset>>;
/**
* Map of propagated module ids (usually something like `/Users/...blog.mdx?astroPropagatedAssets`)
* to a set of hoisted scripts that it uses.
*/
propagatedScriptsMap: Map<string, Set<string>>;
staticFiles: Set<string>;
ssrEntryChunk?: Rollup.OutputChunk;
manifestEntryChunk?: Rollup.OutputChunk;
manifestFileName?: string;
entryPoints: Map<RouteData, URL>;
componentMetadata: SSRResult['componentMetadata'];
middlewareEntryPoint?: URL;
/**
* Chunks in the bundle that are only used in prerendering that we can delete later
*/
prerenderOnlyChunks: Rollup.OutputChunk[];
}
/**
* Creates internal maps used to coordinate the CSS and HTML plugins.
* @returns {BuildInternals}
*/
export declare function createBuildInternals(): BuildInternals;
export declare function trackPageData(internals: BuildInternals, _component: string, pageData: PageBuildData, componentModuleId: string, componentURL: URL): void;
/**
* Tracks client-only components to the pages they are associated with.
*/
export declare function trackClientOnlyPageDatas(internals: BuildInternals, pageData: PageBuildData, clientOnlys: string[]): void;
/**
* Tracks scripts to the pages they are associated with. (experimental.directRenderScript)
*/
export declare function trackScriptPageDatas(internals: BuildInternals, pageData: PageBuildData, scriptIds: string[]): void;
export declare function getPageDatasByClientOnlyID(internals: BuildInternals, viteid: ViteID): Generator<PageBuildData, void, unknown>;
/**
* From its route and component, get the page data from the build internals.
* @param internals Build Internals with all the pages
* @param route The route of the page, used to identify the page
* @param component The component of the page, used to identify the page
*/
export declare function getPageData(internals: BuildInternals, route: string, component: string): PageBuildData | undefined;
/**
* Map internals.pagesByKeys to a new map with the public key instead of the internal key.
* This function is only used to avoid breaking changes in the Integrations API, after we changed the way
* we identify pages, from the entrypoint component to an internal key.
* If the page component is unique -> the public key is the component path. (old behavior)
* If the page component is shared -> the public key is the internal key. (new behavior)
* The new behavior on shared entrypoint it's not a breaking change, because it was not supported before.
* @param pagesByKeys A map of all page data by their internal key
*/
export declare function getPageDatasWithPublicKey(pagesByKeys: Map<string, PageBuildData>): Map<string, PageBuildData>;
export declare function getPageDataByViteID(internals: BuildInternals, viteid: ViteID): PageBuildData | undefined;
export declare function hasPrerenderedPages(internals: BuildInternals): boolean;
interface OrderInfo {
depth: number;
order: number;
}
/**
* Sort a page's CSS by depth. A higher depth means that the CSS comes from shared subcomponents.
* A lower depth means it comes directly from the top-level page.
* Can be used to sort stylesheets so that shared rules come first
* and page-specific rules come after.
*/
export declare function cssOrder(a: OrderInfo, b: OrderInfo): 1 | -1;
export declare function mergeInlineCss(acc: Array<StylesheetAsset>, current: StylesheetAsset): Array<StylesheetAsset>;
/**
* Get all pages data from the build internals, using a specific hoisted script id.
* @param internals Build Internals with all the pages
* @param id Hoisted script id, used to identify the pages using it
*/
export declare function getPageDatasByHoistedScriptId(internals: BuildInternals, id: string): PageBuildData[];
export {};

182
node_modules/astro/dist/core/build/internal.js generated vendored Normal file
View File

@@ -0,0 +1,182 @@
import { prependForwardSlash, removeFileExtension } from "../path.js";
import { viteID } from "../util.js";
import { makePageDataKey } from "./plugins/util.js";
function createBuildInternals() {
const hoistedScriptIdToHoistedMap = /* @__PURE__ */ new Map();
const hoistedScriptIdToPagesMap = /* @__PURE__ */ new Map();
return {
cachedClientEntries: [],
cssModuleToChunkIdMap: /* @__PURE__ */ new Map(),
hoistedScriptIdToHoistedMap,
hoistedScriptIdToPagesMap,
inlinedScripts: /* @__PURE__ */ new Map(),
entrySpecifierToBundleMap: /* @__PURE__ */ new Map(),
pagesByKeys: /* @__PURE__ */ new Map(),
pagesByViteID: /* @__PURE__ */ new Map(),
pagesByClientOnly: /* @__PURE__ */ new Map(),
pagesByScriptId: /* @__PURE__ */ new Map(),
propagatedStylesMap: /* @__PURE__ */ new Map(),
propagatedScriptsMap: /* @__PURE__ */ new Map(),
discoveredHydratedComponents: /* @__PURE__ */ new Map(),
discoveredClientOnlyComponents: /* @__PURE__ */ new Map(),
discoveredScripts: /* @__PURE__ */ new Set(),
staticFiles: /* @__PURE__ */ new Set(),
componentMetadata: /* @__PURE__ */ new Map(),
entryPoints: /* @__PURE__ */ new Map(),
cacheManifestUsed: false,
prerenderOnlyChunks: []
};
}
function trackPageData(internals, _component, pageData, componentModuleId, componentURL) {
pageData.moduleSpecifier = componentModuleId;
internals.pagesByKeys.set(pageData.key, pageData);
internals.pagesByViteID.set(viteID(componentURL), pageData);
}
function trackClientOnlyPageDatas(internals, pageData, clientOnlys) {
for (const clientOnlyComponent of clientOnlys) {
let pageDataSet;
if (internals.pagesByClientOnly.has(clientOnlyComponent)) {
pageDataSet = internals.pagesByClientOnly.get(clientOnlyComponent);
} else {
pageDataSet = /* @__PURE__ */ new Set();
internals.pagesByClientOnly.set(clientOnlyComponent, pageDataSet);
}
pageDataSet.add(pageData);
}
}
function trackScriptPageDatas(internals, pageData, scriptIds) {
for (const scriptId of scriptIds) {
let pageDataSet;
if (internals.pagesByScriptId.has(scriptId)) {
pageDataSet = internals.pagesByScriptId.get(scriptId);
} else {
pageDataSet = /* @__PURE__ */ new Set();
internals.pagesByScriptId.set(scriptId, pageDataSet);
}
pageDataSet.add(pageData);
}
}
function* getPageDatasByClientOnlyID(internals, viteid) {
const pagesByClientOnly = internals.pagesByClientOnly;
if (pagesByClientOnly.size) {
let pageBuildDatas = pagesByClientOnly.get(viteid);
if (!pageBuildDatas) {
let pathname = `/@fs${prependForwardSlash(viteid)}`;
pageBuildDatas = pagesByClientOnly.get(pathname);
}
if (!pageBuildDatas) {
let pathname = `/@fs${prependForwardSlash(removeFileExtension(viteid))}`;
pageBuildDatas = pagesByClientOnly.get(pathname);
}
if (pageBuildDatas) {
for (const pageData of pageBuildDatas) {
yield pageData;
}
}
}
}
function getPageData(internals, route, component) {
let pageData = internals.pagesByKeys.get(makePageDataKey(route, component));
if (pageData) {
return pageData;
}
return void 0;
}
function getPagesDatasByComponent(internals, component) {
const pageDatas = [];
internals.pagesByKeys.forEach((pageData) => {
if (component === pageData.component) pageDatas.push(pageData);
});
return pageDatas;
}
function getPageDatasWithPublicKey(pagesByKeys) {
const pagesWithPublicKey = /* @__PURE__ */ new Map();
const pagesByComponentsArray = Array.from(pagesByKeys.values()).map((pageData) => {
return { component: pageData.component, pageData };
});
const pagesWithUniqueComponent = pagesByComponentsArray.filter((page) => {
return pagesByComponentsArray.filter((p) => p.component === page.component).length === 1;
});
pagesWithUniqueComponent.forEach((page) => {
pagesWithPublicKey.set(page.component, page.pageData);
});
const pagesWithSharedComponent = pagesByComponentsArray.filter((page) => {
return pagesByComponentsArray.filter((p) => p.component === page.component).length > 1;
});
pagesWithSharedComponent.forEach((page) => {
pagesWithPublicKey.set(page.pageData.key, page.pageData);
});
return pagesWithPublicKey;
}
function getPageDataByViteID(internals, viteid) {
if (internals.pagesByViteID.has(viteid)) {
return internals.pagesByViteID.get(viteid);
}
return void 0;
}
function hasPrerenderedPages(internals) {
for (const pageData of internals.pagesByKeys.values()) {
if (pageData.route.prerender) {
return true;
}
}
return false;
}
function cssOrder(a, b) {
let depthA = a.depth, depthB = b.depth, orderA = a.order, orderB = b.order;
if (orderA === -1 && orderB >= 0) {
return 1;
} else if (orderB === -1 && orderA >= 0) {
return -1;
} else if (orderA > orderB) {
return 1;
} else if (orderA < orderB) {
return -1;
} else {
if (depthA === -1) {
return -1;
} else if (depthB === -1) {
return 1;
} else {
return depthA > depthB ? -1 : 1;
}
}
}
function mergeInlineCss(acc, current) {
const lastAdded = acc.at(acc.length - 1);
const lastWasInline = lastAdded?.type === "inline";
const currentIsInline = current?.type === "inline";
if (lastWasInline && currentIsInline) {
const merged = { type: "inline", content: lastAdded.content + current.content };
acc[acc.length - 1] = merged;
return acc;
}
acc.push(current);
return acc;
}
function getPageDatasByHoistedScriptId(internals, id) {
const set = internals.hoistedScriptIdToPagesMap.get(id);
const pageDatas = [];
if (set) {
for (const pageId of set) {
getPagesDatasByComponent(internals, pageId.slice(1)).forEach((pageData) => {
pageDatas.push(pageData);
});
}
}
return pageDatas;
}
export {
createBuildInternals,
cssOrder,
getPageData,
getPageDataByViteID,
getPageDatasByClientOnlyID,
getPageDatasByHoistedScriptId,
getPageDatasWithPublicKey,
hasPrerenderedPages,
mergeInlineCss,
trackClientOnlyPageDatas,
trackPageData,
trackScriptPageDatas
};

13
node_modules/astro/dist/core/build/page-data.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import type { AstroSettings, ManifestData } from '../../@types/astro.js';
import type { Logger } from '../logger/core.js';
import type { AllPagesData } from './types.js';
export interface CollectPagesDataOptions {
settings: AstroSettings;
logger: Logger;
manifest: ManifestData;
}
export interface CollectPagesDataResult {
assets: Record<string, string>;
allPages: AllPagesData;
}
export declare function collectPagesData(opts: CollectPagesDataOptions): CollectPagesDataResult;

43
node_modules/astro/dist/core/build/page-data.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import * as colors from "kleur/colors";
import { debug } from "../logger/core.js";
import { makePageDataKey } from "./plugins/util.js";
function collectPagesData(opts) {
const { settings, manifest } = opts;
const assets = {};
const allPages = {};
for (const route of manifest.routes) {
const key = makePageDataKey(route.route, route.component);
if (route.pathname) {
allPages[key] = {
key,
component: route.component,
route,
moduleSpecifier: "",
styles: [],
hoistedScript: void 0
};
if (settings.config.output === "static") {
const html = `${route.pathname}`.replace(/\/?$/, "/index.html");
debug(
"build",
`\u251C\u2500\u2500 ${colors.bold(colors.green("\u2714"))} ${route.component} \u2192 ${colors.yellow(html)}`
);
} else {
debug("build", `\u251C\u2500\u2500 ${colors.bold(colors.green("\u2714"))} ${route.component}`);
}
continue;
}
allPages[key] = {
key,
component: route.component,
route,
moduleSpecifier: "",
styles: [],
hoistedScript: void 0
};
}
return { assets, allPages };
}
export {
collectPagesData
};

51
node_modules/astro/dist/core/build/pipeline.d.ts generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import type { ComponentInstance, RewritePayload, RouteData, SSRResult } from '../../@types/astro.js';
import type { SSRManifest } from '../app/types.js';
import type { TryRewriteResult } from '../base-pipeline.js';
import { Pipeline } from '../render/index.js';
import { type BuildInternals } from './internal.js';
import type { PageBuildData, SinglePageBuiltModule, StaticBuildOptions } from './types.js';
/**
* The build pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files.
*/
export declare class BuildPipeline extends Pipeline {
#private;
readonly internals: BuildInternals;
readonly manifest: SSRManifest;
readonly options: StaticBuildOptions;
readonly config: import("../../@types/astro.js").AstroConfig;
readonly settings: import("../../@types/astro.js").AstroSettings;
readonly defaultRoutes: {
instance: ComponentInstance;
matchesComponent(filePath: URL): boolean;
route: string;
component: string;
}[];
get outFolder(): URL;
private constructor();
getRoutes(): RouteData[];
static create({ internals, manifest, options, }: Pick<BuildPipeline, 'internals' | 'manifest' | 'options'>): BuildPipeline;
/**
* The SSR build emits two important files:
* - dist/server/manifest.mjs
* - dist/renderers.mjs
*
* These two files, put together, will be used to generate the pages.
*
* ## Errors
*
* It will throw errors if the previous files can't be found in the file system.
*
* @param staticBuildOptions
*/
static retrieveManifest(staticBuildOptions: StaticBuildOptions, internals: BuildInternals): Promise<SSRManifest>;
headElements(routeData: RouteData): Pick<SSRResult, 'scripts' | 'styles' | 'links'>;
componentMetadata(): void;
/**
* It collects the routes to generate during the build.
* It returns a map of page information and their relative entry point as a string.
*/
retrieveRoutesToGenerate(): Map<PageBuildData, string>;
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
retrieveSsrEntry(route: RouteData, filePath: string): Promise<SinglePageBuiltModule>;
}

287
node_modules/astro/dist/core/build/pipeline.js generated vendored Normal file
View File

@@ -0,0 +1,287 @@
import { getOutputDirectory } from "../../prerender/utils.js";
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
import { routeIsFallback, routeIsRedirect } from "../redirects/helpers.js";
import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
import { Pipeline } from "../render/index.js";
import {
createAssetLink,
createModuleScriptsSet,
createStylesheetElementSet
} from "../render/ssr-element.js";
import { createDefaultRoutes } from "../routing/default.js";
import { findRouteToRewrite } from "../routing/rewrite.js";
import { isServerLikeOutput } from "../util.js";
import { getOutDirWithinCwd } from "./common.js";
import { cssOrder, getPageData, mergeInlineCss } from "./internal.js";
import { ASTRO_PAGE_MODULE_ID, ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugins/plugin-pages.js";
import { RESOLVED_SPLIT_MODULE_ID } from "./plugins/plugin-ssr.js";
import { getPagesFromVirtualModulePageName, getVirtualModulePageName } from "./plugins/util.js";
import { i18nHasFallback } from "./util.js";
class BuildPipeline extends Pipeline {
constructor(internals, manifest, options, config = options.settings.config, settings = options.settings, defaultRoutes = createDefaultRoutes(manifest)) {
const resolveCache = /* @__PURE__ */ new Map();
async function resolve(specifier) {
if (resolveCache.has(specifier)) {
return resolveCache.get(specifier);
}
const hashedFilePath = manifest.entryModules[specifier];
if (typeof hashedFilePath !== "string" || hashedFilePath === "") {
if (specifier === BEFORE_HYDRATION_SCRIPT_ID) {
resolveCache.set(specifier, "");
return "";
}
throw new Error(`Cannot find the built path for ${specifier}`);
}
const assetLink = createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
resolveCache.set(specifier, assetLink);
return assetLink;
}
const serverLike = isServerLikeOutput(config);
const streaming = serverLike;
super(
options.logger,
manifest,
options.mode,
manifest.renderers,
resolve,
serverLike,
streaming
);
this.internals = internals;
this.manifest = manifest;
this.options = options;
this.config = config;
this.settings = settings;
this.defaultRoutes = defaultRoutes;
}
#componentsInterner = /* @__PURE__ */ new WeakMap();
/**
* This cache is needed to map a single `RouteData` to its file path.
* @private
*/
#routesByFilePath = /* @__PURE__ */ new WeakMap();
get outFolder() {
const ssr = isServerLikeOutput(this.settings.config);
return ssr ? this.settings.config.build.server : getOutDirWithinCwd(this.settings.config.outDir);
}
getRoutes() {
return this.options.manifest.routes;
}
static create({
internals,
manifest,
options
}) {
return new BuildPipeline(internals, manifest, options);
}
/**
* The SSR build emits two important files:
* - dist/server/manifest.mjs
* - dist/renderers.mjs
*
* These two files, put together, will be used to generate the pages.
*
* ## Errors
*
* It will throw errors if the previous files can't be found in the file system.
*
* @param staticBuildOptions
*/
static async retrieveManifest(staticBuildOptions, internals) {
const config = staticBuildOptions.settings.config;
const baseDirectory = getOutputDirectory(config);
const manifestEntryUrl = new URL(
`${internals.manifestFileName}?time=${Date.now()}`,
baseDirectory
);
const { manifest } = await import(manifestEntryUrl.toString());
if (!manifest) {
throw new Error(
"Astro couldn't find the emitted manifest. This is an internal error, please file an issue."
);
}
const renderersEntryUrl = new URL(`renderers.mjs?time=${Date.now()}`, baseDirectory);
const renderers = await import(renderersEntryUrl.toString());
const middleware = internals.middlewareEntryPoint ? await import(internals.middlewareEntryPoint.toString()).then((mod) => {
return function() {
return { onRequest: mod.onRequest };
};
}) : manifest.middleware;
if (!renderers) {
throw new Error(
"Astro couldn't find the emitted renderers. This is an internal error, please file an issue."
);
}
return {
...manifest,
renderers: renderers.renderers,
middleware
};
}
headElements(routeData) {
const {
internals,
manifest: { assetsPrefix, base },
settings
} = this;
const links = /* @__PURE__ */ new Set();
const pageBuildData = getPageData(internals, routeData.route, routeData.component);
const scripts = createModuleScriptsSet(
pageBuildData?.hoistedScript ? [pageBuildData.hoistedScript] : [],
base,
assetsPrefix
);
const sortedCssAssets = pageBuildData?.styles.sort(cssOrder).map(({ sheet }) => sheet).reduce(mergeInlineCss, []);
const styles = createStylesheetElementSet(sortedCssAssets ?? [], base, assetsPrefix);
if (settings.scripts.some((script) => script.stage === "page")) {
const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
if (typeof hashedFilePath !== "string") {
throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
}
const src = createAssetLink(hashedFilePath, base, assetsPrefix);
scripts.add({
props: { type: "module", src },
children: ""
});
}
for (const script of settings.scripts) {
if (script.stage === "head-inline") {
scripts.add({
props: {},
children: script.content
});
}
}
return { scripts, styles, links };
}
componentMetadata() {
}
/**
* It collects the routes to generate during the build.
* It returns a map of page information and their relative entry point as a string.
*/
retrieveRoutesToGenerate() {
const pages = /* @__PURE__ */ new Map();
for (const [virtualModulePageName, filePath] of this.internals.entrySpecifierToBundleMap) {
if (virtualModulePageName.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) || virtualModulePageName.includes(RESOLVED_SPLIT_MODULE_ID)) {
let pageDatas = [];
if (virtualModulePageName.includes(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
pageDatas.push(
...getPagesFromVirtualModulePageName(
this.internals,
ASTRO_PAGE_RESOLVED_MODULE_ID,
virtualModulePageName
)
);
}
if (virtualModulePageName.includes(RESOLVED_SPLIT_MODULE_ID)) {
pageDatas.push(
...getPagesFromVirtualModulePageName(
this.internals,
RESOLVED_SPLIT_MODULE_ID,
virtualModulePageName
)
);
}
for (const pageData of pageDatas) {
pages.set(pageData, filePath);
}
}
}
for (const pageData of this.internals.pagesByKeys.values()) {
if (routeIsRedirect(pageData.route)) {
pages.set(pageData, pageData.component);
} else if (routeIsFallback(pageData.route) && (i18nHasFallback(this.config) || routeIsFallback(pageData.route) && pageData.route.route === "/")) {
const moduleSpecifier = getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component);
const filePath = this.internals.entrySpecifierToBundleMap.get(moduleSpecifier);
if (filePath) {
pages.set(pageData, filePath);
}
}
}
for (const [buildData, filePath] of pages.entries()) {
this.#routesByFilePath.set(buildData.route, filePath);
}
return pages;
}
async getComponentByRoute(routeData) {
if (this.#componentsInterner.has(routeData)) {
const entry = this.#componentsInterner.get(routeData);
return await entry.page();
}
for (const route of this.defaultRoutes) {
if (route.component === routeData.component) {
return route.instance;
}
}
const filePath = this.#routesByFilePath.get(routeData);
const module = await this.retrieveSsrEntry(routeData, filePath);
return module.page();
}
async tryRewrite(payload, request) {
const { routeData, pathname, newUrl } = findRouteToRewrite({
payload,
request,
routes: this.options.manifest.routes,
trailingSlash: this.config.trailingSlash,
buildFormat: this.config.build.format,
base: this.config.base
});
const componentInstance = await this.getComponentByRoute(routeData);
return { routeData, componentInstance, newUrl, pathname };
}
async retrieveSsrEntry(route, filePath) {
if (this.#componentsInterner.has(route)) {
return this.#componentsInterner.get(route);
}
let entry;
if (routeIsRedirect(route)) {
entry = await this.#getEntryForRedirectRoute(route, this.internals, this.outFolder);
} else if (routeIsFallback(route)) {
entry = await this.#getEntryForFallbackRoute(route, this.internals, this.outFolder);
} else {
const ssrEntryURLPage = createEntryURL(filePath, this.outFolder);
entry = await import(ssrEntryURLPage.toString());
}
this.#componentsInterner.set(route, entry);
return entry;
}
async #getEntryForFallbackRoute(route, _internals, outFolder) {
if (route.type !== "fallback") {
throw new Error(`Expected a redirect route.`);
}
if (route.redirectRoute) {
const filePath = getEntryFilePath(this.internals, route.redirectRoute);
if (filePath) {
const url = createEntryURL(filePath, outFolder);
const ssrEntryPage = await import(url.toString());
return ssrEntryPage;
}
}
return RedirectSinglePageBuiltModule;
}
async #getEntryForRedirectRoute(route, _internals, outFolder) {
if (route.type !== "redirect") {
throw new Error(`Expected a redirect route.`);
}
if (route.redirectRoute) {
const filePath = getEntryFilePath(this.internals, route.redirectRoute);
if (filePath) {
const url = createEntryURL(filePath, outFolder);
const ssrEntryPage = await import(url.toString());
return ssrEntryPage;
}
}
return RedirectSinglePageBuiltModule;
}
}
function createEntryURL(filePath, outFolder) {
return new URL("./" + filePath + `?time=${Date.now()}`, outFolder);
}
function getEntryFilePath(internals, pageData) {
const id = "\0" + getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component);
return internals.entrySpecifierToBundleMap.get(id);
}
export {
BuildPipeline
};

43
node_modules/astro/dist/core/build/plugin.d.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import type { Rollup, Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from './internal.js';
import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
type RollupOutputArray = Extract<ViteBuildReturn, Array<any>>;
type OutputChunkorAsset = RollupOutputArray[number]['output'][number];
type OutputChunk = Extract<OutputChunkorAsset, {
type: 'chunk';
}>;
export type BuildTarget = 'server' | 'client';
type MutateChunk = (chunk: OutputChunk, targets: BuildTarget[], newCode: string) => void;
export interface BuildBeforeHookResult {
enforce?: 'after-user-plugins';
vitePlugin: VitePlugin | VitePlugin[] | undefined;
}
export type AstroBuildPlugin = {
targets: BuildTarget[];
hooks?: {
'build:before'?: (opts: {
target: BuildTarget;
input: Set<string>;
}) => BuildBeforeHookResult | Promise<BuildBeforeHookResult>;
'build:post'?: (opts: {
ssrOutputs: RollupOutputArray;
clientOutputs: RollupOutputArray;
mutate: MutateChunk;
}) => void | Promise<void>;
};
};
export declare function createPluginContainer(options: StaticBuildOptions, internals: BuildInternals): {
options: StaticBuildOptions;
internals: BuildInternals;
register(plugin: AstroBuildPlugin): void;
runBeforeHook(target: BuildTarget, input: Set<string>): Promise<{
vitePlugins: (VitePlugin<any> | VitePlugin<any>[])[];
lastVitePlugins: (VitePlugin<any> | VitePlugin<any>[])[];
}>;
runPostHook(ssrOutputs: Rollup.RollupOutput[], clientOutputs: Rollup.RollupOutput[]): Promise<Map<string, {
targets: BuildTarget[];
code: string;
}>>;
};
export type AstroBuildPluginContainer = ReturnType<typeof createPluginContainer>;
export {};

61
node_modules/astro/dist/core/build/plugin.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
function createPluginContainer(options, internals) {
const plugins = /* @__PURE__ */ new Map();
const allPlugins = /* @__PURE__ */ new Set();
for (const target of ["client", "server"]) {
plugins.set(target, []);
}
return {
options,
internals,
register(plugin) {
allPlugins.add(plugin);
for (const target of plugin.targets) {
const targetPlugins = plugins.get(target) ?? [];
targetPlugins.push(plugin);
plugins.set(target, targetPlugins);
}
},
// Hooks
async runBeforeHook(target, input) {
let targetPlugins = plugins.get(target) ?? [];
let vitePlugins = [];
let lastVitePlugins = [];
for (const plugin of targetPlugins) {
if (plugin.hooks?.["build:before"]) {
let result = await plugin.hooks["build:before"]({ target, input });
if (result.vitePlugin) {
vitePlugins.push(result.vitePlugin);
}
}
}
return {
vitePlugins,
lastVitePlugins
};
},
async runPostHook(ssrOutputs, clientOutputs) {
const mutations = /* @__PURE__ */ new Map();
const mutate = (chunk, targets, newCode) => {
chunk.code = newCode;
mutations.set(chunk.fileName, {
targets,
code: newCode
});
};
for (const plugin of allPlugins) {
const postHook = plugin.hooks?.["build:post"];
if (postHook) {
await postHook({
ssrOutputs,
clientOutputs,
mutate
});
}
}
return mutations;
}
};
}
export {
createPluginContainer
};

View File

@@ -0,0 +1,2 @@
import type { AstroBuildPluginContainer } from '../plugin.js';
export declare function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer): void;

41
node_modules/astro/dist/core/build/plugins/index.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import { astroConfigBuildPlugin } from "../../../content/vite-plugin-content-assets.js";
import { astroHeadBuildPlugin } from "../../../vite-plugin-head/index.js";
import { pluginAnalyzer } from "./plugin-analyzer.js";
import { pluginChunks } from "./plugin-chunks.js";
import { pluginComponentEntry } from "./plugin-component-entry.js";
import { pluginContent } from "./plugin-content.js";
import { pluginCSS } from "./plugin-css.js";
import { pluginHoistedScripts } from "./plugin-hoisted-scripts.js";
import { pluginInternals } from "./plugin-internals.js";
import { pluginManifest } from "./plugin-manifest.js";
import { pluginMiddleware } from "./plugin-middleware.js";
import { pluginPages } from "./plugin-pages.js";
import { pluginPrerender } from "./plugin-prerender.js";
import { pluginRenderers } from "./plugin-renderers.js";
import { pluginScripts } from "./plugin-scripts.js";
import { pluginSSR, pluginSSRSplit } from "./plugin-ssr.js";
function registerAllPlugins({ internals, options, register }) {
register(pluginComponentEntry(internals));
register(pluginAnalyzer(options, internals));
register(pluginInternals(internals));
register(pluginManifest(options, internals));
register(pluginRenderers(options));
register(pluginMiddleware(options, internals));
register(pluginPages(options, internals));
register(pluginContent(options, internals));
register(pluginCSS(options, internals));
register(astroHeadBuildPlugin(internals));
register(pluginPrerender(options, internals));
register(astroConfigBuildPlugin(options, internals));
if (options.settings.config.experimental.directRenderScript) {
register(pluginScripts(internals));
} else {
register(pluginHoistedScripts(internals));
}
register(pluginSSR(options, internals));
register(pluginSSRSplit(options, internals));
register(pluginChunks());
}
export {
registerAllPlugins
};

View File

@@ -0,0 +1,6 @@
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare function vitePluginAnalyzer(options: StaticBuildOptions, internals: BuildInternals): VitePlugin;
export declare function pluginAnalyzer(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,162 @@
import { PROPAGATED_ASSET_FLAG } from "../../../content/consts.js";
import { prependForwardSlash } from "../../../core/path.js";
import {
getParentModuleInfos,
getTopLevelPageModuleInfos,
moduleIsTopLevelPage
} from "../graph.js";
import {
getPageDataByViteID,
trackClientOnlyPageDatas,
trackScriptPageDatas
} from "../internal.js";
function isPropagatedAsset(id) {
try {
return new URL("file://" + id).searchParams.has(PROPAGATED_ASSET_FLAG);
} catch {
return false;
}
}
function vitePluginAnalyzer(options, internals) {
function hoistedScriptScanner() {
const uniqueHoistedIds = /* @__PURE__ */ new Map();
const pageScriptsMap = /* @__PURE__ */ new Map();
return {
async scan(scripts, from) {
const hoistedScripts = /* @__PURE__ */ new Set();
for (let i = 0; i < scripts.length; i++) {
const hid = `${from.replace("/@fs", "")}?astro&type=script&index=${i}&lang.ts`;
hoistedScripts.add(hid);
}
if (hoistedScripts.size) {
for (const parentInfo of getParentModuleInfos(from, this, isPropagatedAsset)) {
if (isPropagatedAsset(parentInfo.id)) {
if (!internals.propagatedScriptsMap.has(parentInfo.id)) {
internals.propagatedScriptsMap.set(parentInfo.id, /* @__PURE__ */ new Set());
}
const propagatedScripts = internals.propagatedScriptsMap.get(parentInfo.id);
for (const hid of hoistedScripts) {
propagatedScripts.add(hid);
}
} else if (moduleIsTopLevelPage(parentInfo)) {
if (!pageScriptsMap.has(parentInfo.id)) {
pageScriptsMap.set(parentInfo.id, {
hoistedSet: /* @__PURE__ */ new Set()
});
}
const pageScripts = pageScriptsMap.get(parentInfo.id);
for (const hid of hoistedScripts) {
pageScripts.hoistedSet.add(hid);
}
}
}
}
},
finalize() {
for (const propagatedScripts of internals.propagatedScriptsMap.values()) {
for (const propagatedScript of propagatedScripts) {
internals.discoveredScripts.add(propagatedScript);
}
}
for (const [pageId, { hoistedSet }] of pageScriptsMap) {
const pageData = getPageDataByViteID(internals, pageId);
if (!pageData) continue;
const { component } = pageData;
const astroModuleId = prependForwardSlash(component);
const uniqueHoistedId = JSON.stringify(Array.from(hoistedSet).sort());
let moduleId;
if (uniqueHoistedIds.has(uniqueHoistedId)) {
moduleId = uniqueHoistedIds.get(uniqueHoistedId);
} else {
moduleId = `/astro/hoisted.js?q=${uniqueHoistedIds.size}`;
uniqueHoistedIds.set(uniqueHoistedId, moduleId);
}
internals.discoveredScripts.add(moduleId);
if (internals.hoistedScriptIdToPagesMap.has(moduleId)) {
const pages = internals.hoistedScriptIdToPagesMap.get(moduleId);
pages.add(astroModuleId);
} else {
internals.hoistedScriptIdToPagesMap.set(moduleId, /* @__PURE__ */ new Set([astroModuleId]));
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedSet);
}
}
}
};
}
return {
name: "@astro/rollup-plugin-astro-analyzer",
async generateBundle() {
const hoistScanner = options.settings.config.experimental.directRenderScript ? { scan: async () => {
}, finalize: () => {
} } : hoistedScriptScanner();
const ids = this.getModuleIds();
for (const id of ids) {
const info = this.getModuleInfo(id);
if (!info?.meta?.astro) continue;
const astro = info.meta.astro;
for (const c of astro.hydratedComponents) {
const rid = c.resolvedPath ? decodeURI(c.resolvedPath) : c.specifier;
if (internals.discoveredHydratedComponents.has(rid)) {
const exportNames = internals.discoveredHydratedComponents.get(rid);
exportNames?.push(c.exportName);
} else {
internals.discoveredHydratedComponents.set(rid, [c.exportName]);
}
}
await hoistScanner.scan.call(this, astro.scripts, id);
if (astro.clientOnlyComponents.length) {
const clientOnlys = [];
for (const c of astro.clientOnlyComponents) {
const cid = c.resolvedPath ? decodeURI(c.resolvedPath) : c.specifier;
if (internals.discoveredClientOnlyComponents.has(cid)) {
const exportNames = internals.discoveredClientOnlyComponents.get(cid);
exportNames?.push(c.exportName);
} else {
internals.discoveredClientOnlyComponents.set(cid, [c.exportName]);
}
clientOnlys.push(cid);
const resolvedId = await this.resolve(c.specifier, id);
if (resolvedId) {
clientOnlys.push(resolvedId.id);
}
}
for (const pageInfo of getTopLevelPageModuleInfos(id, this)) {
const newPageData = getPageDataByViteID(internals, pageInfo.id);
if (!newPageData) continue;
trackClientOnlyPageDatas(internals, newPageData, clientOnlys);
}
}
if (options.settings.config.experimental.directRenderScript && astro.scripts.length) {
const scriptIds = astro.scripts.map(
(_, i) => `${id.replace("/@fs", "")}?astro&type=script&index=${i}&lang.ts`
);
for (const scriptId of scriptIds) {
internals.discoveredScripts.add(scriptId);
}
for (const pageInfo of getTopLevelPageModuleInfos(id, this)) {
const newPageData = getPageDataByViteID(internals, pageInfo.id);
if (!newPageData) continue;
trackScriptPageDatas(internals, newPageData, scriptIds);
}
}
}
hoistScanner.finalize();
}
};
}
function pluginAnalyzer(options, internals) {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginAnalyzer(options, internals)
};
}
}
};
}
export {
pluginAnalyzer,
vitePluginAnalyzer
};

View File

@@ -0,0 +1,4 @@
import type { Plugin as VitePlugin } from 'vite';
import type { AstroBuildPlugin } from '../plugin.js';
export declare function vitePluginChunks(): VitePlugin;
export declare function pluginChunks(): AstroBuildPlugin;

View File

@@ -0,0 +1,37 @@
import { extendManualChunks } from "./util.js";
function vitePluginChunks() {
return {
name: "astro:chunks",
outputOptions(outputOptions) {
extendManualChunks(outputOptions, {
after(id) {
if (id.includes("astro/dist/runtime/server/")) {
return "astro/server";
}
if (id.includes("astro/dist/runtime")) {
return "astro";
}
if (id.includes("astro/dist/env/setup")) {
return "astro/env-setup";
}
}
});
}
};
}
function pluginChunks() {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginChunks()
};
}
}
};
}
export {
pluginChunks,
vitePluginChunks
};

View File

@@ -0,0 +1,12 @@
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
export declare const astroEntryPrefix = "\0astro-entry:";
/**
* When adding hydrated or client:only components as Rollup inputs, sometimes we're not using all
* of the export names, e.g. `import { Counter } from './ManyComponents.jsx'`. This plugin proxies
* entries to re-export only the names the user is using.
*/
export declare function vitePluginComponentEntry(internals: BuildInternals): VitePlugin;
export declare function normalizeEntryId(id: string): string;
export declare function pluginComponentEntry(internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,73 @@
const astroEntryPrefix = "\0astro-entry:";
function vitePluginComponentEntry(internals) {
const componentToExportNames = /* @__PURE__ */ new Map();
mergeComponentExportNames(internals.discoveredHydratedComponents);
mergeComponentExportNames(internals.discoveredClientOnlyComponents);
for (const [componentId, exportNames] of componentToExportNames) {
if (exportNames.some((name) => name.includes(".") || name === "*")) {
componentToExportNames.delete(componentId);
} else {
componentToExportNames.set(componentId, Array.from(new Set(exportNames)));
}
}
function mergeComponentExportNames(components) {
for (const [componentId, exportNames] of components) {
if (componentToExportNames.has(componentId)) {
componentToExportNames.get(componentId)?.push(...exportNames);
} else {
componentToExportNames.set(componentId, exportNames);
}
}
}
return {
name: "@astro/plugin-component-entry",
enforce: "pre",
config(config) {
const rollupInput = config.build?.rollupOptions?.input;
if (Array.isArray(rollupInput)) {
config.build.rollupOptions.input = rollupInput.map((id) => {
if (componentToExportNames.has(id)) {
return astroEntryPrefix + id;
} else {
return id;
}
});
}
},
async resolveId(id) {
if (id.startsWith(astroEntryPrefix)) {
return id;
}
},
async load(id) {
if (id.startsWith(astroEntryPrefix)) {
const componentId = id.slice(astroEntryPrefix.length);
const exportNames = componentToExportNames.get(componentId);
if (exportNames) {
return `export { ${exportNames.join(", ")} } from ${JSON.stringify(componentId)}`;
}
}
}
};
}
function normalizeEntryId(id) {
return id.startsWith(astroEntryPrefix) ? id.slice(astroEntryPrefix.length) : id;
}
function pluginComponentEntry(internals) {
return {
targets: ["client"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginComponentEntry(internals)
};
}
}
};
}
export {
astroEntryPrefix,
normalizeEntryId,
pluginComponentEntry,
vitePluginComponentEntry
};

View File

@@ -0,0 +1,5 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare function copyContentToCache(opts: StaticBuildOptions): Promise<string[]>;
export declare function pluginContent(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,394 @@
import { createHash } from "node:crypto";
import fsMod from "node:fs";
import { fileURLToPath } from "node:url";
import glob from "fast-glob";
import pLimit from "p-limit";
import { normalizePath } from "vite";
import { CONTENT_RENDER_FLAG, PROPAGATED_ASSET_FLAG } from "../../../content/consts.js";
import { hasContentFlag } from "../../../content/utils.js";
import {
generateContentEntryFile,
generateLookupMap
} from "../../../content/vite-plugin-content-virtual-mod.js";
import { configPaths } from "../../config/index.js";
import { emptyDir } from "../../fs/index.js";
import {
appendForwardSlash,
joinPaths,
removeFileExtension,
removeLeadingForwardSlash
} from "../../path.js";
import { isContentCollectionsCacheEnabled } from "../../util.js";
import { addRollupInput } from "../add-rollup-input.js";
import { CHUNKS_PATH, CONTENT_PATH } from "../consts.js";
import { copyFiles } from "../static-build.js";
import { encodeName } from "../util.js";
import { extendManualChunks } from "./util.js";
const CONTENT_CACHE_DIR = "./" + CONTENT_PATH;
const CONTENT_MANIFEST_FILE = "./manifest.json";
const CONTENT_MANIFEST_VERSION = 1;
const virtualEmptyModuleId = `virtual:empty-content`;
const resolvedVirtualEmptyModuleId = `\0${virtualEmptyModuleId}`;
const NO_MANIFEST_VERSION = -1;
function createContentManifest() {
return {
version: NO_MANIFEST_VERSION,
entries: [],
serverEntries: [],
clientEntries: [],
lockfiles: "",
configs: ""
};
}
const getContentRoot = (config) => new URL("./content/", config.outDir);
const getContentCacheDir = (config) => new URL(CONTENT_CACHE_DIR, config.cacheDir);
const getCacheTmp = (contentCacheDir) => new URL("./.tmp/", contentCacheDir);
function vitePluginContent(opts, lookupMap, internals, cachedBuildOutput) {
const { config } = opts.settings;
const distContentRoot = getContentRoot(config);
const contentCacheDir = getContentCacheDir(config);
const contentManifestFile = new URL(CONTENT_MANIFEST_FILE, contentCacheDir);
let oldManifest = createContentManifest();
let newManifest = createContentManifest();
let entries;
let injectedEmptyFile = false;
let currentManifestState = "valid";
if (fsMod.existsSync(contentManifestFile)) {
try {
const data = fsMod.readFileSync(contentManifestFile, { encoding: "utf8" });
oldManifest = JSON.parse(data);
} catch {
}
}
return {
name: "@astro/plugin-build-content",
async options(options) {
let newOptions = Object.assign({}, options);
newManifest = await generateContentManifest(opts, lookupMap);
entries = getEntriesFromManifests(oldManifest, newManifest);
currentManifestState = manifestState(oldManifest, newManifest);
if (currentManifestState === "valid") {
internals.cachedClientEntries = oldManifest.clientEntries;
} else {
let logReason = "";
switch (currentManifestState) {
case "config-mismatch":
logReason = "Astro config has changed";
break;
case "lockfile-mismatch":
logReason = "Lockfiles have changed";
break;
case "no-entries":
logReason = "No content collections entries cached";
break;
case "version-mismatch":
logReason = "The cache manifest version has changed";
break;
case "no-manifest":
logReason = "No content manifest was found in the cache";
break;
}
opts.logger.info("build", `Cache invalid, rebuilding from source. Reason: ${logReason}.`);
}
for (const { type, entry } of entries.buildFromSource) {
const fileURL = encodeURI(joinPaths(opts.settings.config.root.toString(), entry));
const input = fileURLToPath(fileURL);
const inputs = [`${input}?${collectionTypeToFlag(type)}`];
if (type === "content") {
inputs.push(`${input}?${CONTENT_RENDER_FLAG}`);
}
newOptions = addRollupInput(newOptions, inputs);
}
if (currentManifestState === "valid") {
for (const { cached, dist } of cachedBuildOutput) {
if (fsMod.existsSync(cached)) {
await copyFiles(cached, dist, true);
}
}
const cacheExists = fsMod.existsSync(contentCacheDir);
if (cacheExists) {
await copyFiles(contentCacheDir, distContentRoot, false);
}
}
if (entries.buildFromSource.length === 0) {
newOptions = addRollupInput(newOptions, [virtualEmptyModuleId]);
injectedEmptyFile = true;
}
return newOptions;
},
outputOptions(outputOptions) {
const rootPath = normalizePath(fileURLToPath(opts.settings.config.root));
const srcPath = normalizePath(fileURLToPath(opts.settings.config.srcDir));
const entryCache = /* @__PURE__ */ new Map();
extendManualChunks(outputOptions, {
before(id, meta) {
if (id.startsWith(srcPath) && id.slice(srcPath.length).startsWith("content")) {
const info = meta.getModuleInfo(id);
if (info?.dynamicImporters.length === 1 && hasContentFlag(info.dynamicImporters[0], PROPAGATED_ASSET_FLAG)) {
const [srcRelativePath2] = id.replace(rootPath, "/").split("?");
const resultId = encodeName(
`${removeLeadingForwardSlash(removeFileExtension(srcRelativePath2))}.render.mjs`
);
return resultId;
}
const [srcRelativePath, flag] = id.replace(rootPath, "/").split("?");
const collectionEntry = findEntryFromSrcRelativePath(
lookupMap,
srcRelativePath,
entryCache
);
if (collectionEntry) {
let suffix = ".mjs";
if (flag === PROPAGATED_ASSET_FLAG) {
suffix = ".entry.mjs";
}
id = removeLeadingForwardSlash(
removeFileExtension(encodeName(id.replace(srcPath, "/")))
) + suffix;
return id;
}
}
}
});
},
resolveId(id) {
if (id === virtualEmptyModuleId) {
return resolvedVirtualEmptyModuleId;
}
},
async load(id) {
if (id === resolvedVirtualEmptyModuleId) {
return {
code: `// intentionally left empty!
export default {}`
};
}
},
async generateBundle(_options, bundle) {
const code = await generateContentEntryFile({
settings: opts.settings,
fs: fsMod,
lookupMap,
IS_DEV: false,
IS_SERVER: false,
isClient: false
});
this.emitFile({
type: "prebuilt-chunk",
code,
fileName: "content/entry.mjs"
});
if (!injectedEmptyFile) return;
Object.keys(bundle).forEach((key) => {
const mod = bundle[key];
if (mod.type === "asset") return;
if (mod.facadeModuleId === resolvedVirtualEmptyModuleId) {
delete bundle[key];
}
});
},
async writeBundle() {
const clientComponents = /* @__PURE__ */ new Set([
...oldManifest.clientEntries,
...internals.discoveredHydratedComponents.keys(),
...internals.discoveredClientOnlyComponents.keys(),
...internals.discoveredScripts
]);
const serverComponents = /* @__PURE__ */ new Set([
...oldManifest.serverEntries,
...internals.discoveredHydratedComponents.keys()
]);
newManifest.serverEntries = Array.from(serverComponents);
newManifest.clientEntries = Array.from(clientComponents);
const cacheExists = fsMod.existsSync(contentCacheDir);
if (cacheExists && currentManifestState !== "valid") {
emptyDir(contentCacheDir);
}
await fsMod.promises.mkdir(contentCacheDir, { recursive: true });
await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), {
encoding: "utf8"
});
}
};
}
function findEntryFromSrcRelativePath(lookupMap, srcRelativePath, entryCache) {
let value = entryCache.get(srcRelativePath);
if (value) return value;
for (const collection of Object.values(lookupMap)) {
for (const entry of Object.values(collection)) {
for (const entryFile of Object.values(entry)) {
if (entryFile === srcRelativePath) {
value = entryFile;
entryCache.set(srcRelativePath, entryFile);
return value;
}
}
}
}
}
function getEntriesFromManifests(oldManifest, newManifest) {
const { entries: oldEntries } = oldManifest;
const { entries: newEntries } = newManifest;
let entries = { restoreFromCache: [], buildFromSource: [] };
const newEntryMap = new Map(newEntries);
if (manifestState(oldManifest, newManifest) !== "valid") {
entries.buildFromSource = Array.from(newEntryMap.keys());
return entries;
}
const oldEntryHashMap = new Map(
oldEntries.map(([key, hash]) => [hash, key])
);
for (const [entry, hash] of newEntryMap) {
if (oldEntryHashMap.has(hash)) {
entries.restoreFromCache.push(entry);
} else {
entries.buildFromSource.push(entry);
}
}
return entries;
}
function manifestState(oldManifest, newManifest) {
if (oldManifest.version === NO_MANIFEST_VERSION) {
return "no-manifest";
}
if (oldManifest.version !== newManifest.version) {
return "version-mismatch";
}
if (oldManifest.entries.length === 0) {
return "no-entries";
}
if (oldManifest.lockfiles !== newManifest.lockfiles || newManifest.lockfiles === "") {
return "lockfile-mismatch";
}
if (oldManifest.configs !== newManifest.configs) {
return "config-mismatch";
}
return "valid";
}
async function generateContentManifest(opts, lookupMap) {
let manifest = createContentManifest();
manifest.version = CONTENT_MANIFEST_VERSION;
const limit = pLimit(10);
const promises = [];
for (const [collection, { type, entries }] of Object.entries(lookupMap)) {
for (const entry of Object.values(entries)) {
const key = { collection, type, entry };
const fileURL = new URL(encodeURI(joinPaths(opts.settings.config.root.toString(), entry)));
promises.push(
limit(async () => {
const data = await fsMod.promises.readFile(fileURL, { encoding: "utf8" });
manifest.entries.push([key, checksum(data, fileURL.toString())]);
})
);
}
}
const [lockfiles, configs] = await Promise.all([
lockfilesHash(opts.settings.config.root),
configHash(opts.settings.config.root)
]);
manifest.lockfiles = lockfiles;
manifest.configs = configs;
await Promise.all(promises);
return manifest;
}
async function pushBufferInto(fileURL, buffers) {
try {
const handle = await fsMod.promises.open(fileURL, "r");
const data = await handle.readFile();
buffers.push(data);
await handle.close();
} catch {
}
}
async function lockfilesHash(root) {
const lockfiles = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb"];
const datas = [];
const promises = [];
for (const lockfileName of lockfiles) {
const fileURL = new URL(`./${lockfileName}`, root);
promises.push(pushBufferInto(fileURL, datas));
}
await Promise.all(promises);
return checksum(...datas);
}
async function configHash(root) {
const configFileNames = configPaths;
for (const configPath of configFileNames) {
try {
const fileURL = new URL(`./${configPath}`, root);
const data = await fsMod.promises.readFile(fileURL);
const hash = checksum(data);
return hash;
} catch {
}
}
return checksum(`export default {}`);
}
function checksum(...datas) {
const hash = createHash("sha1");
datas.forEach((data) => hash.update(data));
return hash.digest("base64");
}
function collectionTypeToFlag(type) {
const name = type[0].toUpperCase() + type.slice(1);
return `astro${name}CollectionEntry`;
}
async function copyContentToCache(opts) {
const { config } = opts.settings;
const distContentRoot = getContentRoot(config);
const contentCacheDir = getContentCacheDir(config);
const cacheTmp = getCacheTmp(contentCacheDir);
await fsMod.promises.mkdir(cacheTmp, { recursive: true });
await copyFiles(distContentRoot, cacheTmp, true);
await copyFiles(cacheTmp, contentCacheDir);
let files = [];
await Promise.all([
glob(`**/*.{mjs,json}`, {
cwd: fileURLToPath(cacheTmp)
}).then((f) => files.push(...f.map((file) => CONTENT_PATH + file))),
glob(`**/*.{mjs,json}`, {
cwd: fileURLToPath(new URL("./" + CHUNKS_PATH, config.outDir))
}).then((f) => files.push(...f.map((file) => CHUNKS_PATH + file)))
]);
await fsMod.promises.rm(cacheTmp, { recursive: true, force: true });
return files;
}
function pluginContent(opts, internals) {
const { cacheDir, outDir } = opts.settings.config;
const chunksFolder = "./" + CHUNKS_PATH;
const assetsFolder = "./" + appendForwardSlash(opts.settings.config.build.assets);
const cachedBuildOutput = [
{ cached: new URL(chunksFolder, cacheDir), dist: new URL(chunksFolder, outDir) },
{ cached: new URL(assetsFolder, cacheDir), dist: new URL(assetsFolder, outDir) }
];
return {
targets: ["server"],
hooks: {
async "build:before"() {
if (!isContentCollectionsCacheEnabled(opts.settings.config)) {
return { vitePlugin: void 0 };
}
const lookupMap = await generateLookupMap({ settings: opts.settings, fs: fsMod });
return {
vitePlugin: vitePluginContent(opts, lookupMap, internals, cachedBuildOutput)
};
},
async "build:post"() {
if (!isContentCollectionsCacheEnabled(opts.settings.config)) {
return;
}
const promises = [];
for (const { cached, dist } of cachedBuildOutput) {
if (fsMod.existsSync(dist)) {
promises.push(copyFiles(dist, cached, true));
}
}
if (promises.length) await Promise.all(promises);
}
}
};
}
export {
copyContentToCache,
pluginContent
};

View File

@@ -0,0 +1,5 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
/***** ASTRO PLUGIN *****/
export declare function pluginCSS(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,230 @@
import { isBuildableCSSRequest } from "../../../vite-plugin-astro-server/util.js";
import { hasAssetPropagationFlag } from "../../../content/index.js";
import * as assetName from "../css-asset-name.js";
import {
getParentExtendedModuleInfos,
getParentModuleInfos,
moduleIsTopLevelPage
} from "../graph.js";
import {
getPageDataByViteID,
getPageDatasByClientOnlyID,
getPageDatasByHoistedScriptId
} from "../internal.js";
import { extendManualChunks, shouldInlineAsset } from "./util.js";
function pluginCSS(options, internals) {
return {
targets: ["client", "server"],
hooks: {
"build:before": ({ target }) => {
let plugins = rollupPluginAstroBuildCSS({
buildOptions: options,
internals,
target
});
return {
vitePlugin: plugins
};
}
}
};
}
function rollupPluginAstroBuildCSS(options) {
const { internals, buildOptions } = options;
const { settings } = buildOptions;
let resolvedConfig;
const pagesToCss = {};
const moduleIdToPropagatedCss = {};
const cssBuildPlugin = {
name: "astro:rollup-plugin-build-css",
outputOptions(outputOptions) {
const assetFileNames = outputOptions.assetFileNames;
const namingIncludesHash = assetFileNames?.toString().includes("[hash]");
const createNameForParentPages = namingIncludesHash ? assetName.shortHashedName(settings) : assetName.createSlugger(settings);
extendManualChunks(outputOptions, {
after(id, meta) {
if (isBuildableCSSRequest(id)) {
if (options.target === "client") {
return internals.cssModuleToChunkIdMap.get(id);
}
const ctx = { getModuleInfo: meta.getModuleInfo };
for (const pageInfo of getParentModuleInfos(id, ctx)) {
if (hasAssetPropagationFlag(pageInfo.id)) {
const chunkId2 = assetName.createNameHash(id, [id], settings);
internals.cssModuleToChunkIdMap.set(id, chunkId2);
return chunkId2;
}
}
const chunkId = createNameForParentPages(id, meta);
internals.cssModuleToChunkIdMap.set(id, chunkId);
return chunkId;
}
}
});
},
async generateBundle(_outputOptions, bundle) {
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type !== "chunk") continue;
if ("viteMetadata" in chunk === false) continue;
const meta = chunk.viteMetadata;
if (meta.importedCss.size < 1) continue;
if (options.target === "client") {
for (const id of Object.keys(chunk.modules)) {
for (const pageData of getParentClientOnlys(id, this, internals)) {
for (const importedCssImport of meta.importedCss) {
const cssToInfoRecord = pagesToCss[pageData.moduleSpecifier] ??= {};
cssToInfoRecord[importedCssImport] = { depth: -1, order: -1 };
}
}
}
}
for (const id of Object.keys(chunk.modules)) {
const parentModuleInfos = getParentExtendedModuleInfos(id, this, hasAssetPropagationFlag);
for (const { info: pageInfo, depth, order } of parentModuleInfos) {
if (hasAssetPropagationFlag(pageInfo.id)) {
const propagatedCss = moduleIdToPropagatedCss[pageInfo.id] ??= /* @__PURE__ */ new Set();
for (const css of meta.importedCss) {
propagatedCss.add(css);
}
} else if (moduleIsTopLevelPage(pageInfo)) {
const pageViteID = pageInfo.id;
const pageData = getPageDataByViteID(internals, pageViteID);
if (pageData) {
appendCSSToPage(pageData, meta, pagesToCss, depth, order);
}
} else if (options.target === "client") {
if (buildOptions.settings.config.experimental.directRenderScript) {
const pageDatas = internals.pagesByScriptId.get(pageInfo.id);
if (pageDatas) {
for (const pageData of pageDatas) {
appendCSSToPage(pageData, meta, pagesToCss, -1, order);
}
}
} else {
if (internals.hoistedScriptIdToPagesMap.has(pageInfo.id)) {
for (const pageData of getPageDatasByHoistedScriptId(internals, pageInfo.id)) {
appendCSSToPage(pageData, meta, pagesToCss, -1, order);
}
}
}
}
}
}
}
}
};
const cssScopeToPlugin = {
name: "astro:rollup-plugin-css-scope-to",
renderChunk(_, chunk, __, meta) {
for (const id in chunk.modules) {
const modMeta = this.getModuleInfo(id)?.meta;
const cssScopeTo = modMeta?.astroCss?.cssScopeTo;
if (cssScopeTo && !isCssScopeToRendered(cssScopeTo, Object.values(meta.chunks))) {
delete chunk.modules[id];
const moduleIdsIndex = chunk.moduleIds.indexOf(id);
if (moduleIdsIndex > -1) {
chunk.moduleIds.splice(moduleIdsIndex, 1);
}
}
}
}
};
const singleCssPlugin = {
name: "astro:rollup-plugin-single-css",
enforce: "post",
configResolved(config) {
resolvedConfig = config;
},
generateBundle(_, bundle) {
if (resolvedConfig.build.cssCodeSplit) return;
const cssChunk = Object.values(bundle).find(
(chunk) => chunk.type === "asset" && chunk.name === "style.css"
);
if (cssChunk === void 0) return;
for (const pageData of internals.pagesByKeys.values()) {
const cssToInfoMap = pagesToCss[pageData.moduleSpecifier] ??= {};
cssToInfoMap[cssChunk.fileName] = { depth: -1, order: -1 };
}
}
};
let assetsInlineLimit;
const inlineStylesheetsPlugin = {
name: "astro:rollup-plugin-inline-stylesheets",
enforce: "post",
configResolved(config) {
assetsInlineLimit = config.build.assetsInlineLimit;
},
async generateBundle(_outputOptions, bundle) {
const inlineConfig = settings.config.build.inlineStylesheets;
Object.entries(bundle).forEach(([id, stylesheet]) => {
if (stylesheet.type !== "asset" || stylesheet.name?.endsWith(".css") !== true || typeof stylesheet.source !== "string")
return;
const toBeInlined = inlineConfig === "always" ? true : inlineConfig === "never" ? false : shouldInlineAsset(stylesheet.source, stylesheet.fileName, assetsInlineLimit);
const sheet = toBeInlined ? { type: "inline", content: stylesheet.source } : { type: "external", src: stylesheet.fileName };
let sheetAddedToPage = false;
internals.pagesByKeys.forEach((pageData) => {
const orderingInfo = pagesToCss[pageData.moduleSpecifier]?.[stylesheet.fileName];
if (orderingInfo !== void 0) {
pageData.styles.push({ ...orderingInfo, sheet });
sheetAddedToPage = true;
}
});
for (const moduleId in moduleIdToPropagatedCss) {
if (!moduleIdToPropagatedCss[moduleId].has(stylesheet.fileName)) continue;
let propagatedStyles = internals.propagatedStylesMap.get(moduleId);
if (!propagatedStyles) {
propagatedStyles = /* @__PURE__ */ new Set();
internals.propagatedStylesMap.set(moduleId, propagatedStyles);
}
propagatedStyles.add(sheet);
sheetAddedToPage = true;
}
if (toBeInlined && sheetAddedToPage) {
delete bundle[id];
for (const chunk of Object.values(bundle)) {
if (chunk.type === "chunk") {
chunk.viteMetadata?.importedCss?.delete(id);
}
}
}
});
}
};
return [cssBuildPlugin, cssScopeToPlugin, singleCssPlugin, inlineStylesheetsPlugin];
}
function* getParentClientOnlys(id, ctx, internals) {
for (const info of getParentModuleInfos(id, ctx)) {
yield* getPageDatasByClientOnlyID(internals, info.id);
}
}
function appendCSSToPage(pageData, meta, pagesToCss, depth, order) {
for (const importedCssImport of meta.importedCss) {
const cssInfo = pagesToCss[pageData.moduleSpecifier]?.[importedCssImport];
if (cssInfo !== void 0) {
if (depth < cssInfo.depth) {
cssInfo.depth = depth;
}
if (cssInfo.order === -1) {
cssInfo.order = order;
} else if (order < cssInfo.order && order > -1) {
cssInfo.order = order;
}
} else {
const cssToInfoRecord = pagesToCss[pageData.moduleSpecifier] ??= {};
cssToInfoRecord[importedCssImport] = { depth, order };
}
}
}
function isCssScopeToRendered(cssScopeTo, chunks) {
for (const moduleId in cssScopeTo) {
const exports = cssScopeTo[moduleId];
const renderedModule = chunks.find((c) => c.moduleIds.includes(moduleId))?.modules[moduleId];
if (renderedModule?.renderedExports.some((e) => exports.includes(e))) {
return true;
}
}
return false;
}
export {
pluginCSS
};

View File

@@ -0,0 +1,5 @@
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
export declare function vitePluginHoistedScripts(internals: BuildInternals): VitePlugin;
export declare function pluginHoistedScripts(internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,83 @@
import { getPageDatasByHoistedScriptId } from "../internal.js";
import { shouldInlineAsset } from "./util.js";
function virtualHoistedEntry(id) {
return id.startsWith("/astro/hoisted.js?q=");
}
function vitePluginHoistedScripts(internals) {
let assetsInlineLimit;
return {
name: "@astro/rollup-plugin-astro-hoisted-scripts",
configResolved(config) {
assetsInlineLimit = config.build.assetsInlineLimit;
},
resolveId(id) {
if (virtualHoistedEntry(id)) {
return id;
}
},
load(id) {
if (virtualHoistedEntry(id)) {
let code = "";
for (let path of internals.hoistedScriptIdToHoistedMap.get(id)) {
let importPath = path;
if (importPath.startsWith("/@fs")) {
importPath = importPath.slice("/@fs".length);
}
code += `import "${importPath}";`;
}
return {
code
};
}
return void 0;
},
async generateBundle(_options, bundle) {
const considerInlining = /* @__PURE__ */ new Map();
const importedByOtherScripts = /* @__PURE__ */ new Set();
Object.entries(bundle).forEach(([id, output]) => {
if (output.type === "chunk" && output.facadeModuleId && virtualHoistedEntry(output.facadeModuleId)) {
considerInlining.set(id, output);
output.imports.forEach((imported) => importedByOtherScripts.add(imported));
}
});
for (const [id, output] of considerInlining.entries()) {
const canBeInlined = importedByOtherScripts.has(output.fileName) === false && output.imports.length === 0 && output.dynamicImports.length === 0 && shouldInlineAsset(output.code, output.fileName, assetsInlineLimit);
let removeFromBundle = false;
const facadeId = output.facadeModuleId;
for (const pageData of getPageDatasByHoistedScriptId(internals, facadeId)) {
if (canBeInlined) {
pageData.hoistedScript = {
type: "inline",
value: output.code
};
removeFromBundle = true;
} else {
pageData.hoistedScript = {
type: "external",
value: id
};
}
}
if (removeFromBundle) {
delete bundle[id];
}
}
}
};
}
function pluginHoistedScripts(internals) {
return {
targets: ["client"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginHoistedScripts(internals)
};
}
}
};
}
export {
pluginHoistedScripts,
vitePluginHoistedScripts
};

View File

@@ -0,0 +1,5 @@
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
export declare function vitePluginInternals(input: Set<string>, internals: BuildInternals): VitePlugin;
export declare function pluginInternals(internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,64 @@
import { normalizeEntryId } from "./plugin-component-entry.js";
function vitePluginInternals(input, internals) {
return {
name: "@astro/plugin-build-internals",
config(config, options) {
if (options.command === "build" && config.build?.ssr) {
return {
ssr: {
// Always bundle Astro runtime when building for SSR
noExternal: ["astro"],
// Except for these packages as they're not bundle-friendly. Users with strict package installations
// need to manually install these themselves if they use the related features.
external: [
"sharp"
// For sharp image service
]
}
};
}
},
async generateBundle(_options, bundle) {
const promises = [];
const mapping = /* @__PURE__ */ new Map();
for (const specifier of input) {
promises.push(
this.resolve(specifier).then((result) => {
if (result) {
if (mapping.has(result.id)) {
mapping.get(result.id).add(specifier);
} else {
mapping.set(result.id, /* @__PURE__ */ new Set([specifier]));
}
}
})
);
}
await Promise.all(promises);
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === "chunk" && chunk.facadeModuleId) {
const specifiers = mapping.get(chunk.facadeModuleId) || /* @__PURE__ */ new Set([chunk.facadeModuleId]);
for (const specifier of specifiers) {
internals.entrySpecifierToBundleMap.set(normalizeEntryId(specifier), chunk.fileName);
}
}
}
}
};
}
function pluginInternals(internals) {
return {
targets: ["client", "server"],
hooks: {
"build:before": ({ input }) => {
return {
vitePlugin: vitePluginInternals(input, internals)
};
}
}
};
}
export {
pluginInternals,
vitePluginInternals
};

View File

@@ -0,0 +1,6 @@
import { type BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare const SSR_MANIFEST_VIRTUAL_MODULE_ID = "@astrojs-manifest";
export declare const RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID: string;
export declare function pluginManifest(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,228 @@
import { fileURLToPath } from "node:url";
import glob from "fast-glob";
import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
import { normalizeTheLocale } from "../../../i18n/index.js";
import { toFallbackType, toRoutingStrategy } from "../../../i18n/utils.js";
import { runHookBuildSsr } from "../../../integrations/hooks.js";
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../../vite-plugin-scripts/index.js";
import { encodeKey } from "../../encryption.js";
import { fileExtension, joinPaths, prependForwardSlash } from "../../path.js";
import { serializeRouteData } from "../../routing/index.js";
import { addRollupInput } from "../add-rollup-input.js";
import { getOutFile, getOutFolder } from "../common.js";
import { cssOrder, mergeInlineCss } from "../internal.js";
import { makePageDataKey } from "./util.js";
const manifestReplace = "@@ASTRO_MANIFEST_REPLACE@@";
const replaceExp = new RegExp(`['"]${manifestReplace}['"]`, "g");
const SSR_MANIFEST_VIRTUAL_MODULE_ID = "@astrojs-manifest";
const RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID = "\0" + SSR_MANIFEST_VIRTUAL_MODULE_ID;
function vitePluginManifest(_options, internals) {
return {
name: "@astro/plugin-build-manifest",
enforce: "post",
options(opts) {
return addRollupInput(opts, [SSR_MANIFEST_VIRTUAL_MODULE_ID]);
},
resolveId(id) {
if (id === SSR_MANIFEST_VIRTUAL_MODULE_ID) {
return RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID;
}
},
augmentChunkHash(chunkInfo) {
if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
return Date.now().toString();
}
},
async load(id) {
if (id === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
const imports = [
`import { deserializeManifest as _deserializeManifest } from 'astro/app'`,
`import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest'`
];
const contents = [
`const manifest = _deserializeManifest('${manifestReplace}');`,
`_privateSetManifestDontUseThis(manifest);`
];
const exports = [`export { manifest }`];
return [...imports, ...contents, ...exports].join("\n");
}
},
async generateBundle(_opts, bundle) {
for (const [chunkName, chunk] of Object.entries(bundle)) {
if (chunk.type === "asset") {
continue;
}
if (chunk.modules[RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID]) {
internals.manifestEntryChunk = chunk;
delete bundle[chunkName];
}
if (chunkName.startsWith("manifest")) {
internals.manifestFileName = chunkName;
}
}
}
};
}
function pluginManifest(options, internals) {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginManifest(options, internals)
};
},
"build:post": async ({ mutate }) => {
if (!internals.manifestEntryChunk) {
throw new Error(`Did not generate an entry chunk for SSR`);
}
const manifest = await createManifest(options, internals);
const shouldPassMiddlewareEntryPoint = options.settings.adapter?.adapterFeatures?.edgeMiddleware;
await runHookBuildSsr({
config: options.settings.config,
manifest,
logger: options.logger,
entryPoints: internals.entryPoints,
middlewareEntryPoint: shouldPassMiddlewareEntryPoint ? internals.middlewareEntryPoint : void 0
});
const code = injectManifest(manifest, internals.manifestEntryChunk);
mutate(internals.manifestEntryChunk, ["server"], code);
}
}
};
}
async function createManifest(buildOpts, internals) {
if (!internals.manifestEntryChunk) {
throw new Error(`Did not generate an entry chunk for SSR`);
}
const clientStatics = new Set(
await glob("**/*", {
cwd: fileURLToPath(buildOpts.settings.config.build.client)
})
);
for (const file of clientStatics) {
internals.staticFiles.add(file);
}
const staticFiles = internals.staticFiles;
const encodedKey = await encodeKey(await buildOpts.key);
return buildManifest(buildOpts, internals, Array.from(staticFiles), encodedKey);
}
function injectManifest(manifest, chunk) {
const code = chunk.code;
return code.replace(replaceExp, () => {
return JSON.stringify(manifest);
});
}
function buildManifest(opts, internals, staticFiles, encodedKey) {
const { settings } = opts;
const routes = [];
const domainLookupTable = {};
const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries());
if (settings.scripts.some((script) => script.stage === "page")) {
staticFiles.push(entryModules[PAGE_SCRIPT_ID]);
}
const prefixAssetPath = (pth) => {
if (settings.config.build.assetsPrefix) {
const pf = getAssetsPrefix(fileExtension(pth), settings.config.build.assetsPrefix);
return joinPaths(pf, pth);
} else {
return prependForwardSlash(joinPaths(settings.config.base, pth));
}
};
for (const route of opts.manifest.routes) {
if (!route.prerender) continue;
if (!route.pathname) continue;
const outFolder = getOutFolder(opts.settings.config, route.pathname, route);
const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route);
const file = outFile.toString().replace(opts.settings.config.build.client.toString(), "");
routes.push({
file,
links: [],
scripts: [],
styles: [],
routeData: serializeRouteData(route, settings.config.trailingSlash)
});
staticFiles.push(file);
}
for (const route of opts.manifest.routes) {
const pageData = internals.pagesByKeys.get(makePageDataKey(route.route, route.component));
if (route.prerender || !pageData) continue;
const scripts = [];
if (pageData.hoistedScript) {
const shouldPrefixAssetPath = pageData.hoistedScript.type === "external";
const hoistedValue = pageData.hoistedScript.value;
const value = shouldPrefixAssetPath ? prefixAssetPath(hoistedValue) : hoistedValue;
scripts.unshift(
Object.assign({}, pageData.hoistedScript, {
value
})
);
}
if (settings.scripts.some((script) => script.stage === "page")) {
const src = entryModules[PAGE_SCRIPT_ID];
scripts.push({
type: "external",
value: prefixAssetPath(src)
});
}
const links = [];
const styles = pageData.styles.sort(cssOrder).map(({ sheet }) => sheet).map((s) => s.type === "external" ? { ...s, src: prefixAssetPath(s.src) } : s).reduce(mergeInlineCss, []);
routes.push({
file: "",
links,
scripts: [
...scripts,
...settings.scripts.filter((script) => script.stage === "head-inline").map(({ stage, content }) => ({ stage, children: content }))
],
styles,
routeData: serializeRouteData(route, settings.config.trailingSlash)
});
}
const i18n = settings.config.i18n;
if (i18n && i18n.domains) {
for (const [locale, domainValue] of Object.entries(i18n.domains)) {
domainLookupTable[domainValue] = normalizeTheLocale(locale);
}
}
if (!(BEFORE_HYDRATION_SCRIPT_ID in entryModules)) {
entryModules[BEFORE_HYDRATION_SCRIPT_ID] = "";
}
let i18nManifest = void 0;
if (settings.config.i18n) {
i18nManifest = {
fallback: settings.config.i18n.fallback,
fallbackType: toFallbackType(settings.config.i18n.routing),
strategy: toRoutingStrategy(settings.config.i18n.routing, settings.config.i18n.domains),
locales: settings.config.i18n.locales,
defaultLocale: settings.config.i18n.defaultLocale,
domainLookupTable
};
}
return {
hrefRoot: opts.settings.config.root.toString(),
adapterName: opts.settings.adapter?.name ?? "",
routes,
site: settings.config.site,
base: settings.config.base,
trailingSlash: settings.config.trailingSlash,
compressHTML: settings.config.compressHTML,
assetsPrefix: settings.config.build.assetsPrefix,
componentMetadata: Array.from(internals.componentMetadata),
renderers: [],
clientDirectives: Array.from(settings.clientDirectives),
entryModules,
inlinedScripts: Array.from(internals.inlinedScripts),
assets: staticFiles.map(prefixAssetPath),
i18n: i18nManifest,
buildFormat: settings.config.build.format,
checkOrigin: settings.config.security?.checkOrigin ?? false,
serverIslandNameMap: Array.from(settings.serverIslandNameMap),
key: encodedKey,
experimentalEnvGetSecretEnabled: settings.config.experimental.env !== void 0 && (settings.adapter?.supportedAstroFeatures.envGetSecret ?? "unsupported") !== "unsupported"
};
}
export {
RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID,
SSR_MANIFEST_VIRTUAL_MODULE_ID,
pluginManifest
};

View File

@@ -0,0 +1,5 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export { MIDDLEWARE_MODULE_ID } from '../../middleware/vite-plugin.js';
export declare function pluginMiddleware(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,18 @@
import { vitePluginMiddlewareBuild } from "../../middleware/vite-plugin.js";
import { MIDDLEWARE_MODULE_ID } from "../../middleware/vite-plugin.js";
function pluginMiddleware(opts, internals) {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginMiddlewareBuild(opts, internals)
};
}
}
};
}
export {
MIDDLEWARE_MODULE_ID,
pluginMiddleware
};

View File

@@ -0,0 +1,6 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare const ASTRO_PAGE_MODULE_ID = "@astro-page:";
export declare const ASTRO_PAGE_RESOLVED_MODULE_ID: string;
export declare function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,66 @@
import { routeIsRedirect } from "../../redirects/index.js";
import { addRollupInput } from "../add-rollup-input.js";
import { RENDERERS_MODULE_ID } from "./plugin-renderers.js";
import { getPagesFromVirtualModulePageName, getVirtualModulePageName } from "./util.js";
const ASTRO_PAGE_MODULE_ID = "@astro-page:";
const ASTRO_PAGE_RESOLVED_MODULE_ID = "\0" + ASTRO_PAGE_MODULE_ID;
function vitePluginPages(opts, internals) {
return {
name: "@astro/plugin-build-pages",
options(options) {
if (opts.settings.config.output === "static") {
const inputs = /* @__PURE__ */ new Set();
for (const pageData of Object.values(opts.allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
inputs.add(getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component));
}
return addRollupInput(options, Array.from(inputs));
}
},
resolveId(id) {
if (id.startsWith(ASTRO_PAGE_MODULE_ID)) {
return "\0" + id;
}
},
async load(id) {
if (id.startsWith(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
const imports = [];
const exports = [];
const pageDatas = getPagesFromVirtualModulePageName(
internals,
ASTRO_PAGE_RESOLVED_MODULE_ID,
id
);
for (const pageData of pageDatas) {
const resolvedPage = await this.resolve(pageData.moduleSpecifier);
if (resolvedPage) {
imports.push(`import * as _page from ${JSON.stringify(pageData.moduleSpecifier)};`);
exports.push(`export const page = () => _page`);
imports.push(`import { renderers } from "${RENDERERS_MODULE_ID}";`);
exports.push(`export { renderers };`);
return `${imports.join("\n")}${exports.join("\n")}`;
}
}
}
}
};
}
function pluginPages(opts, internals) {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginPages(opts, internals)
};
}
}
};
}
export {
ASTRO_PAGE_MODULE_ID,
ASTRO_PAGE_RESOLVED_MODULE_ID,
pluginPages
};

View File

@@ -0,0 +1,4 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare function pluginPrerender(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,79 @@
import { getPrerenderMetadata } from "../../../prerender/metadata.js";
import { ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugin-pages.js";
import { getPagesFromVirtualModulePageName } from "./util.js";
function vitePluginPrerender(internals) {
return {
name: "astro:rollup-plugin-prerender",
generateBundle(_, bundle) {
const moduleIds = this.getModuleIds();
for (const id of moduleIds) {
const pageInfo = internals.pagesByViteID.get(id);
if (!pageInfo) continue;
const moduleInfo = this.getModuleInfo(id);
if (!moduleInfo) continue;
const prerender = !!getPrerenderMetadata(moduleInfo);
pageInfo.route.prerender = prerender;
}
const nonPrerenderOnlyChunks = getNonPrerenderOnlyChunks(bundle, internals);
internals.prerenderOnlyChunks = Object.values(bundle).filter((chunk) => {
return chunk.type === "chunk" && !nonPrerenderOnlyChunks.has(chunk);
});
}
};
}
function getNonPrerenderOnlyChunks(bundle, internals) {
const chunks = Object.values(bundle);
const prerenderOnlyEntryChunks = /* @__PURE__ */ new Set();
const nonPrerenderOnlyEntryChunks = /* @__PURE__ */ new Set();
for (const chunk of chunks) {
if (chunk.type === "chunk" && chunk.isEntry) {
if (chunk.facadeModuleId?.startsWith(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
const pageDatas = getPagesFromVirtualModulePageName(
internals,
ASTRO_PAGE_RESOLVED_MODULE_ID,
chunk.facadeModuleId
);
const prerender = pageDatas.every((pageData) => pageData.route.prerender);
if (prerender) {
prerenderOnlyEntryChunks.add(chunk);
continue;
}
}
nonPrerenderOnlyEntryChunks.add(chunk);
}
}
const nonPrerenderOnlyChunks = new Set(nonPrerenderOnlyEntryChunks);
for (const chunk of nonPrerenderOnlyChunks) {
for (const importFileName of chunk.imports) {
const importChunk = bundle[importFileName];
if (importChunk?.type === "chunk") {
nonPrerenderOnlyChunks.add(importChunk);
}
}
for (const dynamicImportFileName of chunk.dynamicImports) {
const dynamicImportChunk = bundle[dynamicImportFileName];
if (dynamicImportChunk?.type === "chunk" && !prerenderOnlyEntryChunks.has(dynamicImportChunk)) {
nonPrerenderOnlyChunks.add(dynamicImportChunk);
}
}
}
return nonPrerenderOnlyChunks;
}
function pluginPrerender(opts, internals) {
if (opts.settings.config.output === "static") {
return { targets: ["server"] };
}
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginPrerender(internals)
};
}
}
};
}
export {
pluginPrerender
};

View File

@@ -0,0 +1,7 @@
import type { Plugin as VitePlugin } from 'vite';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare const RENDERERS_MODULE_ID = "@astro-renderers";
export declare const RESOLVED_RENDERERS_MODULE_ID = "\0@astro-renderers";
export declare function vitePluginRenderers(opts: StaticBuildOptions): VitePlugin;
export declare function pluginRenderers(opts: StaticBuildOptions): AstroBuildPlugin;

View File

@@ -0,0 +1,55 @@
import { addRollupInput } from "../add-rollup-input.js";
const RENDERERS_MODULE_ID = "@astro-renderers";
const RESOLVED_RENDERERS_MODULE_ID = `\0${RENDERERS_MODULE_ID}`;
function vitePluginRenderers(opts) {
return {
name: "@astro/plugin-renderers",
options(options) {
return addRollupInput(options, [RENDERERS_MODULE_ID]);
},
resolveId(id) {
if (id === RENDERERS_MODULE_ID) {
return RESOLVED_RENDERERS_MODULE_ID;
}
},
async load(id) {
if (id === RESOLVED_RENDERERS_MODULE_ID) {
if (opts.settings.renderers.length > 0) {
const imports = [];
const exports = [];
let i = 0;
let rendererItems = "";
for (const renderer of opts.settings.renderers) {
const variable = `_renderer${i}`;
imports.push(`import ${variable} from '${renderer.serverEntrypoint}';`);
rendererItems += `Object.assign(${JSON.stringify(renderer)}, { ssr: ${variable} }),`;
i++;
}
exports.push(`export const renderers = [${rendererItems}];`);
return `${imports.join("\n")}
${exports.join("\n")}`;
} else {
return `export const renderers = [];`;
}
}
}
};
}
function pluginRenderers(opts) {
return {
targets: ["server"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginRenderers(opts)
};
}
}
};
}
export {
RENDERERS_MODULE_ID,
RESOLVED_RENDERERS_MODULE_ID,
pluginRenderers,
vitePluginRenderers
};

View File

@@ -0,0 +1,8 @@
import type { Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
/**
* Used by the `experimental.directRenderScript` option to inline scripts directly into the HTML.
*/
export declare function vitePluginScripts(internals: BuildInternals): VitePlugin;
export declare function pluginScripts(internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,43 @@
import { shouldInlineAsset } from "./util.js";
function vitePluginScripts(internals) {
let assetInlineLimit;
return {
name: "@astro/plugin-scripts",
configResolved(config) {
assetInlineLimit = config.build.assetsInlineLimit;
},
async generateBundle(_options, bundle) {
const outputs = Object.values(bundle);
const importedIds = /* @__PURE__ */ new Set();
for (const output of outputs) {
if (output.type === "chunk") {
for (const id of output.imports) {
importedIds.add(id);
}
}
}
for (const output of outputs) {
if (output.type === "chunk" && output.facadeModuleId && internals.discoveredScripts.has(output.facadeModuleId) && !importedIds.has(output.fileName) && output.imports.length === 0 && output.dynamicImports.length === 0 && shouldInlineAsset(output.code, output.fileName, assetInlineLimit)) {
internals.inlinedScripts.set(output.facadeModuleId, output.code.trim());
delete bundle[output.fileName];
}
}
}
};
}
function pluginScripts(internals) {
return {
targets: ["client"],
hooks: {
"build:before": () => {
return {
vitePlugin: vitePluginScripts(internals)
};
}
}
};
}
export {
pluginScripts,
vitePluginScripts
};

View File

@@ -0,0 +1,9 @@
import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
export declare const SSR_VIRTUAL_MODULE_ID = "@astrojs-ssr-virtual-entry";
export declare const RESOLVED_SSR_VIRTUAL_MODULE_ID: string;
export declare function pluginSSR(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;
export declare const SPLIT_MODULE_ID = "@astro-page-split:";
export declare const RESOLVED_SPLIT_MODULE_ID = "\0@astro-page-split:";
export declare function pluginSSRSplit(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;

View File

@@ -0,0 +1,281 @@
import { join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { isFunctionPerRouteEnabled } from "../../../integrations/hooks.js";
import { routeIsRedirect } from "../../redirects/index.js";
import { VIRTUAL_ISLAND_MAP_ID } from "../../server-islands/vite-plugin-server-islands.js";
import { isServerLikeOutput } from "../../util.js";
import { addRollupInput } from "../add-rollup-input.js";
import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from "./plugin-manifest.js";
import { MIDDLEWARE_MODULE_ID } from "./plugin-middleware.js";
import { ASTRO_PAGE_MODULE_ID } from "./plugin-pages.js";
import { RENDERERS_MODULE_ID } from "./plugin-renderers.js";
import { getComponentFromVirtualModulePageName, getVirtualModulePageName } from "./util.js";
const SSR_VIRTUAL_MODULE_ID = "@astrojs-ssr-virtual-entry";
const RESOLVED_SSR_VIRTUAL_MODULE_ID = "\0" + SSR_VIRTUAL_MODULE_ID;
const ADAPTER_VIRTUAL_MODULE_ID = "@astrojs-ssr-adapter";
const RESOLVED_ADAPTER_VIRTUAL_MODULE_ID = "\0" + ADAPTER_VIRTUAL_MODULE_ID;
function vitePluginAdapter(adapter) {
return {
name: "@astrojs/vite-plugin-astro-adapter",
enforce: "post",
resolveId(id) {
if (id === ADAPTER_VIRTUAL_MODULE_ID) {
return RESOLVED_ADAPTER_VIRTUAL_MODULE_ID;
}
},
async load(id) {
if (id === RESOLVED_ADAPTER_VIRTUAL_MODULE_ID) {
return `export * from '${adapter.serverEntrypoint}';`;
}
}
};
}
function vitePluginSSR(internals, adapter, options) {
return {
name: "@astrojs/vite-plugin-astro-ssr-server",
enforce: "post",
options(opts) {
const inputs = /* @__PURE__ */ new Set();
for (const pageData of Object.values(options.allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
inputs.add(getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component));
}
const adapterServerEntrypoint = options.settings.adapter?.serverEntrypoint;
if (adapterServerEntrypoint) {
inputs.add(ADAPTER_VIRTUAL_MODULE_ID);
}
inputs.add(SSR_VIRTUAL_MODULE_ID);
return addRollupInput(opts, Array.from(inputs));
},
resolveId(id) {
if (id === SSR_VIRTUAL_MODULE_ID) {
return RESOLVED_SSR_VIRTUAL_MODULE_ID;
}
},
async load(id) {
if (id === RESOLVED_SSR_VIRTUAL_MODULE_ID) {
const { allPages } = options;
const imports = [];
const contents = [];
const exports = [];
let i = 0;
const pageMap = [];
for (const pageData of Object.values(allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
const virtualModuleName = getVirtualModulePageName(
ASTRO_PAGE_MODULE_ID,
pageData.component
);
let module = await this.resolve(virtualModuleName);
if (module) {
const variable = `_page${i}`;
imports.push(`const ${variable} = () => import("${virtualModuleName}");`);
const pageData2 = internals.pagesByKeys.get(pageData.key);
if (pageData2) {
pageMap.push(`[${JSON.stringify(pageData2.component)}, ${variable}]`);
}
i++;
}
}
contents.push(`const pageMap = new Map([
${pageMap.join(",\n ")}
]);`);
exports.push(`export { pageMap }`);
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
const ssrCode = generateSSRCode(options.settings, adapter, middleware.id);
imports.push(...ssrCode.imports);
contents.push(...ssrCode.contents);
return [...imports, ...contents, ...exports].join("\n");
}
},
async generateBundle(_opts, bundle) {
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === "asset") {
internals.staticFiles.add(chunk.fileName);
}
}
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === "asset") {
continue;
}
if (chunk.modules[RESOLVED_SSR_VIRTUAL_MODULE_ID]) {
internals.ssrEntryChunk = chunk;
}
}
}
};
}
function pluginSSR(options, internals) {
const ssr = isServerLikeOutput(options.settings.config);
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
return {
targets: ["server"],
hooks: {
"build:before": () => {
const adapter = options.settings.adapter;
let ssrPlugin = ssr && functionPerRouteEnabled === false ? vitePluginSSR(internals, adapter, options) : void 0;
const vitePlugin = [vitePluginAdapter(adapter)];
if (ssrPlugin) {
vitePlugin.unshift(ssrPlugin);
}
return {
enforce: "after-user-plugins",
vitePlugin
};
},
"build:post": async () => {
if (!ssr) {
return;
}
if (functionPerRouteEnabled) {
return;
}
if (!internals.ssrEntryChunk) {
throw new Error(`Did not generate an entry chunk for SSR`);
}
internals.ssrEntryChunk.fileName = options.settings.config.build.serverEntry;
}
}
};
}
const SPLIT_MODULE_ID = "@astro-page-split:";
const RESOLVED_SPLIT_MODULE_ID = "\0@astro-page-split:";
function vitePluginSSRSplit(internals, adapter, options) {
return {
name: "@astrojs/vite-plugin-astro-ssr-split",
enforce: "post",
options(opts) {
const inputs = /* @__PURE__ */ new Set();
for (const pageData of Object.values(options.allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
inputs.add(getVirtualModulePageName(SPLIT_MODULE_ID, pageData.component));
}
return addRollupInput(opts, Array.from(inputs));
},
resolveId(id) {
if (id.startsWith(SPLIT_MODULE_ID)) {
return "\0" + id;
}
},
async load(id) {
if (id.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
const imports = [];
const contents = [];
const exports = [];
const componentPath = getComponentFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, id);
const virtualModuleName = getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, componentPath);
let module = await this.resolve(virtualModuleName);
if (module) {
imports.push(`import * as pageModule from "${virtualModuleName}";`);
}
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
const ssrCode = generateSSRCode(options.settings, adapter, middleware.id);
imports.push(...ssrCode.imports);
contents.push(...ssrCode.contents);
exports.push("export { pageModule }");
return [...imports, ...contents, ...exports].join("\n");
}
},
async generateBundle(_opts, bundle) {
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === "asset") {
internals.staticFiles.add(chunk.fileName);
}
}
for (const [, chunk] of Object.entries(bundle)) {
if (chunk.type === "asset") {
continue;
}
for (const moduleKey of Object.keys(chunk.modules)) {
if (moduleKey.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
storeEntryPoint(moduleKey, options, internals, chunk.fileName);
}
}
}
}
};
}
function pluginSSRSplit(options, internals) {
const ssr = isServerLikeOutput(options.settings.config);
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
return {
targets: ["server"],
hooks: {
"build:before": () => {
const adapter = options.settings.adapter;
let ssrPlugin = ssr && functionPerRouteEnabled ? vitePluginSSRSplit(internals, adapter, options) : void 0;
const vitePlugin = [vitePluginAdapter(adapter)];
if (ssrPlugin) {
vitePlugin.unshift(ssrPlugin);
}
return {
enforce: "after-user-plugins",
vitePlugin
};
}
}
};
}
function generateSSRCode(settings, adapter, middlewareId) {
const edgeMiddleware = adapter?.adapterFeatures?.edgeMiddleware ?? false;
const pageMap = isFunctionPerRouteEnabled(adapter) ? "pageModule" : "pageMap";
const imports = [
`import { renderers } from '${RENDERERS_MODULE_ID}';`,
`import * as serverEntrypointModule from '${ADAPTER_VIRTUAL_MODULE_ID}';`,
`import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
settings.config.experimental.serverIslands ? `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';` : ""
];
const contents = [
settings.config.experimental.serverIslands ? "" : `const serverIslandMap = new Map()`,
`const _manifest = Object.assign(defaultManifest, {`,
` ${pageMap},`,
` serverIslandMap,`,
` renderers,`,
` middleware: ${edgeMiddleware ? "undefined" : `() => import("${middlewareId}")`}`,
`});`,
`const _args = ${adapter.args ? JSON.stringify(adapter.args, null, 4) : "undefined"};`,
adapter.exports ? `const _exports = serverEntrypointModule.createExports(_manifest, _args);` : "",
...adapter.exports?.map((name) => {
if (name === "default") {
return `export default _exports.default;`;
} else {
return `export const ${name} = _exports['${name}'];`;
}
}) ?? [],
// NOTE: This is intentionally obfuscated!
// Do NOT simplify this to something like `serverEntrypointModule.start?.(_manifest, _args)`
// They are NOT equivalent! Some bundlers will throw if `start` is not exported, but we
// only want to silently ignore it... hence the dynamic, obfuscated weirdness.
`const _start = 'start';
if (_start in serverEntrypointModule) {
serverEntrypointModule[_start](_manifest, _args);
}`
];
return {
imports,
contents
};
}
function storeEntryPoint(moduleKey, options, internals, fileName) {
const componentPath = getComponentFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, moduleKey);
for (const pageData of Object.values(options.allPages)) {
if (componentPath == pageData.component) {
const publicPath = fileURLToPath(options.settings.config.build.server);
internals.entryPoints.set(pageData.route, pathToFileURL(join(publicPath, fileName)));
}
}
}
export {
RESOLVED_SPLIT_MODULE_ID,
RESOLVED_SSR_VIRTUAL_MODULE_ID,
SPLIT_MODULE_ID,
SSR_VIRTUAL_MODULE_ID,
pluginSSR,
pluginSSRSplit
};

42
node_modules/astro/dist/core/build/plugins/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,42 @@
import type { BuildOptions, Rollup, Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { PageBuildData } from '../types.js';
type OutputOptionsHook = Extract<VitePlugin['outputOptions'], Function>;
type OutputOptions = Parameters<OutputOptionsHook>[0];
type ExtendManualChunksHooks = {
before?: Rollup.GetManualChunk;
after?: Rollup.GetManualChunk;
};
export declare function extendManualChunks(outputOptions: OutputOptions, hooks: ExtendManualChunksHooks): void;
export declare const ASTRO_PAGE_EXTENSION_POST_PATTERN = "@_@";
export declare const ASTRO_PAGE_KEY_SEPARATOR = "&";
/**
* Generate a unique key to identify each page in the build process.
* @param route Usually pageData.route.route
* @param componentPath Usually pageData.component
*/
export declare function makePageDataKey(route: string, componentPath: string): string;
/**
* Prevents Rollup from triggering other plugins in the process by masking the extension (hence the virtual file).
* Inverse function of getComponentFromVirtualModulePageName() below.
* @param virtualModulePrefix The prefix used to create the virtual module
* @param path Page component path
*/
export declare function getVirtualModulePageName(virtualModulePrefix: string, path: string): string;
/**
* From the VirtualModulePageName, and the internals, get all pageDatas that use this
* component as their entry point.
* @param virtualModulePrefix The prefix used to create the virtual module
* @param id Virtual module name
*/
export declare function getPagesFromVirtualModulePageName(internals: BuildInternals, virtualModulePrefix: string, id: string): PageBuildData[];
/**
* From the VirtualModulePageName, get the component path.
* Remember that the component can be use by multiple routes.
* Inverse function of getVirtualModulePageName() above.
* @param virtualModulePrefix The prefix at the beginning of the virtual module
* @param id Virtual module name
*/
export declare function getComponentFromVirtualModulePageName(virtualModulePrefix: string, id: string): string;
export declare function shouldInlineAsset(assetContent: string, assetPath: string, assetsInlineLimit: NonNullable<BuildOptions['assetsInlineLimit']>): boolean;
export {};

70
node_modules/astro/dist/core/build/plugins/util.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import { extname } from "node:path";
function extendManualChunks(outputOptions, hooks) {
const manualChunks = outputOptions.manualChunks;
outputOptions.manualChunks = function(id, meta) {
if (hooks.before) {
let value = hooks.before(id, meta);
if (value) {
return value;
}
}
if (typeof manualChunks == "object") {
if (id in manualChunks) {
let value = manualChunks[id];
return value[0];
}
} else if (typeof manualChunks === "function") {
const outid = manualChunks.call(this, id, meta);
if (outid) {
return outid;
}
}
if (hooks.after) {
return hooks.after(id, meta) || null;
}
return null;
};
}
const ASTRO_PAGE_EXTENSION_POST_PATTERN = "@_@";
const ASTRO_PAGE_KEY_SEPARATOR = "&";
function makePageDataKey(route, componentPath) {
return route + ASTRO_PAGE_KEY_SEPARATOR + componentPath;
}
function getVirtualModulePageName(virtualModulePrefix, path) {
const extension = extname(path);
return virtualModulePrefix + (extension.startsWith(".") ? path.slice(0, -extension.length) + extension.replace(".", ASTRO_PAGE_EXTENSION_POST_PATTERN) : path);
}
function getPagesFromVirtualModulePageName(internals, virtualModulePrefix, id) {
const path = getComponentFromVirtualModulePageName(virtualModulePrefix, id);
const pages = [];
internals.pagesByKeys.forEach((pageData) => {
if (pageData.component === path) {
pages.push(pageData);
}
});
return pages;
}
function getComponentFromVirtualModulePageName(virtualModulePrefix, id) {
return id.slice(virtualModulePrefix.length).replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, ".");
}
function shouldInlineAsset(assetContent, assetPath, assetsInlineLimit) {
if (typeof assetsInlineLimit === "function") {
const result = assetsInlineLimit(assetPath, Buffer.from(assetContent));
if (result != null) {
return result;
} else {
return Buffer.byteLength(assetContent) < 4096;
}
}
return Buffer.byteLength(assetContent) < Number(assetsInlineLimit);
}
export {
ASTRO_PAGE_EXTENSION_POST_PATTERN,
ASTRO_PAGE_KEY_SEPARATOR,
extendManualChunks,
getComponentFromVirtualModulePageName,
getPagesFromVirtualModulePageName,
getVirtualModulePageName,
makePageDataKey,
shouldInlineAsset
};

41
node_modules/astro/dist/core/build/static-build.d.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import type { RouteData } from '../../@types/astro.js';
import { type BuildInternals } from '../../core/build/internal.js';
import type { StaticBuildOptions } from './types.js';
export declare function viteBuild(opts: StaticBuildOptions): Promise<{
internals: BuildInternals;
ssrOutputChunkNames: string[];
}>;
export declare function staticBuild(opts: StaticBuildOptions, internals: BuildInternals, ssrOutputChunkNames: string[]): Promise<void>;
export declare function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles?: boolean): Promise<void[] | undefined>;
/**
* This function takes the virtual module name of any page entrypoint and
* transforms it to generate a final `.mjs` output file.
*
* Input: `@astro-page:src/pages/index@_@astro`
* Output: `pages/index.astro.mjs`
* Input: `@astro-page:../node_modules/my-dep/injected@_@astro`
* Output: `pages/injected.mjs`
*
* 1. We clean the `facadeModuleId` by removing the `ASTRO_PAGE_MODULE_ID` prefix and `ASTRO_PAGE_EXTENSION_POST_PATTERN`.
* 2. We find the matching route pattern in the manifest (or fallback to the cleaned module id)
* 3. We replace square brackets with underscore (`[slug]` => `_slug_`) and `...` with `` (`[...slug]` => `_---slug_`).
* 4. We append the `.mjs` extension, so the file will always be an ESM module
*
* @param prefix string
* @param facadeModuleId string
* @param pages AllPagesData
*/
export declare function makeAstroPageEntryPointFileName(prefix: string, facadeModuleId: string, routes: RouteData[]): string;
/**
* The `facadeModuleId` has a shape like: \0@astro-serverless-page:src/pages/index@_@astro.
*
* 1. We call `makeAstroPageEntryPointFileName` which normalise its name, making it like a file path
* 2. We split the file path using the file system separator and attempt to retrieve the last entry
* 3. The last entry should be the file
* 4. We prepend the file name with `entry.`
* 5. We built the file path again, using the new en3built in the previous step
*
* @param facadeModuleId
* @param opts
*/
export declare function makeSplitEntryPointFileName(facadeModuleId: string, routes: RouteData[]): string;

406
node_modules/astro/dist/core/build/static-build.js generated vendored Normal file
View File

@@ -0,0 +1,406 @@
import fs from "node:fs";
import path, { extname } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { teardown } from "@astrojs/compiler";
import glob from "fast-glob";
import { bgGreen, bgMagenta, black, green } from "kleur/colors";
import * as vite from "vite";
import { PROPAGATED_ASSET_FLAG } from "../../content/consts.js";
import {
getSymlinkedContentCollections,
hasAnyContentFlag,
reverseSymlink
} from "../../content/utils.js";
import {
createBuildInternals,
getPageDatasWithPublicKey
} from "../../core/build/internal.js";
import { emptyDir, removeEmptyDirs } from "../../core/fs/index.js";
import { appendForwardSlash, prependForwardSlash, removeFileExtension } from "../../core/path.js";
import { isModeServerWithNoAdapter, isServerLikeOutput } from "../../core/util.js";
import { runHookBuildSetup } from "../../integrations/hooks.js";
import { getOutputDirectory } from "../../prerender/utils.js";
import { PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
import { AstroError, AstroErrorData } from "../errors/index.js";
import { routeIsRedirect } from "../redirects/index.js";
import { getOutDirWithinCwd } from "./common.js";
import { CHUNKS_PATH } from "./consts.js";
import { generatePages } from "./generate.js";
import { trackPageData } from "./internal.js";
import { createPluginContainer } from "./plugin.js";
import { registerAllPlugins } from "./plugins/index.js";
import { copyContentToCache } from "./plugins/plugin-content.js";
import { RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID } from "./plugins/plugin-manifest.js";
import { ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugins/plugin-pages.js";
import { RESOLVED_RENDERERS_MODULE_ID } from "./plugins/plugin-renderers.js";
import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from "./plugins/plugin-ssr.js";
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from "./plugins/util.js";
import { encodeName, getTimeStat, viteBuildReturnToRollupOutputs } from "./util.js";
async function viteBuild(opts) {
const { allPages, settings, logger } = opts;
if (isModeServerWithNoAdapter(opts.settings)) {
throw new AstroError(AstroErrorData.NoAdapterInstalled);
}
settings.timer.start("SSR build");
const pageInput = /* @__PURE__ */ new Set();
const internals = createBuildInternals();
for (const pageData of Object.values(allPages)) {
const astroModuleURL = new URL("./" + pageData.component, settings.config.root);
const astroModuleId = prependForwardSlash(pageData.component);
trackPageData(internals, pageData.component, pageData, astroModuleId, astroModuleURL);
if (!routeIsRedirect(pageData.route)) {
pageInput.add(astroModuleId);
}
}
if (settings.config?.vite?.build?.emptyOutDir !== false) {
emptyDir(settings.config.outDir, new Set(".git"));
}
const container = createPluginContainer(opts, internals);
registerAllPlugins(container);
const ssrTime = performance.now();
opts.logger.info("build", `Building ${settings.config.output} entrypoints...`);
const ssrOutput = await ssrBuild(opts, internals, pageInput, container, logger);
opts.logger.info("build", green(`\u2713 Completed in ${getTimeStat(ssrTime, performance.now())}.`));
settings.timer.end("SSR build");
settings.timer.start("Client build");
const rendererClientEntrypoints = settings.renderers.map((r) => r.clientEntrypoint).filter((a) => typeof a === "string");
const clientInput = /* @__PURE__ */ new Set([
...internals.cachedClientEntries,
...internals.discoveredHydratedComponents.keys(),
...internals.discoveredClientOnlyComponents.keys(),
...rendererClientEntrypoints,
...internals.discoveredScripts
]);
if (settings.scripts.some((script) => script.stage === "page")) {
clientInput.add(PAGE_SCRIPT_ID);
}
const clientOutput = await clientBuild(opts, internals, clientInput, container);
const ssrOutputs = viteBuildReturnToRollupOutputs(ssrOutput);
const clientOutputs = viteBuildReturnToRollupOutputs(clientOutput ?? []);
await runPostBuildHooks(container, ssrOutputs, clientOutputs);
settings.timer.end("Client build");
internals.ssrEntryChunk = void 0;
if (opts.teardownCompiler) {
teardown();
}
const ssrOutputChunkNames = [];
for (const output of ssrOutputs) {
for (const chunk of output.output) {
if (chunk.type === "chunk") {
ssrOutputChunkNames.push(chunk.fileName);
}
}
}
return { internals, ssrOutputChunkNames };
}
async function staticBuild(opts, internals, ssrOutputChunkNames) {
const { settings } = opts;
if (settings.config.output === "static") {
settings.timer.start("Static generate");
await generatePages(opts, internals);
await cleanServerOutput(opts, ssrOutputChunkNames, internals);
settings.timer.end("Static generate");
} else if (isServerLikeOutput(settings.config)) {
settings.timer.start("Server generate");
await generatePages(opts, internals);
await cleanStaticOutput(opts, internals);
await ssrMoveAssets(opts);
settings.timer.end("Server generate");
}
}
async function ssrBuild(opts, internals, input, container, logger) {
const buildID = Date.now().toString();
const { allPages, settings, viteConfig } = opts;
const ssr = isServerLikeOutput(settings.config);
const out = getOutputDirectory(settings.config);
const routes = Object.values(allPages).flatMap((pageData) => pageData.route);
const isContentCache = !ssr && settings.config.experimental.contentCollectionCache;
const { lastVitePlugins, vitePlugins } = await container.runBeforeHook("server", input);
const contentDir = new URL("./src/content", settings.config.root);
const symlinks = await getSymlinkedContentCollections({ contentDir, logger, fs });
const viteBuildConfig = {
...viteConfig,
mode: viteConfig.mode || "production",
logLevel: viteConfig.logLevel ?? "error",
build: {
target: "esnext",
// Vite defaults cssMinify to false in SSR by default, but we want to minify it
// as the CSS generated are used and served to the client.
cssMinify: viteConfig.build?.minify == null ? true : !!viteConfig.build?.minify,
...viteConfig.build,
emptyOutDir: false,
manifest: false,
outDir: fileURLToPath(out),
copyPublicDir: !ssr,
rollupOptions: {
...viteConfig.build?.rollupOptions,
// Setting as `exports-only` allows us to safely delete inputs that are only used during prerendering
preserveEntrySignatures: "exports-only",
input: [],
output: {
hoistTransitiveImports: isContentCache,
format: "esm",
minifyInternalExports: !isContentCache,
// Server chunks can't go in the assets (_astro) folder
// We need to keep these separate
chunkFileNames(chunkInfo) {
const { name } = chunkInfo;
let prefix = CHUNKS_PATH;
let suffix = "_[hash].mjs";
if (isContentCache) {
prefix += `${buildID}/`;
suffix = ".mjs";
if (name.includes("/content/")) {
const parts = name.split("/");
if (parts.at(1) === "content") {
return encodeName(parts.slice(1).join("/"));
}
}
}
if (name.includes(ASTRO_PAGE_EXTENSION_POST_PATTERN)) {
const [sanitizedName] = name.split(ASTRO_PAGE_EXTENSION_POST_PATTERN);
return [prefix, sanitizedName, suffix].join("");
}
if (name.startsWith("pages/")) {
const sanitizedName = name.split(".")[0];
return [prefix, sanitizedName, suffix].join("");
}
const encoded = encodeName(name);
return [prefix, encoded, suffix].join("");
},
assetFileNames: `${settings.config.build.assets}/[name].[hash][extname]`,
...viteConfig.build?.rollupOptions?.output,
entryFileNames(chunkInfo) {
if (chunkInfo.facadeModuleId?.startsWith(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
return makeAstroPageEntryPointFileName(
ASTRO_PAGE_RESOLVED_MODULE_ID,
chunkInfo.facadeModuleId,
routes
);
} else if (chunkInfo.facadeModuleId?.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
return makeSplitEntryPointFileName(chunkInfo.facadeModuleId, routes);
} else if (chunkInfo.facadeModuleId === RESOLVED_SSR_VIRTUAL_MODULE_ID) {
return opts.settings.config.build.serverEntry;
} else if (chunkInfo.facadeModuleId === RESOLVED_RENDERERS_MODULE_ID) {
return "renderers.mjs";
} else if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
return "manifest_[hash].mjs";
} else if (chunkInfo.facadeModuleId === settings.adapter?.serverEntrypoint) {
return "adapter_[hash].mjs";
} else if (settings.config.experimental.contentCollectionCache && chunkInfo.facadeModuleId && hasAnyContentFlag(chunkInfo.facadeModuleId)) {
const moduleId = reverseSymlink({
symlinks,
entry: chunkInfo.facadeModuleId,
contentDir
});
const [srcRelative, flag] = moduleId.split("/src/")[1].split("?");
if (flag === PROPAGATED_ASSET_FLAG) {
return encodeName(`${removeFileExtension(srcRelative)}.entry.mjs`);
}
return encodeName(`${removeFileExtension(srcRelative)}.mjs`);
} else {
return "[name].mjs";
}
}
}
},
ssr: true,
ssrEmitAssets: true,
// improve build performance
minify: false,
modulePreload: { polyfill: false },
reportCompressedSize: false
},
plugins: [...vitePlugins, ...viteConfig.plugins || [], ...lastVitePlugins],
envPrefix: viteConfig.envPrefix ?? "PUBLIC_",
base: settings.config.base
};
const updatedViteBuildConfig = await runHookBuildSetup({
config: settings.config,
pages: getPageDatasWithPublicKey(internals.pagesByKeys),
vite: viteBuildConfig,
target: "server",
logger: opts.logger
});
return await vite.build(updatedViteBuildConfig);
}
async function clientBuild(opts, internals, input, container) {
const { settings, viteConfig } = opts;
const ssr = isServerLikeOutput(settings.config);
const out = ssr ? settings.config.build.client : getOutDirWithinCwd(settings.config.outDir);
if (!input.size) {
if (ssr) {
await copyFiles(settings.config.publicDir, out, true);
}
return null;
}
const { lastVitePlugins, vitePlugins } = await container.runBeforeHook("client", input);
opts.logger.info("SKIP_FORMAT", `
${bgGreen(black(" building client (vite) "))}`);
const viteBuildConfig = {
...viteConfig,
mode: viteConfig.mode || "production",
build: {
target: "esnext",
...viteConfig.build,
emptyOutDir: false,
outDir: fileURLToPath(out),
copyPublicDir: ssr,
rollupOptions: {
...viteConfig.build?.rollupOptions,
input: Array.from(input),
output: {
format: "esm",
entryFileNames: `${settings.config.build.assets}/[name].[hash].js`,
chunkFileNames: `${settings.config.build.assets}/[name].[hash].js`,
assetFileNames: `${settings.config.build.assets}/[name].[hash][extname]`,
...viteConfig.build?.rollupOptions?.output
},
preserveEntrySignatures: "exports-only"
}
},
plugins: [...vitePlugins, ...viteConfig.plugins || [], ...lastVitePlugins],
envPrefix: viteConfig.envPrefix ?? "PUBLIC_",
base: settings.config.base
};
await runHookBuildSetup({
config: settings.config,
pages: getPageDatasWithPublicKey(internals.pagesByKeys),
vite: viteBuildConfig,
target: "client",
logger: opts.logger
});
const buildResult = await vite.build(viteBuildConfig);
return buildResult;
}
async function runPostBuildHooks(container, ssrOutputs, clientOutputs) {
const mutations = await container.runPostHook(ssrOutputs, clientOutputs);
const config = container.options.settings.config;
const build = container.options.settings.config.build;
for (const [fileName, mutation] of mutations) {
const root = isServerLikeOutput(config) ? mutation.targets.includes("server") ? build.server : build.client : getOutDirWithinCwd(config.outDir);
const fullPath = path.join(fileURLToPath(root), fileName);
const fileURL = pathToFileURL(fullPath);
await fs.promises.mkdir(new URL("./", fileURL), { recursive: true });
await fs.promises.writeFile(fileURL, mutation.code, "utf-8");
}
}
async function cleanStaticOutput(opts, internals) {
const ssr = isServerLikeOutput(opts.settings.config);
const out = ssr ? opts.settings.config.build.server : getOutDirWithinCwd(opts.settings.config.outDir);
await Promise.all(
internals.prerenderOnlyChunks.map(async (chunk) => {
const url = new URL(chunk.fileName, out);
try {
if (chunk.isEntry || chunk.isDynamicEntry) {
await fs.promises.writeFile(
url,
"// Contents removed by Astro as it's used for prerendering only",
"utf-8"
);
} else {
await fs.promises.unlink(url);
}
} catch {
}
})
);
}
async function cleanServerOutput(opts, ssrOutputChunkNames, internals) {
const out = getOutDirWithinCwd(opts.settings.config.outDir);
const files = ssrOutputChunkNames.filter((f) => f.endsWith(".mjs"));
if (internals.manifestFileName) {
files.push(internals.manifestFileName);
}
if (files.length) {
await Promise.all(
files.map(async (filename) => {
const url = new URL(filename, out);
const map = new URL(url + ".map");
await Promise.all([fs.promises.rm(url), fs.promises.rm(new URL(map)).catch(() => {
})]);
})
);
removeEmptyDirs(out);
}
if (out.toString() !== opts.settings.config.outDir.toString()) {
const fileNames = await fs.promises.readdir(out);
await Promise.all(
fileNames.filter((fileName) => fileName.endsWith(".d.ts")).map((fileName) => fs.promises.rm(new URL(fileName, out)))
);
await copyFiles(out, opts.settings.config.outDir, true);
await fs.promises.rm(out, { recursive: true });
return;
}
}
async function copyFiles(fromFolder, toFolder, includeDotfiles = false) {
const files = await glob("**/*", {
cwd: fileURLToPath(fromFolder),
dot: includeDotfiles
});
if (files.length === 0) return;
return await Promise.all(
files.map(async function copyFile(filename) {
const from = new URL(filename, fromFolder);
const to = new URL(filename, toFolder);
const lastFolder = new URL("./", to);
return fs.promises.mkdir(lastFolder, { recursive: true }).then(async function fsCopyFile() {
const p = await fs.promises.copyFile(from, to, fs.constants.COPYFILE_FICLONE);
return p;
});
})
);
}
async function ssrMoveAssets(opts) {
opts.logger.info("build", "Rearranging server assets...");
const serverRoot = opts.settings.config.output === "static" ? opts.settings.config.build.client : opts.settings.config.build.server;
const clientRoot = opts.settings.config.build.client;
const assets = opts.settings.config.build.assets;
const serverAssets = new URL(`./${assets}/`, appendForwardSlash(serverRoot.toString()));
const clientAssets = new URL(`./${assets}/`, appendForwardSlash(clientRoot.toString()));
const files = await glob(`**/*`, {
cwd: fileURLToPath(serverAssets)
});
if (files.length > 0) {
await Promise.all(
files.map(async function moveAsset(filename) {
const currentUrl = new URL(filename, appendForwardSlash(serverAssets.toString()));
const clientUrl = new URL(filename, appendForwardSlash(clientAssets.toString()));
const dir = new URL(path.parse(clientUrl.href).dir);
if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true });
return fs.promises.rename(currentUrl, clientUrl);
})
);
removeEmptyDirs(serverAssets);
}
}
function makeAstroPageEntryPointFileName(prefix, facadeModuleId, routes) {
const pageModuleId = facadeModuleId.replace(prefix, "").replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, ".");
const route = routes.find((routeData) => routeData.component === pageModuleId);
const name = route?.route ?? pageModuleId;
return `pages${name.replace(/\/$/, "/index").replaceAll(/[[\]]/g, "_").replaceAll("...", "---")}.astro.mjs`;
}
function makeSplitEntryPointFileName(facadeModuleId, routes) {
const filePath = `${makeAstroPageEntryPointFileName(
RESOLVED_SPLIT_MODULE_ID,
facadeModuleId,
routes
)}`;
const pathComponents = filePath.split(path.sep);
const lastPathComponent = pathComponents.pop();
if (lastPathComponent) {
const extension = extname(lastPathComponent);
if (extension.length > 0) {
const newFileName = `entry.${lastPathComponent}`;
return [...pathComponents, newFileName].join(path.sep);
}
}
return filePath;
}
export {
copyFiles,
makeAstroPageEntryPointFileName,
makeSplitEntryPointFileName,
staticBuild,
viteBuild
};

54
node_modules/astro/dist/core/build/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,54 @@
import type * as vite from 'vite';
import type { InlineConfig } from 'vite';
import type { AstroSettings, ComponentInstance, ManifestData, MiddlewareHandler, RouteData, RuntimeMode, SSRLoadedRenderer } from '../../@types/astro.js';
import type { Logger } from '../logger/core.js';
export type ComponentPath = string;
export type ViteID = string;
export type StylesheetAsset = {
type: 'inline';
content: string;
} | {
type: 'external';
src: string;
};
export type HoistedScriptAsset = {
type: 'inline' | 'external';
value: string;
};
export interface PageBuildData {
key: string;
component: ComponentPath;
route: RouteData;
moduleSpecifier: string;
hoistedScript: HoistedScriptAsset | undefined;
styles: Array<{
depth: number;
order: number;
sheet: StylesheetAsset;
}>;
}
export type AllPagesData = Record<ComponentPath, PageBuildData>;
/** Options for the static build */
export interface StaticBuildOptions {
allPages: AllPagesData;
settings: AstroSettings;
logger: Logger;
manifest: ManifestData;
mode: RuntimeMode;
origin: string;
pageNames: string[];
viteConfig: InlineConfig;
teardownCompiler: boolean;
key: Promise<CryptoKey>;
}
type ImportComponentInstance = () => Promise<ComponentInstance>;
export interface SinglePageBuiltModule {
page: ImportComponentInstance;
/**
* The `onRequest` hook exported by the middleware
*/
onRequest?: MiddlewareHandler;
renderers: SSRLoadedRenderer[];
}
export type ViteBuildReturn = Awaited<ReturnType<typeof vite.build>>;
export {};

0
node_modules/astro/dist/core/build/types.js generated vendored Normal file
View File

11
node_modules/astro/dist/core/build/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import type { Rollup } from 'vite';
import type { AstroConfig } from '../../@types/astro.js';
import type { ViteBuildReturn } from './types.js';
export declare function getTimeStat(timeStart: number, timeEnd: number): string;
/**
* Given the Astro configuration, it tells if a slash should be appended or not
*/
export declare function shouldAppendForwardSlash(trailingSlash: AstroConfig['trailingSlash'], buildFormat: AstroConfig['build']['format']): boolean;
export declare function i18nHasFallback(config: AstroConfig): boolean;
export declare function encodeName(name: string): string;
export declare function viteBuildReturnToRollupOutputs(viteBuildReturn: ViteBuildReturn): Rollup.RollupOutput[];

54
node_modules/astro/dist/core/build/util.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
function getTimeStat(timeStart, timeEnd) {
const buildTime = timeEnd - timeStart;
return buildTime < 1e3 ? `${Math.round(buildTime)}ms` : `${(buildTime / 1e3).toFixed(2)}s`;
}
function shouldAppendForwardSlash(trailingSlash, buildFormat) {
switch (trailingSlash) {
case "always":
return true;
case "never":
return false;
case "ignore": {
switch (buildFormat) {
case "directory":
return true;
case "preserve":
case "file":
return false;
}
}
}
}
function i18nHasFallback(config) {
if (config.i18n && config.i18n.fallback) {
return Object.keys(config.i18n.fallback).length > 0;
}
return false;
}
function encodeName(name) {
for (let i = 0; i < name.length; i++) {
if (name[i] === "%") {
const third = name.codePointAt(i + 2) | 32;
if (name[i + 1] !== "2" || third !== 102) {
return `${name.replace(/%/g, "_percent_")}`;
}
}
}
return name;
}
function viteBuildReturnToRollupOutputs(viteBuildReturn) {
const result = [];
if (Array.isArray(viteBuildReturn)) {
result.push(...viteBuildReturn);
} else if ("output" in viteBuildReturn) {
result.push(viteBuildReturn);
}
return result;
}
export {
encodeName,
getTimeStat,
i18nHasFallback,
shouldAppendForwardSlash,
viteBuildReturnToRollupOutputs
};