summaryrefslogtreecommitdiff
path: root/packages/astro/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/astro/src')
-rw-r--r--packages/astro/src/actions/runtime/middleware.ts2
-rw-r--r--packages/astro/src/actions/runtime/route.ts1
-rw-r--r--packages/astro/src/actions/runtime/virtual/shared.ts3
-rw-r--r--packages/astro/src/assets/endpoint/generic.ts1
-rw-r--r--packages/astro/src/assets/endpoint/node.ts2
-rw-r--r--packages/astro/src/assets/internal.ts2
-rw-r--r--packages/astro/src/assets/utils/imageKind.ts2
-rw-r--r--packages/astro/src/cli/add/index.ts1
-rw-r--r--packages/astro/src/cli/create-key/index.ts1
-rw-r--r--packages/astro/src/cli/index.ts1
-rw-r--r--packages/astro/src/cli/info/index.ts1
-rw-r--r--packages/astro/src/cli/preferences/index.ts9
-rw-r--r--packages/astro/src/cli/telemetry/index.ts1
-rw-r--r--packages/astro/src/cli/throw-and-exit.ts1
-rw-r--r--packages/astro/src/content/runtime.ts6
-rw-r--r--packages/astro/src/content/types-generator.ts2
-rw-r--r--packages/astro/src/core/app/node.ts52
-rw-r--r--packages/astro/src/core/build/generate.ts77
-rw-r--r--packages/astro/src/core/build/internal.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-ssr.ts4
-rw-r--r--packages/astro/src/core/config/config.ts2
-rw-r--r--packages/astro/src/core/config/schema.ts7
-rw-r--r--packages/astro/src/core/cookies/cookies.ts1
-rw-r--r--packages/astro/src/core/dev/restart.ts2
-rw-r--r--packages/astro/src/core/logger/console.ts2
-rw-r--r--packages/astro/src/core/messages.ts2
-rw-r--r--packages/astro/src/core/middleware/index.ts8
-rw-r--r--packages/astro/src/core/preview/vite-plugin-astro-preview.ts2
-rw-r--r--packages/astro/src/core/render-context.ts4
-rw-r--r--packages/astro/src/events/error.ts2
-rw-r--r--packages/astro/src/i18n/utils.ts19
-rw-r--r--packages/astro/src/i18n/vite-plugin-i18n.ts2
-rw-r--r--packages/astro/src/jsx/rehype.ts1
-rw-r--r--packages/astro/src/prefetch/index.ts1
-rw-r--r--packages/astro/src/runtime/client/dev-toolbar/settings.ts1
-rw-r--r--packages/astro/src/runtime/client/dev-toolbar/toolbar.ts1
-rw-r--r--packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts1
-rw-r--r--packages/astro/src/runtime/server/astro-island.ts4
-rw-r--r--packages/astro/src/runtime/server/render/astro/instance.ts1
-rw-r--r--packages/astro/src/runtime/server/render/component.ts1
-rw-r--r--packages/astro/src/runtime/server/render/util.ts1
-rw-r--r--packages/astro/src/runtime/server/transition.ts2
-rw-r--r--packages/astro/src/transitions/router.ts3
-rw-r--r--packages/astro/src/types/public/config.ts27
-rw-r--r--packages/astro/src/vite-plugin-astro-server/response.ts6
-rw-r--r--packages/astro/src/vite-plugin-astro-server/route.ts2
-rw-r--r--packages/astro/src/vite-plugin-astro-server/vite.ts2
47 files changed, 175 insertions, 103 deletions
diff --git a/packages/astro/src/actions/runtime/middleware.ts b/packages/astro/src/actions/runtime/middleware.ts
index 22d4f9c7d..78c0e93a6 100644
--- a/packages/astro/src/actions/runtime/middleware.ts
+++ b/packages/astro/src/actions/runtime/middleware.ts
@@ -27,7 +27,6 @@ const encoder = new TextEncoder();
export const onRequest = defineMiddleware(async (context, next) => {
if (context.isPrerendered) {
if (context.request.method === 'POST') {
- // eslint-disable-next-line no-console
console.warn(
yellow('[astro:actions]'),
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".',
@@ -145,7 +144,6 @@ async function redirectWithResult({
if (!referer) {
throw new Error('Internal: Referer unexpectedly missing from Action POST request.');
}
-
return context.redirect(referer);
}
diff --git a/packages/astro/src/actions/runtime/route.ts b/packages/astro/src/actions/runtime/route.ts
index 5827e431f..d1f4d1669 100644
--- a/packages/astro/src/actions/runtime/route.ts
+++ b/packages/astro/src/actions/runtime/route.ts
@@ -10,7 +10,6 @@ export const POST: APIRoute = async (context) => {
baseAction = await getAction(url.pathname);
} catch (e) {
if (import.meta.env.DEV) throw e;
- // eslint-disable-next-line no-console
console.error(e);
return new Response(e instanceof Error ? e.message : null, { status: 404 });
}
diff --git a/packages/astro/src/actions/runtime/virtual/shared.ts b/packages/astro/src/actions/runtime/virtual/shared.ts
index f250b0a1a..4067ad321 100644
--- a/packages/astro/src/actions/runtime/virtual/shared.ts
+++ b/packages/astro/src/actions/runtime/virtual/shared.ts
@@ -57,8 +57,7 @@ const statusToCodeMap: Record<number, ActionErrorCode> = Object.entries(codeToSt
// T is used for error inference with SafeInput -> isInputError.
// See: https://github.com/withastro/astro/pull/11173/files#r1622767246
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export class ActionError<T extends ErrorInferenceObject = ErrorInferenceObject> extends Error {
+export class ActionError<_T extends ErrorInferenceObject = ErrorInferenceObject> extends Error {
type = 'AstroActionError';
code: ActionErrorCode = 'INTERNAL_SERVER_ERROR';
status = 500;
diff --git a/packages/astro/src/assets/endpoint/generic.ts b/packages/astro/src/assets/endpoint/generic.ts
index d453787fd..f8924134b 100644
--- a/packages/astro/src/assets/endpoint/generic.ts
+++ b/packages/astro/src/assets/endpoint/generic.ts
@@ -73,7 +73,6 @@ export const GET: APIRoute = async ({ request }) => {
},
});
} catch (err: unknown) {
- // eslint-disable-next-line no-console
console.error('Could not process image request:', err);
return new Response(`Server Error: ${err}`, { status: 500 });
}
diff --git a/packages/astro/src/assets/endpoint/node.ts b/packages/astro/src/assets/endpoint/node.ts
index 04275652c..4312e28cb 100644
--- a/packages/astro/src/assets/endpoint/node.ts
+++ b/packages/astro/src/assets/endpoint/node.ts
@@ -1,5 +1,5 @@
import { readFile } from 'node:fs/promises';
-/* eslint-disable no-console */
+
import os from 'node:os';
import { isAbsolute } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts
index 9a5926e8d..a984ff025 100644
--- a/packages/astro/src/assets/internal.ts
+++ b/packages/astro/src/assets/internal.ts
@@ -80,7 +80,7 @@ export async function getImage(
// Causing our generate step to think the image is used outside of the image optimization pipeline
const clonedSrc = isESMImportedImage(resolvedOptions.src)
? // @ts-expect-error - clone is a private, hidden prop
- resolvedOptions.src.clone ?? resolvedOptions.src
+ (resolvedOptions.src.clone ?? resolvedOptions.src)
: resolvedOptions.src;
resolvedOptions.src = clonedSrc;
diff --git a/packages/astro/src/assets/utils/imageKind.ts b/packages/astro/src/assets/utils/imageKind.ts
index 7b42f9f70..e3e1b3341 100644
--- a/packages/astro/src/assets/utils/imageKind.ts
+++ b/packages/astro/src/assets/utils/imageKind.ts
@@ -9,5 +9,5 @@ export function isRemoteImage(src: ImageMetadata | string): src is string {
}
export async function resolveSrc(src: UnresolvedImageTransform['src']) {
- return typeof src === 'object' && 'then' in src ? (await src).default ?? (await src) : src;
+ return typeof src === 'object' && 'then' in src ? ((await src).default ?? (await src)) : src;
}
diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts
index 313f4f89a..11ddaffbe 100644
--- a/packages/astro/src/cli/add/index.ts
+++ b/packages/astro/src/cli/add/index.ts
@@ -690,7 +690,6 @@ async function tryToInstallIntegrations({
spinner.error();
logger.debug('add', 'Error installing dependencies', err);
// NOTE: `err.stdout` can be an empty string, so log the full error instead for a more helpful log
- // eslint-disable-next-line no-console
console.error('\n', err.stdout || err.message, '\n');
return UpdateResult.failure;
}
diff --git a/packages/astro/src/cli/create-key/index.ts b/packages/astro/src/cli/create-key/index.ts
index d9b9f08ff..bc03c5357 100644
--- a/packages/astro/src/cli/create-key/index.ts
+++ b/packages/astro/src/cli/create-key/index.ts
@@ -23,7 +23,6 @@ ASTRO_KEY=${encoded}`,
);
} catch (err: unknown) {
if (err != null) {
- // eslint-disable-next-line no-console
console.error(err.toString());
}
return 1;
diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts
index 23486f938..5f1cc75a9 100644
--- a/packages/astro/src/cli/index.ts
+++ b/packages/astro/src/cli/index.ts
@@ -1,4 +1,3 @@
-/* eslint-disable no-console */
import * as colors from 'kleur/colors';
import yargs from 'yargs-parser';
import { ASTRO_VERSION } from '../core/constants.js';
diff --git a/packages/astro/src/cli/info/index.ts b/packages/astro/src/cli/info/index.ts
index ff0d35081..ab24e2213 100644
--- a/packages/astro/src/cli/info/index.ts
+++ b/packages/astro/src/cli/info/index.ts
@@ -1,6 +1,5 @@
import { execSync } from 'node:child_process';
import { arch, platform } from 'node:os';
-/* eslint-disable no-console */
import * as colors from 'kleur/colors';
import prompts from 'prompts';
import { resolveConfig } from '../../core/config/index.js';
diff --git a/packages/astro/src/cli/preferences/index.ts b/packages/astro/src/cli/preferences/index.ts
index bd60343c2..c31841d24 100644
--- a/packages/astro/src/cli/preferences/index.ts
+++ b/packages/astro/src/cli/preferences/index.ts
@@ -1,12 +1,8 @@
-/* eslint-disable no-console */
-import type { AstroSettings } from '../../types/astro.js';
-
import { fileURLToPath } from 'node:url';
-import { bgGreen, black, bold, dim, yellow } from 'kleur/colors';
-
import { formatWithOptions } from 'node:util';
import dlv from 'dlv';
import { flattie } from 'flattie';
+import { bgGreen, black, bold, dim, yellow } from 'kleur/colors';
import { resolveConfig } from '../../core/config/config.js';
import { createSettings } from '../../core/config/settings.js';
import { collectErrorMetadata } from '../../core/errors/dev/utils.js';
@@ -14,6 +10,7 @@ import * as msg from '../../core/messages.js';
import { apply as applyPolyfill } from '../../core/polyfill.js';
import { DEFAULT_PREFERENCES } from '../../preferences/defaults.js';
import { type PreferenceKey, coerce, isValidKey } from '../../preferences/index.js';
+import type { AstroSettings } from '../../types/astro.js';
import { type Flags, createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js';
interface PreferencesOptions {
@@ -335,7 +332,7 @@ function formatTable(object: Record<string, AnnotatedValue>, columnLabels: [stri
const colALength = [colA, ...Object.keys(object)].reduce(longest, 0) + 3;
const colBLength = [colB, ...Object.values(object).map(annotatedFormat)].reduce(longest, 0) + 3;
function formatRow(
- i: number,
+ _i: number,
a: string,
b: AnnotatedValue,
style: (value: string | number | boolean) => string = (v) => v.toString(),
diff --git a/packages/astro/src/cli/telemetry/index.ts b/packages/astro/src/cli/telemetry/index.ts
index 276f00ef1..a854220c3 100644
--- a/packages/astro/src/cli/telemetry/index.ts
+++ b/packages/astro/src/cli/telemetry/index.ts
@@ -1,4 +1,3 @@
-/* eslint-disable no-console */
import * as msg from '../../core/messages.js';
import { telemetry } from '../../events/index.js';
import { type Flags, createLoggerFromFlags } from '../flags.js';
diff --git a/packages/astro/src/cli/throw-and-exit.ts b/packages/astro/src/cli/throw-and-exit.ts
index 1a8916ede..b7821caa5 100644
--- a/packages/astro/src/cli/throw-and-exit.ts
+++ b/packages/astro/src/cli/throw-and-exit.ts
@@ -1,4 +1,3 @@
-/* eslint-disable no-console */
import { collectErrorMetadata } from '../core/errors/dev/index.js';
import { isAstroConfigZodError } from '../core/errors/errors.js';
import { createSafeError } from '../core/errors/index.js';
diff --git a/packages/astro/src/content/runtime.ts b/packages/astro/src/content/runtime.ts
index 82dc3058e..6a8d3f214 100644
--- a/packages/astro/src/content/runtime.ts
+++ b/packages/astro/src/content/runtime.ts
@@ -98,7 +98,6 @@ export function createGetCollection({
}
return result;
} else {
- // eslint-disable-next-line no-console
console.warn(
`The collection ${JSON.stringify(
collection,
@@ -183,7 +182,6 @@ export function createGetEntryBySlug({
message: AstroErrorData.GetEntryDeprecationError.message(collection, 'getEntryBySlug'),
});
}
- // eslint-disable-next-line no-console
console.warn(
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`,
);
@@ -228,7 +226,6 @@ export function createGetDataEntryById({
if (store.hasCollection(collection)) {
return getEntry(collection, id);
}
- // eslint-disable-next-line no-console
console.warn(
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`,
);
@@ -319,7 +316,6 @@ export function createGetEntry({
if (store.hasCollection(collection)) {
const entry = store.get<DataEntry>(collection, lookupId);
if (!entry) {
- // eslint-disable-next-line no-console
console.warn(`Entry ${collection} → ${lookupId} was not found.`);
return;
}
@@ -337,7 +333,6 @@ export function createGetEntry({
}
if (!collectionNames.has(collection)) {
- // eslint-disable-next-line no-console
console.warn(
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`,
);
@@ -487,7 +482,6 @@ export async function renderEntry(
renderEntryImport,
});
} catch (e) {
- // eslint-disable-next-line
console.error(e);
}
}
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index 7ed44bec8..9ede0ab66 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -477,7 +477,7 @@ async function writeContentFiles({
collection.type === 'unknown'
? // Add empty / unknown collections to the data type map by default
// This ensures `getCollection('empty-collection')` doesn't raise a type error
- collectionConfig?.type ?? 'data'
+ (collectionConfig?.type ?? 'data')
: collection.type;
const collectionEntryKeys = Object.keys(collection.entries).sort();
diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts
index 77c7b16e4..b7b485ea8 100644
--- a/packages/astro/src/core/app/node.ts
+++ b/packages/astro/src/core/app/node.ts
@@ -1,5 +1,6 @@
import fs from 'node:fs';
import type { IncomingMessage, ServerResponse } from 'node:http';
+import { Http2ServerResponse } from 'node:http2';
import type { RouteData } from '../../types/public/internal.js';
import { deserializeManifest } from './common.js';
import { createOutgoingHttpHeaders } from './createOutgoingHttpHeaders.js';
@@ -60,16 +61,34 @@ export class NodeApp extends App {
* ```
*/
static createRequest(req: NodeRequest, { skipBody = false } = {}): Request {
- const protocol =
- req.headers['x-forwarded-proto'] ??
- ('encrypted' in req.socket && req.socket.encrypted ? 'https' : 'http');
- const hostname =
- req.headers['x-forwarded-host'] ?? req.headers.host ?? req.headers[':authority'];
- const port = req.headers['x-forwarded-port'];
+ const isEncrypted = 'encrypted' in req.socket && req.socket.encrypted;
+
+ // Parses multiple header and returns first value if available.
+ const getFirstForwardedValue = (multiValueHeader?: string | string[]) => {
+ return multiValueHeader
+ ?.toString()
+ ?.split(',')
+ .map((e) => e.trim())?.[0];
+ };
+
+ // Get the used protocol between the end client and first proxy.
+ // NOTE: Some proxies append values with spaces and some do not.
+ // We need to handle it here and parse the header correctly.
+ // @example "https, http,http" => "http"
+ const forwardedProtocol = getFirstForwardedValue(req.headers['x-forwarded-proto']);
+ const protocol = forwardedProtocol ?? (isEncrypted ? 'https' : 'http');
+
+ // @example "example.com,www2.example.com" => "example.com"
+ const forwardedHostname = getFirstForwardedValue(req.headers['x-forwarded-host']);
+ const hostname = forwardedHostname ?? req.headers.host ?? req.headers[':authority'];
+
+ // @example "443,8080,80" => "443"
+ const forwardedPort = getFirstForwardedValue(req.headers['x-forwarded-port']);
+ const port =
+ forwardedPort ?? req.socket?.remotePort?.toString() ?? (isEncrypted ? '443' : '80');
- const portInHostname =
- typeof hostname === 'string' && typeof port === 'string' && hostname.endsWith(port);
- const hostnamePort = portInHostname ? hostname : hostname + (port ? `:${port}` : '');
+ const portInHostname = typeof hostname === 'string' && /:\d+$/.test(hostname);
+ const hostnamePort = portInHostname ? hostname : `${hostname}:${port}`;
const url = `${protocol}://${hostnamePort}${req.url}`;
const options: RequestInit = {
@@ -80,14 +99,17 @@ export class NodeApp extends App {
if (bodyAllowed) {
Object.assign(options, makeRequestBody(req));
}
+
const request = new Request(url, options);
- const clientIp = req.headers['x-forwarded-for'];
+ // Get the IP of end client behind the proxy.
+ // @example "1.1.1.1,8.8.8.8" => "1.1.1.1"
+ const forwardedClientIp = getFirstForwardedValue(req.headers['x-forwarded-for']);
+ const clientIp = forwardedClientIp || req.socket?.remoteAddress;
if (clientIp) {
Reflect.set(request, clientAddressSymbol, clientIp);
- } else if (req.socket?.remoteAddress) {
- Reflect.set(request, clientAddressSymbol, req.socket.remoteAddress);
}
+
return request;
}
@@ -108,7 +130,10 @@ export class NodeApp extends App {
*/
static async writeResponse(source: Response, destination: ServerResponse) {
const { status, headers, body, statusText } = source;
- destination.statusMessage = statusText;
+ // HTTP/2 doesn't support statusMessage
+ if (!(destination instanceof Http2ServerResponse)) {
+ destination.statusMessage = statusText;
+ }
destination.writeHead(status, createOutgoingHttpHeaders(headers));
if (!body) return destination.end();
try {
@@ -118,7 +143,6 @@ export class NodeApp extends App {
// an error in the ReadableStream's cancel callback, but
// also because of an error anywhere in the stream.
reader.cancel().catch((err) => {
- // eslint-disable-next-line no-console
console.error(
`There was an uncaught error in the middle of the stream while rendering ${destination.req.url}.`,
err,
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 64ba64309..a26eca79b 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -1,6 +1,7 @@
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,
@@ -173,6 +174,40 @@ async function generatePage(
styles,
mod: pageModule,
};
+
+ async function generatePathWithLogs(
+ path: string,
+ route: RouteData,
+ index: number,
+ paths: string[],
+ isConcurrent: boolean,
+ ) {
+ 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 ? '└─' : '├─';
+
+ // Log the rendering path first if not concurrent. We'll later append the time taken to render.
+ // We skip if it's concurrent as the logs may overlap
+ 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}`);
+ }
+ }
+
// Now we explode the routes. A route render itself, and it can render its fallbacks (i18n routing)
for (const route of eachRouteInRouteData(pageData)) {
const icon =
@@ -180,28 +215,24 @@ async function generatePage(
? green('▶')
: magenta('λ');
logger.info(null, `${icon} ${getPrettyRouteName(route)}`);
+
// Get paths for the route, calling getStaticPaths if needed.
const paths = await getPathsForRoute(route, pageModule, pipeline, builtPaths);
- let timeStart = performance.now();
- let prevTimeEnd = timeStart;
- for (let i = 0; i < paths.length; i++) {
- const path = paths[i];
- pipeline.logger.debug('build', `Generating: ${path}`);
- const filePath = getOutputFilename(config, path, pageData.route.type);
- const lineIcon = i === paths.length - 1 ? '└─' : '├─';
- logger.info(null, ` ${blue(lineIcon)} ${dim(filePath)}`, false);
- await generatePath(path, pipeline, generationOptions, route);
- const timeEnd = performance.now();
- const timeChange = getTimeStat(prevTimeEnd, timeEnd);
- const timeIncrease = `(+${timeChange})`;
- let timeIncreaseLabel;
- if (timeEnd - prevTimeEnd > THRESHOLD_SLOW_RENDER_TIME_MS) {
- timeIncreaseLabel = red(timeIncrease);
- } else {
- timeIncreaseLabel = dim(timeIncrease);
+
+ // Generate each paths
+ if (config.build.concurrency > 1) {
+ const limit = PLimit(config.build.concurrency);
+ const promises: Promise<void>[] = [];
+ 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);
}
- logger.info('SKIP_FORMAT', ` ${timeIncreaseLabel}`);
- prevTimeEnd = timeEnd;
}
}
}
@@ -309,14 +340,6 @@ function getInvalidRouteSegmentError(
});
}
-interface GeneratePathOptions {
- pageData: PageBuildData;
- linkIds: string[];
- scripts: { type: 'inline' | 'external'; value: string } | null;
- styles: StylesheetAsset[];
- mod: ComponentInstance;
-}
-
function addPageName(pathname: string, opts: StaticBuildOptions): void {
const trailingSlash = opts.settings.config.trailingSlash;
const buildFormat = opts.settings.config.build.format;
diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts
index 2de34467e..4e3675876 100644
--- a/packages/astro/src/core/build/internal.ts
+++ b/packages/astro/src/core/build/internal.ts
@@ -123,7 +123,7 @@ export function createBuildInternals(): BuildInternals {
export function trackPageData(
internals: BuildInternals,
- component: string,
+ _component: string,
pageData: PageBuildData,
componentModuleId: string,
componentURL: URL,
diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts
index 68745817b..6acc236ae 100644
--- a/packages/astro/src/core/build/plugins/plugin-ssr.ts
+++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts
@@ -100,7 +100,7 @@ function vitePluginSSR(
contents.push(`const pageMap = new Map([\n ${pageMap.join(',\n ')}\n]);`);
exports.push(`export { pageMap }`);
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
- const ssrCode = generateSSRCode(options.settings, adapter, middleware!.id);
+ const ssrCode = generateSSRCode(adapter, middleware!.id);
imports.push(...ssrCode.imports);
contents.push(...ssrCode.contents);
return [...imports, ...contents, ...exports].join('\n');
@@ -163,7 +163,7 @@ export function pluginSSR(
};
}
-function generateSSRCode(settings: AstroSettings, adapter: AstroAdapter, middlewareId: string) {
+function generateSSRCode(adapter: AstroAdapter, middlewareId: string) {
const edgeMiddleware = adapter?.adapterFeatures?.edgeMiddleware ?? false;
const imports = [
diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts
index 3e19db801..ae15805ff 100644
--- a/packages/astro/src/core/config/config.ts
+++ b/packages/astro/src/core/config/config.ts
@@ -97,7 +97,6 @@ async function loadConfig(
} catch (e) {
const configPathText = configFile ? colors.bold(configFile) : 'your Astro config';
// Config errors should bypass log level as it breaks startup
- // eslint-disable-next-line no-console
console.error(`${colors.bold(colors.red('[astro]'))} Unable to load ${configPathText}\n`);
throw e;
}
@@ -158,7 +157,6 @@ export async function resolveConfig(
// Mark this error so the callee can decide to suppress Zod's error if needed.
// We still want to throw the error to signal an error in validation.
trackAstroConfigZodError(e);
- // eslint-disable-next-line no-console
console.error(formatConfigErrorMessage(e) + '\n');
telemetry.record(eventConfigError({ cmd: command, err: e, isFatal: true }));
}
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index eec3d869d..48af43339 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -63,6 +63,7 @@ export const ASTRO_CONFIG_DEFAULTS = {
serverEntry: 'entry.mjs',
redirects: true,
inlineStylesheets: 'auto',
+ concurrency: 1,
},
image: {
endpoint: { entrypoint: undefined, route: '/_image' },
@@ -187,6 +188,7 @@ export const AstroConfigSchema = z.object({
.enum(['always', 'auto', 'never'])
.optional()
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
+ concurrency: z.number().min(1).optional().default(ASTRO_CONFIG_DEFAULTS.build.concurrency),
})
.default({}),
server: z.preprocess(
@@ -316,6 +318,10 @@ export const AstroConfigSchema = z.object({
return langs;
})
.default([]),
+ langAlias: z
+ .record(z.string(), z.string())
+ .optional()
+ .default(ASTRO_CONFIG_DEFAULTS.markdown.shikiConfig.langAlias!),
theme: z
.enum(Object.keys(bundledThemes) as [BuiltinTheme, ...BuiltinTheme[]])
.or(z.custom<ShikiTheme>())
@@ -615,6 +621,7 @@ export function createRelativeSchema(cmd: string, fileProtocolRoot: string) {
.enum(['always', 'auto', 'never'])
.optional()
.default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets),
+ concurrency: z.number().min(1).optional().default(ASTRO_CONFIG_DEFAULTS.build.concurrency),
})
.optional()
.default({}),
diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts
index 852be913d..f2679f23f 100644
--- a/packages/astro/src/core/cookies/cookies.ts
+++ b/packages/astro/src/core/cookies/cookies.ts
@@ -156,7 +156,6 @@ class AstroCookies implements AstroCookiesInterface {
'Please make sure that Astro.cookies.set() is only called in the frontmatter of the main page.',
);
warning.name = 'Warning';
- // eslint-disable-next-line no-console
console.warn(warning);
}
let serializedValue: string;
diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts
index 9d68f4365..e9ac726f6 100644
--- a/packages/astro/src/core/dev/restart.ts
+++ b/packages/astro/src/core/dev/restart.ts
@@ -32,7 +32,7 @@ async function createRestartedContainer(
return newContainer;
}
-const configRE = /.*astro.config.(?:mjs|cjs|js|ts)$/;
+const configRE = /.*astro.config.(?:mjs|mts|cjs|cts|js|ts)$/;
function shouldRestartContainer(
{ settings, inlineConfig, restartInFlight }: Container,
diff --git a/packages/astro/src/core/logger/console.ts b/packages/astro/src/core/logger/console.ts
index ae7241447..30368bd86 100644
--- a/packages/astro/src/core/logger/console.ts
+++ b/packages/astro/src/core/logger/console.ts
@@ -2,10 +2,8 @@ import { type LogMessage, type LogWritable, getEventPrefix, levels } from './cor
export const consoleLogDestination: LogWritable<LogMessage> = {
write(event: LogMessage) {
- // eslint-disable-next-line no-console
let dest = console.error;
if (levels[event.level] < levels['error']) {
- // eslint-disable-next-line no-console
dest = console.log;
}
if (event.label === 'SKIP_FORMAT') {
diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts
index 8104d993b..3081c0b6c 100644
--- a/packages/astro/src/core/messages.ts
+++ b/packages/astro/src/core/messages.ts
@@ -380,6 +380,6 @@ export function printHelp({
message.push(linebreak(), `${description}`);
}
- // eslint-disable-next-line no-console
+ // biome-ignore lint/suspicious/noConsoleLog: allowed
console.log(message.join('\n') + '\n');
}
diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts
index 1d604957b..facd64231 100644
--- a/packages/astro/src/core/middleware/index.ts
+++ b/packages/astro/src/core/middleware/index.ts
@@ -32,6 +32,11 @@ export type CreateContext = {
* A list of locales that are supported by the user
*/
userDefinedLocales?: string[];
+
+ /**
+ * User defined default locale
+ */
+ defaultLocale: string;
};
/**
@@ -41,6 +46,7 @@ function createContext({
request,
params = {},
userDefinedLocales = [],
+ defaultLocale = '',
}: CreateContext): APIContext {
let preferredLocale: string | undefined = undefined;
let preferredLocaleList: string[] | undefined = undefined;
@@ -78,7 +84,7 @@ function createContext({
return (preferredLocaleList ??= computePreferredLocaleList(request, userDefinedLocales));
},
get currentLocale(): string | undefined {
- return (currentLocale ??= computeCurrentLocale(route, userDefinedLocales));
+ return (currentLocale ??= computeCurrentLocale(route, userDefinedLocales, defaultLocale));
},
url,
get clientAddress() {
diff --git a/packages/astro/src/core/preview/vite-plugin-astro-preview.ts b/packages/astro/src/core/preview/vite-plugin-astro-preview.ts
index fd9bbae66..992f82f14 100644
--- a/packages/astro/src/core/preview/vite-plugin-astro-preview.ts
+++ b/packages/astro/src/core/preview/vite-plugin-astro-preview.ts
@@ -74,7 +74,7 @@ export function vitePluginAstroPreview(settings: AstroSettings): Plugin {
return () => {
// NOTE: the `base` is stripped from `req.url` for post middlewares
- server.middlewares.use((req, res, next) => {
+ server.middlewares.use((req, _res, next) => {
const pathname = cleanUrl(req.url!);
// Vite doesn't handle /foo/ if /foo.html exists, we handle it anyways
diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts
index 5a20b795d..1088accc1 100644
--- a/packages/astro/src/core/render-context.ts
+++ b/packages/astro/src/core/render-context.ts
@@ -520,8 +520,8 @@ export class RenderContext {
// and url.pathname to pass Astro.currentLocale tests.
// A single call with `routeData.pathname ?? routeData.route` as the pathname still fails.
return (this.#currentLocale ??=
- computeCurrentLocale(routeData.route, locales) ??
- computeCurrentLocale(url.pathname, locales) ??
+ computeCurrentLocale(routeData.route, locales, defaultLocale) ??
+ computeCurrentLocale(url.pathname, locales, defaultLocale) ??
fallbackTo);
}
diff --git a/packages/astro/src/events/error.ts b/packages/astro/src/events/error.ts
index fc8eddfd8..65e0cabb7 100644
--- a/packages/astro/src/events/error.ts
+++ b/packages/astro/src/events/error.ts
@@ -101,7 +101,7 @@ function getSafeErrorMessage(message: string | Function): string {
.slice(1, -1)
.replace(
/\$\{([^}]+)\}/g,
- (str, match1) =>
+ (_str, match1) =>
`${match1
.split(/\.?(?=[A-Z])/)
.join('_')
diff --git a/packages/astro/src/i18n/utils.ts b/packages/astro/src/i18n/utils.ts
index 5dc58908a..98eb4c94a 100644
--- a/packages/astro/src/i18n/utils.ts
+++ b/packages/astro/src/i18n/utils.ts
@@ -148,7 +148,11 @@ export function computePreferredLocaleList(request: Request, locales: Locales):
return result;
}
-export function computeCurrentLocale(pathname: string, locales: Locales): undefined | string {
+export function computeCurrentLocale(
+ pathname: string,
+ locales: Locales,
+ defaultLocale: string,
+): string | undefined {
for (const segment of pathname.split('/')) {
for (const locale of locales) {
if (typeof locale === 'string') {
@@ -171,6 +175,19 @@ export function computeCurrentLocale(pathname: string, locales: Locales): undefi
}
}
}
+ // If we didn't exit, it's probably because we don't have any code/locale in the URL.
+ // We use the default locale.
+ for (const locale of locales) {
+ if (typeof locale === 'string') {
+ if (locale === defaultLocale) {
+ return locale;
+ }
+ } else {
+ if (locale.path === defaultLocale) {
+ return locale.codes.at(0);
+ }
+ }
+ }
}
export type RoutingStrategies =
diff --git a/packages/astro/src/i18n/vite-plugin-i18n.ts b/packages/astro/src/i18n/vite-plugin-i18n.ts
index 5ee79a883..11a1177c6 100644
--- a/packages/astro/src/i18n/vite-plugin-i18n.ts
+++ b/packages/astro/src/i18n/vite-plugin-i18n.ts
@@ -30,7 +30,7 @@ export default function astroInternationalization({
return {
name: 'astro:i18n',
enforce: 'pre',
- config(config, { command }) {
+ config(_config, { command }) {
const i18nConfig: I18nInternalConfig = {
base,
format,
diff --git a/packages/astro/src/jsx/rehype.ts b/packages/astro/src/jsx/rehype.ts
index a93a92d5d..3db1a3070 100644
--- a/packages/astro/src/jsx/rehype.ts
+++ b/packages/astro/src/jsx/rehype.ts
@@ -50,7 +50,6 @@ export const rehypeAnalyzeAstroMetadata: RehypePlugin = () => {
(attr) => attr.type === 'mdxJsxAttribute' && attr.name.startsWith('client:'),
) as MdxJsxAttribute | undefined;
if (clientAttribute) {
- // eslint-disable-next-line
console.warn(
`You are attempting to render <${node.name!} ${
clientAttribute.name
diff --git a/packages/astro/src/prefetch/index.ts b/packages/astro/src/prefetch/index.ts
index 3eb8cd570..70f7052d3 100644
--- a/packages/astro/src/prefetch/index.ts
+++ b/packages/astro/src/prefetch/index.ts
@@ -2,7 +2,6 @@
NOTE: Do not add any dependencies or imports in this file so that it can load quickly in dev.
*/
-// eslint-disable-next-line no-console
const debug = import.meta.env.DEV ? console.debug : undefined;
const inBrowser = import.meta.env.SSR === false;
// Track prefetched URLs so we don't prefetch twice
diff --git a/packages/astro/src/runtime/client/dev-toolbar/settings.ts b/packages/astro/src/runtime/client/dev-toolbar/settings.ts
index 538473326..8441afc2f 100644
--- a/packages/astro/src/runtime/client/dev-toolbar/settings.ts
+++ b/packages/astro/src/runtime/client/dev-toolbar/settings.ts
@@ -28,7 +28,6 @@ function getSettings() {
}
function log(message: string, level: 'log' | 'warn' | 'error' = 'log') {
- // eslint-disable-next-line no-console
console[level](
`%cAstro`,
'background: linear-gradient(66.77deg, #D83333 0%, #F041FF 100%); color: white; padding-inline: 4px; border-radius: 2px; font-family: monospace;',
diff --git a/packages/astro/src/runtime/client/dev-toolbar/toolbar.ts b/packages/astro/src/runtime/client/dev-toolbar/toolbar.ts
index 7f5f2ac47..1ab7e9d09 100644
--- a/packages/astro/src/runtime/client/dev-toolbar/toolbar.ts
+++ b/packages/astro/src/runtime/client/dev-toolbar/toolbar.ts
@@ -1,4 +1,3 @@
-/* eslint-disable no-console */
import type { ResolvedDevToolbarApp as DevToolbarAppDefinition } from '../../../types/public/toolbar.js';
import { type ToolbarAppEventTarget, serverHelpers } from './helpers.js';
import { settings } from './settings.js';
diff --git a/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts b/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
index 79508cc69..a223bf1a8 100644
--- a/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
+++ b/packages/astro/src/runtime/client/dev-toolbar/ui-library/radio-checkbox.ts
@@ -14,7 +14,6 @@ export class DevToolbarRadioCheckbox extends HTMLElement {
set radioStyle(value) {
if (!styles.includes(value)) {
- // eslint-disable-next-line no-console
console.error(`Invalid style: ${value}, expected one of ${styles.join(', ')}.`);
return;
}
diff --git a/packages/astro/src/runtime/server/astro-island.ts b/packages/astro/src/runtime/server/astro-island.ts
index 252ed65c8..d9a13146e 100644
--- a/packages/astro/src/runtime/server/astro-island.ts
+++ b/packages/astro/src/runtime/server/astro-island.ts
@@ -45,7 +45,7 @@ declare const Astro: {
return Object.fromEntries(Object.entries(raw).map(([key, value]) => [key, reviveTuple(value)]));
};
- // 🌊🏝️🌴
+ // 🌊🏝🌴
class AstroIsland extends HTMLElement {
public Component: any;
public hydrator: any;
@@ -127,7 +127,6 @@ declare const Astro: {
this,
);
} catch (e) {
- // eslint-disable-next-line no-console
console.error(`[astro-island] Error hydrating ${this.getAttribute('component-url')}`, e);
}
}
@@ -179,7 +178,6 @@ declare const Astro: {
componentName += ` (export ${componentExport})`;
}
- // eslint-disable-next-line no-console
console.error(
`[hydrate] Error parsing props for component ${componentName}`,
this.getAttribute('props'),
diff --git a/packages/astro/src/runtime/server/render/astro/instance.ts b/packages/astro/src/runtime/server/render/astro/instance.ts
index 029231a28..5ea2d5216 100644
--- a/packages/astro/src/runtime/server/render/astro/instance.ts
+++ b/packages/astro/src/runtime/server/render/astro/instance.ts
@@ -77,7 +77,6 @@ function validateComponentProps(props: any, displayName: string) {
if (props != null) {
for (const prop of Object.keys(props)) {
if (prop.startsWith('client:')) {
- // eslint-disable-next-line
console.warn(
`You are attempting to render <${displayName} ${prop} />, but ${displayName} is an Astro component. Astro components do not render in the client and should not have a hydration directive. Please use a framework component for client rendering.`,
);
diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts
index 017594e75..b7af9cd92 100644
--- a/packages/astro/src/runtime/server/render/component.ts
+++ b/packages/astro/src/runtime/server/render/component.ts
@@ -264,7 +264,6 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
: metadata.hydrateArgs;
if (!clientOnlyValues.has(rendererName)) {
// warning if provide incorrect client:only directive but find the renderer by guess
- // eslint-disable-next-line no-console
console.warn(
`The client:only directive for ${metadata.displayName} is not recognized. The renderer ${renderer.name} will be used. If you intended to use a different renderer, please provide a valid client:only directive.`,
);
diff --git a/packages/astro/src/runtime/server/render/util.ts b/packages/astro/src/runtime/server/render/util.ts
index 953488a83..2373d624c 100644
--- a/packages/astro/src/runtime/server/render/util.ts
+++ b/packages/astro/src/runtime/server/render/util.ts
@@ -66,7 +66,6 @@ export function addAttribute(value: any, key: string, shouldEscape = true) {
// compiler directives cannot be applied dynamically, log a warning and ignore.
if (STATIC_DIRECTIVES.has(key)) {
- // eslint-disable-next-line no-console
console.warn(`[astro] The "${key}" directive cannot be applied dynamically at runtime. It will not be rendered as an attribute.
Make sure to use the static attribute syntax (\`${key}={value}\`) instead of the dynamic spread syntax (\`{...{ "${key}": value }}\`).`);
diff --git a/packages/astro/src/runtime/server/transition.ts b/packages/astro/src/runtime/server/transition.ts
index 4baae442a..6f1cd5ba4 100644
--- a/packages/astro/src/runtime/server/transition.ts
+++ b/packages/astro/src/runtime/server/transition.ts
@@ -77,7 +77,7 @@ function reEncode(s: string) {
codepoint < 0x80
? codepoint === 95
? '__'
- : reEncodeValidChars[codepoint] ?? '_' + codepoint.toString(16).padStart(2, '0')
+ : (reEncodeValidChars[codepoint] ?? '_' + codepoint.toString(16).padStart(2, '0'))
: String.fromCodePoint(codepoint);
}
}
diff --git a/packages/astro/src/transitions/router.ts b/packages/astro/src/transitions/router.ts
index e136da92d..3db5a7549 100644
--- a/packages/astro/src/transitions/router.ts
+++ b/packages/astro/src/transitions/router.ts
@@ -543,7 +543,7 @@ async function transition(
// This log doesn't make it worse than before, where we got error messages about uncaught exceptions, which can't be caught when the trigger was a click or history traversal.
// Needs more investigation on root causes if errors still occur sporadically
const err = e as Error;
- // eslint-disable-next-line no-console
+ // biome-ignore lint/suspicious/noConsoleLog: allowed
console.log('[astro]', err.name, err.message, err.stack);
}
}
@@ -558,7 +558,6 @@ export async function navigate(href: string, options?: Options) {
'The view transitions client API was called during a server side render. This may be unintentional as the navigate() function is expected to be called in response to user interactions. Please make sure that your usage is correct.',
);
warning.name = 'Warning';
- // eslint-disable-next-line no-console
console.warn(warning);
navigateOnServerWarned = true;
}
diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts
index fda779bdc..66be4037b 100644
--- a/packages/astro/src/types/public/config.ts
+++ b/packages/astro/src/types/public/config.ts
@@ -727,6 +727,33 @@ export interface AstroUserConfig {
* ```
*/
inlineStylesheets?: 'always' | 'auto' | 'never';
+ /**
+ * @docs
+ * @name build.concurrency
+ * @type { number }
+ * @default `1`
+ * @version 4.16.0
+ * @description
+ * The number of pages to build in parallel.
+ *
+ * **In most cases, you should not change the default value of `1`.**
+ *
+ * Use this option only when other attempts to reduce the overall rendering time (e.g. batch or cache long running tasks like fetch calls or data access) are not possible or are insufficient.
+ * If the number is set too high, page rendering may slow down due to insufficient memory resources and because JS is single-threaded.
+ *
+ * ```js
+ * {
+ * build: {
+ * concurrency: 2
+ * }
+ * }
+ * ```
+ *
+ * :::caution[Breaking changes possible]
+ * This feature is stable and is not considered experimental. However, this feature is only intended to address difficult performance issues, and breaking changes may occur in a [minor release](https://docs.astro.build/en/upgrade-astro/#semantic-versioning) to keep this option as performant as possible. Please check the [Astro CHANGELOG](https://github.com/withastro/astro/blob/refs/heads/next/packages/astro/CHANGELOG.md) for every minor release if you are using this feature.
+ * :::
+ */
+ concurrency?: number;
};
/**
diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts
index bc316d7c2..a6257508e 100644
--- a/packages/astro/src/vite-plugin-astro-server/response.ts
+++ b/packages/astro/src/vite-plugin-astro-server/response.ts
@@ -1,4 +1,5 @@
import type http from 'node:http';
+import { Http2ServerResponse } from 'node:http2';
import type { ErrorWithMetadata } from '../core/errors/index.js';
import type { ModuleLoader } from '../core/module-loader/index.js';
@@ -67,7 +68,10 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re
if (headers.has('set-cookie')) {
_headers['set-cookie'] = headers.getSetCookie();
}
- res.statusMessage = statusText;
+ // HTTP/2 doesn't support statusMessage
+ if (!(res instanceof Http2ServerResponse)) {
+ res.statusMessage = statusText;
+ }
res.writeHead(status, _headers);
if (body) {
if (Symbol.for('astro.responseBody') in webResponse) {
diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts
index 6568b3f1f..459d24cc3 100644
--- a/packages/astro/src/vite-plugin-astro-server/route.ts
+++ b/packages/astro/src/vite-plugin-astro-server/route.ts
@@ -239,7 +239,7 @@ export async function handleRoute({
req({
url: pathname,
method: incomingRequest.method,
- statusCode: isRewrite ? response.status : status ?? response.status,
+ statusCode: isRewrite ? response.status : (status ?? response.status),
isRewrite,
reqTime: timeEnd - timeStart,
}),
diff --git a/packages/astro/src/vite-plugin-astro-server/vite.ts b/packages/astro/src/vite-plugin-astro-server/vite.ts
index 147853954..697174571 100644
--- a/packages/astro/src/vite-plugin-astro-server/vite.ts
+++ b/packages/astro/src/vite-plugin-astro-server/vite.ts
@@ -27,7 +27,7 @@ export async function* crawlGraph(
? // "getModulesByFile" pulls from a delayed module cache (fun implementation detail),
// So we can get up-to-date info on initial server load.
// Needed for slower CSS preprocessing like Tailwind
- loader.getModulesByFile(id) ?? new Set()
+ (loader.getModulesByFile(id) ?? new Set())
: // For non-root files, we're safe to pull from "getModuleById" based on testing.
// TODO: Find better invalidation strategy to use "getModuleById" in all cases!
new Set([loader.getModuleById(id)]);