refactor: internal refactor to use the Logger (#8227)

This commit is contained in:
Emanuele Stoppa 2023-08-25 15:57:47 +01:00 committed by GitHub
parent 2c07656c8d
commit f91acd8fca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 529 additions and 620 deletions

View file

@ -20,7 +20,7 @@ import type { AstroConfigType } from '../core/config';
import type { AstroTimer } from '../core/config/timer'; import type { AstroTimer } from '../core/config/timer';
import type { AstroCookies } from '../core/cookies'; import type { AstroCookies } from '../core/cookies';
import type { ResponseWithEncoding } from '../core/endpoint/index.js'; import type { ResponseWithEncoding } from '../core/endpoint/index.js';
import type { AstroIntegrationLogger, LogOptions, LoggerLevel } from '../core/logger/core'; import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core';
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server'; import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js'; import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
@ -1399,7 +1399,7 @@ export interface AstroInlineOnlyConfig {
/** /**
* @internal for testing only, use `logLevel` instead. * @internal for testing only, use `logLevel` instead.
*/ */
logging?: LogOptions; logger?: Logger;
} }
export type ContentEntryModule = { export type ContentEntryModule = {
@ -2067,7 +2067,7 @@ export type AstroMiddlewareInstance<R> = {
export interface AstroPluginOptions { export interface AstroPluginOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
} }
export type RouteType = 'page' | 'endpoint' | 'redirect'; export type RouteType = 'page' | 'endpoint' | 'redirect';

View file

@ -1,13 +1,12 @@
import fs, { readFileSync } from 'node:fs'; import fs, { readFileSync } from 'node:fs';
import { basename, join } from 'node:path/posix'; import { basename, join } from 'node:path/posix';
import type { StaticBuildOptions } from '../../core/build/types.js';
import { warn } from '../../core/logger/core.js';
import { prependForwardSlash } from '../../core/path.js'; import { prependForwardSlash } from '../../core/path.js';
import { isServerLikeOutput } from '../../prerender/utils.js'; import { isServerLikeOutput } from '../../prerender/utils.js';
import { getConfiguredImageService, isESMImportedImage } from '../internal.js'; import { getConfiguredImageService, isESMImportedImage } from '../internal.js';
import type { LocalImageService } from '../services/service.js'; import type { LocalImageService } from '../services/service.js';
import type { ImageMetadata, ImageTransform } from '../types.js'; import type { ImageMetadata, ImageTransform } from '../types.js';
import { loadRemoteImage, type RemoteCacheEntry } from './remote.js'; import { loadRemoteImage, type RemoteCacheEntry } from './remote.js';
import type { BuildPipeline } from '../../core/build/buildPipeline';
interface GenerationDataUncached { interface GenerationDataUncached {
cached: false; cached: false;
@ -24,19 +23,20 @@ interface GenerationDataCached {
type GenerationData = GenerationDataUncached | GenerationDataCached; type GenerationData = GenerationDataUncached | GenerationDataCached;
export async function generateImage( export async function generateImage(
buildOpts: StaticBuildOptions, pipeline: BuildPipeline,
options: ImageTransform, options: ImageTransform,
filepath: string filepath: string
): Promise<GenerationData | undefined> { ): Promise<GenerationData | undefined> {
const config = pipeline.getConfig();
const logger = pipeline.getLogger();
let useCache = true; let useCache = true;
const assetsCacheDir = new URL('assets/', buildOpts.settings.config.cacheDir); const assetsCacheDir = new URL('assets/', config.cacheDir);
// Ensure that the cache directory exists // Ensure that the cache directory exists
try { try {
await fs.promises.mkdir(assetsCacheDir, { recursive: true }); await fs.promises.mkdir(assetsCacheDir, { recursive: true });
} catch (err) { } catch (err) {
warn( logger.warn(
buildOpts.logging,
'astro:assets', 'astro:assets',
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}` `An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
); );
@ -44,12 +44,12 @@ export async function generateImage(
} }
let serverRoot: URL, clientRoot: URL; let serverRoot: URL, clientRoot: URL;
if (isServerLikeOutput(buildOpts.settings.config)) { if (isServerLikeOutput(config)) {
serverRoot = buildOpts.settings.config.build.server; serverRoot = config.build.server;
clientRoot = buildOpts.settings.config.build.client; clientRoot = config.build.client;
} else { } else {
serverRoot = buildOpts.settings.config.outDir; serverRoot = config.outDir;
clientRoot = buildOpts.settings.config.outDir; clientRoot = config.outDir;
} }
const isLocalImage = isESMImportedImage(options.src); const isLocalImage = isESMImportedImage(options.src);
@ -105,10 +105,7 @@ export async function generateImage(
if (isLocalImage) { if (isLocalImage) {
imageData = await fs.promises.readFile( imageData = await fs.promises.readFile(
new URL( new URL(
'.' + '.' + prependForwardSlash(join(config.build.assets, basename(originalImagePath))),
prependForwardSlash(
join(buildOpts.settings.config.build.assets, basename(originalImagePath))
),
serverRoot serverRoot
) )
); );
@ -120,11 +117,7 @@ export async function generateImage(
const imageService = (await getConfiguredImageService()) as LocalImageService; const imageService = (await getConfiguredImageService()) as LocalImageService;
resultData.data = ( resultData.data = (
await imageService.transform( await imageService.transform(imageData, { ...options, src: originalImagePath }, config.image)
imageData,
{ ...options, src: originalImagePath },
buildOpts.settings.config.image
)
).data; ).data;
try { try {
@ -143,8 +136,7 @@ export async function generateImage(
} }
} }
} catch (e) { } catch (e) {
warn( logger.warn(
buildOpts.logging,
'astro:assets', 'astro:assets',
`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}` `An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
); );

View file

@ -16,14 +16,14 @@ import {
updateTSConfigForFramework, updateTSConfigForFramework,
type frameworkWithTSSettings, type frameworkWithTSSettings,
} from '../../core/config/tsconfig.js'; } from '../../core/config/tsconfig.js';
import { debug, info, type LogOptions } from '../../core/logger/core.js'; import type { Logger } from '../../core/logger/core.js';
import * as msg from '../../core/messages.js'; import * as msg from '../../core/messages.js';
import { printHelp } from '../../core/messages.js'; import { printHelp } from '../../core/messages.js';
import { appendForwardSlash } from '../../core/path.js'; import { appendForwardSlash } from '../../core/path.js';
import { apply as applyPolyfill } from '../../core/polyfill.js'; import { apply as applyPolyfill } from '../../core/polyfill.js';
import { parseNpmName } from '../../core/util.js'; import { parseNpmName } from '../../core/util.js';
import { eventCliSession, telemetry } from '../../events/index.js'; import { eventCliSession, telemetry } from '../../events/index.js';
import { createLoggingFromFlags } from '../flags.js'; import { createLoggerFromFlags } from '../flags.js';
import { generate, parse, t, visit } from './babel.js'; import { generate, parse, t, visit } from './babel.js';
import { ensureImport } from './imports.js'; import { ensureImport } from './imports.js';
import { wrapDefaultExport } from './wrapper.js'; import { wrapDefaultExport } from './wrapper.js';
@ -130,10 +130,10 @@ export async function add(names: string[], { flags }: AddOptions) {
// Some packages might have a common alias! We normalize those here. // Some packages might have a common alias! We normalize those here.
const cwd = flags.root; const cwd = flags.root;
const logging = createLoggingFromFlags(flags); const logger = createLoggerFromFlags(flags);
const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name)); const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name));
const integrations = await validateIntegrations(integrationNames); const integrations = await validateIntegrations(integrationNames);
let installResult = await tryToInstallIntegrations({ integrations, cwd, flags, logging }); let installResult = await tryToInstallIntegrations({ integrations, cwd, flags, logger });
const rootPath = resolveRoot(cwd); const rootPath = resolveRoot(cwd);
const root = pathToFileURL(rootPath); const root = pathToFileURL(rootPath);
// Append forward slash to compute relative paths // Append forward slash to compute relative paths
@ -144,7 +144,8 @@ export async function add(names: string[], { flags }: AddOptions) {
if (integrations.find((integration) => integration.id === 'tailwind')) { if (integrations.find((integration) => integration.id === 'tailwind')) {
await setupIntegrationConfig({ await setupIntegrationConfig({
root, root,
logging, logger,
flags, flags,
integrationName: 'Tailwind', integrationName: 'Tailwind',
possibleConfigFiles: [ possibleConfigFiles: [
@ -159,7 +160,7 @@ export async function add(names: string[], { flags }: AddOptions) {
if (integrations.find((integration) => integration.id === 'svelte')) { if (integrations.find((integration) => integration.id === 'svelte')) {
await setupIntegrationConfig({ await setupIntegrationConfig({
root, root,
logging, logger,
flags, flags,
integrationName: 'Svelte', integrationName: 'Svelte',
possibleConfigFiles: ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'], possibleConfigFiles: ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'],
@ -175,7 +176,7 @@ export async function add(names: string[], { flags }: AddOptions) {
) { ) {
await setupIntegrationConfig({ await setupIntegrationConfig({
root, root,
logging, logger,
flags, flags,
integrationName: 'Lit', integrationName: 'Lit',
possibleConfigFiles: ['./.npmrc'], possibleConfigFiles: ['./.npmrc'],
@ -186,8 +187,7 @@ export async function add(names: string[], { flags }: AddOptions) {
break; break;
} }
case UpdateResult.cancelled: { case UpdateResult.cancelled: {
info( logger.info(
logging,
null, null,
msg.cancelled( msg.cancelled(
`Dependencies ${bold('NOT')} installed.`, `Dependencies ${bold('NOT')} installed.`,
@ -209,9 +209,9 @@ export async function add(names: string[], { flags }: AddOptions) {
let configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined; let configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined;
if (configURL) { if (configURL) {
debug('add', `Found config at ${configURL}`); logger.debug('add', `Found config at ${configURL}`);
} else { } else {
info(logging, 'add', `Unable to locate a config file, generating one for you.`); logger.info('add', `Unable to locate a config file, generating one for you.`);
configURL = new URL('./astro.config.mjs', root); configURL = new URL('./astro.config.mjs', root);
await fs.writeFile(fileURLToPath(configURL), ASTRO_CONFIG_STUB, { encoding: 'utf-8' }); await fs.writeFile(fileURLToPath(configURL), ASTRO_CONFIG_STUB, { encoding: 'utf-8' });
} }
@ -220,7 +220,7 @@ export async function add(names: string[], { flags }: AddOptions) {
try { try {
ast = await parseAstroConfig(configURL); ast = await parseAstroConfig(configURL);
debug('add', 'Parsed astro config'); logger.debug('add', 'Parsed astro config');
const defineConfig = t.identifier('defineConfig'); const defineConfig = t.identifier('defineConfig');
ensureImport( ensureImport(
@ -232,7 +232,7 @@ export async function add(names: string[], { flags }: AddOptions) {
); );
wrapDefaultExport(ast, defineConfig); wrapDefaultExport(ast, defineConfig);
debug('add', 'Astro config ensured `defineConfig`'); logger.debug('add', 'Astro config ensured `defineConfig`');
for (const integration of integrations) { for (const integration of integrations) {
if (isAdapter(integration)) { if (isAdapter(integration)) {
@ -240,8 +240,7 @@ export async function add(names: string[], { flags }: AddOptions) {
if (officialExportName) { if (officialExportName) {
await setAdapter(ast, integration, officialExportName); await setAdapter(ast, integration, officialExportName);
} else { } else {
info( logger.info(
logging,
null, null,
`\n ${magenta( `\n ${magenta(
`Check our deployment docs for ${bold( `Check our deployment docs for ${bold(
@ -253,10 +252,10 @@ export async function add(names: string[], { flags }: AddOptions) {
} else { } else {
await addIntegration(ast, integration); await addIntegration(ast, integration);
} }
debug('add', `Astro config added integration ${integration.id}`); logger.debug('add', `Astro config added integration ${integration.id}`);
} }
} catch (err) { } catch (err) {
debug('add', 'Error parsing/modifying astro config: ', err); logger.debug('add', 'Error parsing/modifying astro config: ', err);
throw createPrettyError(err as Error); throw createPrettyError(err as Error);
} }
@ -268,18 +267,18 @@ export async function add(names: string[], { flags }: AddOptions) {
configURL, configURL,
ast, ast,
flags, flags,
logging, logger,
logAdapterInstructions: integrations.some(isAdapter), logAdapterInstructions: integrations.some(isAdapter),
}); });
} catch (err) { } catch (err) {
debug('add', 'Error updating astro config', err); logger.debug('add', 'Error updating astro config', err);
throw createPrettyError(err as Error); throw createPrettyError(err as Error);
} }
} }
switch (configResult) { switch (configResult) {
case UpdateResult.cancelled: { case UpdateResult.cancelled: {
info(logging, null, msg.cancelled(`Your configuration has ${bold('NOT')} been updated.`)); logger.info(null, msg.cancelled(`Your configuration has ${bold('NOT')} been updated.`));
break; break;
} }
case UpdateResult.none: { case UpdateResult.none: {
@ -293,18 +292,17 @@ export async function add(names: string[], { flags }: AddOptions) {
(integration) => !deps.includes(integration.packageName) (integration) => !deps.includes(integration.packageName)
); );
if (missingDeps.length === 0) { if (missingDeps.length === 0) {
info(logging, null, msg.success(`Configuration up-to-date.`)); logger.info(null, msg.success(`Configuration up-to-date.`));
break; break;
} }
} }
info(logging, null, msg.success(`Configuration up-to-date.`)); logger.info(null, msg.success(`Configuration up-to-date.`));
break; break;
} }
default: { default: {
const list = integrations.map((integration) => ` - ${integration.packageName}`).join('\n'); const list = integrations.map((integration) => ` - ${integration.packageName}`).join('\n');
info( logger.info(
logging,
null, null,
msg.success( msg.success(
`Added the following integration${ `Added the following integration${
@ -315,15 +313,14 @@ export async function add(names: string[], { flags }: AddOptions) {
} }
} }
const updateTSConfigResult = await updateTSConfig(cwd, logging, integrations, flags); const updateTSConfigResult = await updateTSConfig(cwd, logger, integrations, flags);
switch (updateTSConfigResult) { switch (updateTSConfigResult) {
case UpdateResult.none: { case UpdateResult.none: {
break; break;
} }
case UpdateResult.cancelled: { case UpdateResult.cancelled: {
info( logger.info(
logging,
null, null,
msg.cancelled(`Your TypeScript configuration has ${bold('NOT')} been updated.`) msg.cancelled(`Your TypeScript configuration has ${bold('NOT')} been updated.`)
); );
@ -335,7 +332,7 @@ export async function add(names: string[], { flags }: AddOptions) {
); );
} }
default: default:
info(logging, null, msg.success(`Successfully updated TypeScript settings`)); logger.info(null, msg.success(`Successfully updated TypeScript settings`));
} }
} }
@ -529,13 +526,13 @@ async function updateAstroConfig({
configURL, configURL,
ast, ast,
flags, flags,
logging, logger,
logAdapterInstructions, logAdapterInstructions,
}: { }: {
configURL: URL; configURL: URL;
ast: t.File; ast: t.File;
flags: yargs.Arguments; flags: yargs.Arguments;
logging: LogOptions; logger: Logger;
logAdapterInstructions: boolean; logAdapterInstructions: boolean;
}): Promise<UpdateResult> { }): Promise<UpdateResult> {
const input = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' }); const input = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' });
@ -562,15 +559,13 @@ async function updateAstroConfig({
title: configURL.pathname.split('/').pop(), title: configURL.pathname.split('/').pop(),
})}\n`; })}\n`;
info( logger.info(
logging,
null, null,
`\n ${magenta('Astro will make the following changes to your config file:')}\n${message}` `\n ${magenta('Astro will make the following changes to your config file:')}\n${message}`
); );
if (logAdapterInstructions) { if (logAdapterInstructions) {
info( logger.info(
logging,
null, null,
magenta( magenta(
` For complete deployment options, visit\n ${bold( ` For complete deployment options, visit\n ${bold(
@ -582,7 +577,7 @@ async function updateAstroConfig({
if (await askToContinue({ flags })) { if (await askToContinue({ flags })) {
await fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' }); await fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' });
debug('add', `Updated astro config`); logger.debug('add', `Updated astro config`);
return UpdateResult.updated; return UpdateResult.updated;
} else { } else {
return UpdateResult.cancelled; return UpdateResult.cancelled;
@ -598,13 +593,15 @@ interface InstallCommand {
async function getInstallIntegrationsCommand({ async function getInstallIntegrationsCommand({
integrations, integrations,
logger,
cwd = process.cwd(), cwd = process.cwd(),
}: { }: {
integrations: IntegrationInfo[]; integrations: IntegrationInfo[];
logger: Logger;
cwd?: string; cwd?: string;
}): Promise<InstallCommand | null> { }): Promise<InstallCommand | null> {
const pm = await preferredPM(cwd); const pm = await preferredPM(cwd);
debug('add', `package manager: ${JSON.stringify(pm)}`); logger.debug('add', `package manager: ${JSON.stringify(pm)}`);
if (!pm) return null; if (!pm) return null;
let dependencies = integrations let dependencies = integrations
@ -644,14 +641,14 @@ async function tryToInstallIntegrations({
integrations, integrations,
cwd, cwd,
flags, flags,
logging, logger,
}: { }: {
integrations: IntegrationInfo[]; integrations: IntegrationInfo[];
cwd?: string; cwd?: string;
flags: yargs.Arguments; flags: yargs.Arguments;
logging: LogOptions; logger: Logger;
}): Promise<UpdateResult> { }): Promise<UpdateResult> {
const installCommand = await getInstallIntegrationsCommand({ integrations, cwd }); const installCommand = await getInstallIntegrationsCommand({ integrations, cwd, logger });
const inheritedFlags = Object.entries(flags) const inheritedFlags = Object.entries(flags)
.map(([flag]) => { .map(([flag]) => {
@ -677,8 +674,7 @@ async function tryToInstallIntegrations({
padding: 0.5, padding: 0.5,
borderStyle: 'round', borderStyle: 'round',
})}\n`; })}\n`;
info( logger.info(
logging,
null, null,
`\n ${magenta('Astro will run the following command:')}\n ${dim( `\n ${magenta('Astro will run the following command:')}\n ${dim(
'If you skip this step, you can always run it yourself later' 'If you skip this step, you can always run it yourself later'
@ -702,7 +698,7 @@ async function tryToInstallIntegrations({
return UpdateResult.updated; return UpdateResult.updated;
} catch (err) { } catch (err) {
spinner.fail(); spinner.fail();
debug('add', 'Error installing dependencies', err); logger.debug('add', 'Error installing dependencies', err);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('\n', (err as any).stdout, '\n'); console.error('\n', (err as any).stdout, '\n');
return UpdateResult.failure; return UpdateResult.failure;
@ -829,7 +825,7 @@ export async function validateIntegrations(integrations: string[]): Promise<Inte
async function updateTSConfig( async function updateTSConfig(
cwd = process.cwd(), cwd = process.cwd(),
logging: LogOptions, logger: Logger,
integrationsInfo: IntegrationInfo[], integrationsInfo: IntegrationInfo[],
flags: yargs.Arguments flags: yargs.Arguments
): Promise<UpdateResult> { ): Promise<UpdateResult> {
@ -852,7 +848,7 @@ async function updateTSConfig(
} }
if (inputConfig.reason === 'not-found') { if (inputConfig.reason === 'not-found') {
debug('add', "Couldn't find tsconfig.json or jsconfig.json, generating one"); logger.debug('add', "Couldn't find tsconfig.json or jsconfig.json, generating one");
} }
const outputConfig = updateTSConfigForFramework( const outputConfig = updateTSConfigForFramework(
@ -875,8 +871,7 @@ async function updateTSConfig(
title: configFileName, title: configFileName,
})}\n`; })}\n`;
info( logger.info(
logging,
null, null,
`\n ${magenta(`Astro will make the following changes to your ${configFileName}:`)}\n${message}` `\n ${magenta(`Astro will make the following changes to your ${configFileName}:`)}\n${message}`
); );
@ -890,8 +885,7 @@ async function updateTSConfig(
integrations.filter((integration) => conflictingIntegrations.includes(integration)).length > 0; integrations.filter((integration) => conflictingIntegrations.includes(integration)).length > 0;
if (hasConflictingIntegrations) { if (hasConflictingIntegrations) {
info( logger.info(
logging,
null, null,
red( red(
` ${bold( ` ${bold(
@ -907,7 +901,7 @@ async function updateTSConfig(
await fs.writeFile(inputConfig?.path ?? path.join(cwd, 'tsconfig.json'), output, { await fs.writeFile(inputConfig?.path ?? path.join(cwd, 'tsconfig.json'), output, {
encoding: 'utf-8', encoding: 'utf-8',
}); });
debug('add', `Updated ${configFileName} file`); logger.debug('add', `Updated ${configFileName} file`);
return UpdateResult.updated; return UpdateResult.updated;
} else { } else {
return UpdateResult.cancelled; return UpdateResult.cancelled;
@ -971,13 +965,14 @@ function getDiffContent(input: string, output: string): string | null {
async function setupIntegrationConfig(opts: { async function setupIntegrationConfig(opts: {
root: URL; root: URL;
logging: LogOptions; logger: Logger;
flags: yargs.Arguments; flags: yargs.Arguments;
integrationName: string; integrationName: string;
possibleConfigFiles: string[]; possibleConfigFiles: string[];
defaultConfigFile: string; defaultConfigFile: string;
defaultConfigContent: string; defaultConfigContent: string;
}) { }) {
const logger = opts.logger;
const possibleConfigFiles = opts.possibleConfigFiles.map((p) => const possibleConfigFiles = opts.possibleConfigFiles.map((p) =>
fileURLToPath(new URL(p, opts.root)) fileURLToPath(new URL(p, opts.root))
); );
@ -989,8 +984,7 @@ async function setupIntegrationConfig(opts: {
} }
} }
if (!alreadyConfigured) { if (!alreadyConfigured) {
info( logger.info(
opts.logging,
null, null,
`\n ${magenta(`Astro will generate a minimal ${bold(opts.defaultConfigFile)} file.`)}\n` `\n ${magenta(`Astro will generate a minimal ${bold(opts.defaultConfigFile)} file.`)}\n`
); );
@ -1002,9 +996,9 @@ async function setupIntegrationConfig(opts: {
encoding: 'utf-8', encoding: 'utf-8',
} }
); );
debug('add', `Generated default ${opts.defaultConfigFile} file`); logger.debug('add', `Generated default ${opts.defaultConfigFile} file`);
} }
} else { } else {
debug('add', `Using existing ${opts.integrationName} configuration`); logger.debug('add', `Using existing ${opts.integrationName} configuration`);
} }
} }

View file

@ -1,23 +1,21 @@
import path from 'node:path'; import path from 'node:path';
import type { Arguments } from 'yargs-parser'; import type { Arguments } from 'yargs-parser';
import { error, info } from '../../core/logger/core.js'; import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js';
import { createLoggingFromFlags, flagsToAstroInlineConfig } from '../flags.js';
import { getPackage } from '../install-package.js'; import { getPackage } from '../install-package.js';
export async function check(flags: Arguments) { export async function check(flags: Arguments) {
const logging = createLoggingFromFlags(flags); const logger = createLoggerFromFlags(flags);
const getPackageOpts = { skipAsk: flags.yes || flags.y, cwd: flags.root }; const getPackageOpts = { skipAsk: flags.yes || flags.y, cwd: flags.root };
const checkPackage = await getPackage<typeof import('@astrojs/check')>( const checkPackage = await getPackage<typeof import('@astrojs/check')>(
'@astrojs/check', '@astrojs/check',
logging, logger,
getPackageOpts, getPackageOpts,
['typescript'] ['typescript']
); );
const typescript = await getPackage('typescript', logging, getPackageOpts); const typescript = await getPackage('typescript', logger, getPackageOpts);
if (!checkPackage || !typescript) { if (!checkPackage || !typescript) {
error( logger.error(
logging,
'check', 'check',
'The `@astrojs/check` and `typescript` packages are required for this command to work. Please manually install them into your project and try again.' 'The `@astrojs/check` and `typescript` packages are required for this command to work. Please manually install them into your project and try again.'
); );
@ -38,6 +36,6 @@ export async function check(flags: Arguments) {
const config = parseArgsAsCheckConfig(process.argv); const config = parseArgsAsCheckConfig(process.argv);
info(logging, 'check', `Getting diagnostics for Astro files in ${path.resolve(config.root)}...`); logger.info('check', `Getting diagnostics for Astro files in ${path.resolve(config.root)}...`);
return await checker(config); return await checker(config);
} }

View file

@ -1,6 +1,6 @@
import type { Arguments as Flags } from 'yargs-parser'; import type { Arguments as Flags } from 'yargs-parser';
import type { AstroInlineConfig } from '../@types/astro.js'; import type { AstroInlineConfig } from '../@types/astro.js';
import type { LogOptions } from '../core/logger/core.js'; import { Logger, type LogOptions } from '../core/logger/core.js';
import { nodeLogDestination } from '../core/logger/node.js'; import { nodeLogDestination } from '../core/logger/node.js';
export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig { export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
@ -30,7 +30,7 @@ export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
* The `logging` is usually created from an `AstroInlineConfig`, but some flows like `add` * The `logging` is usually created from an `AstroInlineConfig`, but some flows like `add`
* doesn't read the AstroConfig directly, so we create a `logging` object from the CLI flags instead. * doesn't read the AstroConfig directly, so we create a `logging` object from the CLI flags instead.
*/ */
export function createLoggingFromFlags(flags: Flags): LogOptions { export function createLoggerFromFlags(flags: Flags): Logger {
const logging: LogOptions = { const logging: LogOptions = {
dest: nodeLogDestination, dest: nodeLogDestination,
level: 'info', level: 'info',
@ -42,5 +42,5 @@ export function createLoggingFromFlags(flags: Flags): LogOptions {
logging.level = 'silent'; logging.level = 'silent';
} }
return logging; return new Logger(logging);
} }

View file

@ -5,7 +5,7 @@ import { createRequire } from 'node:module';
import ora from 'ora'; import ora from 'ora';
import prompts from 'prompts'; import prompts from 'prompts';
import whichPm from 'which-pm'; import whichPm from 'which-pm';
import { debug, info, type LogOptions } from '../core/logger/core.js'; import { type Logger } from '../core/logger/core.js';
type GetPackageOptions = { type GetPackageOptions = {
skipAsk?: boolean; skipAsk?: boolean;
@ -14,7 +14,7 @@ type GetPackageOptions = {
export async function getPackage<T>( export async function getPackage<T>(
packageName: string, packageName: string,
logging: LogOptions, logger: Logger,
options: GetPackageOptions, options: GetPackageOptions,
otherDeps: string[] = [] otherDeps: string[] = []
): Promise<T | undefined> { ): Promise<T | undefined> {
@ -27,12 +27,11 @@ export async function getPackage<T>(
// The `require.resolve` is required as to avoid Node caching the failed `import` // The `require.resolve` is required as to avoid Node caching the failed `import`
packageImport = await import(packageName); packageImport = await import(packageName);
} catch (e) { } catch (e) {
info( logger.info(
logging,
'', '',
`To continue, Astro requires the following dependency to be installed: ${bold(packageName)}.` `To continue, Astro requires the following dependency to be installed: ${bold(packageName)}.`
); );
const result = await installPackage([packageName, ...otherDeps], options, logging); const result = await installPackage([packageName, ...otherDeps], options, logger);
if (result) { if (result) {
packageImport = await import(packageName); packageImport = await import(packageName);
@ -60,7 +59,7 @@ function getInstallCommand(packages: string[], packageManager: string) {
async function installPackage( async function installPackage(
packageNames: string[], packageNames: string[],
options: GetPackageOptions, options: GetPackageOptions,
logging: LogOptions logger: Logger
): Promise<boolean> { ): Promise<boolean> {
const cwd = options.cwd ?? process.cwd(); const cwd = options.cwd ?? process.cwd();
const packageManager = (await whichPm(cwd)).name ?? 'npm'; const packageManager = (await whichPm(cwd)).name ?? 'npm';
@ -79,8 +78,7 @@ async function installPackage(
padding: 0.5, padding: 0.5,
borderStyle: 'round', borderStyle: 'round',
})}\n`; })}\n`;
info( logger.info(
logging,
null, null,
`\n ${magenta('Astro will run the following command:')}\n ${dim( `\n ${magenta('Astro will run the following command:')}\n ${dim(
'If you skip this step, you can always run it yourself later' 'If you skip this step, you can always run it yourself later'
@ -113,7 +111,7 @@ async function installPackage(
return true; return true;
} catch (err) { } catch (err) {
debug('add', 'Error installing dependencies', err); logger.debug('add', 'Error installing dependencies', err);
spinner.fail(); spinner.fail();
return false; return false;

View file

@ -1,6 +1,6 @@
import type { UserConfig } from 'vite'; import type { UserConfig } from 'vite';
import type { AstroUserConfig } from '../@types/astro'; import type { AstroUserConfig } from '../@types/astro';
import type { LogOptions } from '../core/logger/core'; import { Logger } from '../core/logger/core';
export function defineConfig(config: AstroUserConfig) { export function defineConfig(config: AstroUserConfig) {
return config; return config;
@ -30,24 +30,24 @@ export function getViteConfig(inlineConfig: UserConfig) {
import('../integrations/index.js'), import('../integrations/index.js'),
import('./vite-plugin-content-listen.js'), import('./vite-plugin-content-listen.js'),
]); ]);
const logging: LogOptions = { const logger = new Logger({
dest: nodeLogDestination, dest: nodeLogDestination,
level: 'info', level: 'info',
}; });
const { astroConfig: config } = await resolveConfig({}, cmd); const { astroConfig: config } = await resolveConfig({}, cmd);
const settings = createSettings(config, inlineConfig.root); const settings = createSettings(config, inlineConfig.root);
await runHookConfigSetup({ settings, command: cmd, logging }); await runHookConfigSetup({ settings, command: cmd, logger });
const viteConfig = await createVite( const viteConfig = await createVite(
{ {
mode, mode,
plugins: [ plugins: [
// Initialize the content listener // Initialize the content listener
astroContentListenPlugin({ settings, logging, fs }), astroContentListenPlugin({ settings, logger, fs }),
], ],
}, },
{ settings, logging: logging, mode } { settings, logger, mode }
); );
await runHookConfigDone({ settings, logging }); await runHookConfigDone({ settings, logger });
return mergeConfig(viteConfig, inlineConfig); return mergeConfig(viteConfig, inlineConfig);
}; };
} }

View file

@ -2,7 +2,7 @@ import type fsMod from 'node:fs';
import type { Plugin, ViteDevServer } from 'vite'; import type { Plugin, ViteDevServer } from 'vite';
import type { AstroSettings } from '../@types/astro'; import type { AstroSettings } from '../@types/astro';
import { attachContentServerListeners } from '../content/server-listeners.js'; import { attachContentServerListeners } from '../content/server-listeners.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
/** /**
* Listen for Astro content directory changes and generate types. * Listen for Astro content directory changes and generate types.
@ -14,11 +14,11 @@ import type { LogOptions } from '../core/logger/core.js';
*/ */
export function astroContentListenPlugin({ export function astroContentListenPlugin({
settings, settings,
logging, logger,
fs, fs,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
fs: typeof fsMod; fs: typeof fsMod;
}): Plugin { }): Plugin {
let server: ViteDevServer; let server: ViteDevServer;
@ -33,7 +33,7 @@ export function astroContentListenPlugin({
await attachContentServerListeners({ await attachContentServerListeners({
fs: fs, fs: fs,
settings, settings,
logging, logger,
viteServer: server, viteServer: server,
}); });
}, },

View file

@ -5,14 +5,14 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import type { ViteDevServer } from 'vite'; import type { ViteDevServer } from 'vite';
import type { AstroSettings } from '../@types/astro.js'; import type { AstroSettings } from '../@types/astro.js';
import { loadTSConfig } from '../core/config/tsconfig.js'; import { loadTSConfig } from '../core/config/tsconfig.js';
import { info, warn, type LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { appendForwardSlash } from '../core/path.js'; import { appendForwardSlash } from '../core/path.js';
import { createContentTypesGenerator } from './types-generator.js'; import { createContentTypesGenerator } from './types-generator.js';
import { getContentPaths, globalContentConfigObserver, type ContentPaths } from './utils.js'; import { getContentPaths, globalContentConfigObserver, type ContentPaths } from './utils.js';
interface ContentServerListenerParams { interface ContentServerListenerParams {
fs: typeof fsMod; fs: typeof fsMod;
logging: LogOptions; logger: Logger;
settings: AstroSettings; settings: AstroSettings;
viteServer: ViteDevServer; viteServer: ViteDevServer;
} }
@ -20,27 +20,26 @@ interface ContentServerListenerParams {
export async function attachContentServerListeners({ export async function attachContentServerListeners({
viteServer, viteServer,
fs, fs,
logging, logger,
settings, settings,
}: ContentServerListenerParams) { }: ContentServerListenerParams) {
const contentPaths = getContentPaths(settings.config, fs); const contentPaths = getContentPaths(settings.config, fs);
if (fs.existsSync(contentPaths.contentDir)) { if (fs.existsSync(contentPaths.contentDir)) {
info( logger.info(
logging,
'content', 'content',
`Watching ${cyan( `Watching ${cyan(
contentPaths.contentDir.href.replace(settings.config.root.href, '') contentPaths.contentDir.href.replace(settings.config.root.href, '')
)} for changes` )} for changes`
); );
const maybeTsConfigStats = getTSConfigStatsWhenAllowJsFalse({ contentPaths, settings }); const maybeTsConfigStats = getTSConfigStatsWhenAllowJsFalse({ contentPaths, settings });
if (maybeTsConfigStats) warnAllowJsIsFalse({ ...maybeTsConfigStats, logging }); if (maybeTsConfigStats) warnAllowJsIsFalse({ ...maybeTsConfigStats, logger });
await attachListeners(); await attachListeners();
} else { } else {
viteServer.watcher.on('addDir', contentDirListener); viteServer.watcher.on('addDir', contentDirListener);
async function contentDirListener(dir: string) { async function contentDirListener(dir: string) {
if (appendForwardSlash(pathToFileURL(dir).href) === contentPaths.contentDir.href) { if (appendForwardSlash(pathToFileURL(dir).href) === contentPaths.contentDir.href) {
info(logging, 'content', `Content dir found. Watching for changes`); logger.info('content', `Content dir found. Watching for changes`);
await attachListeners(); await attachListeners();
viteServer.watcher.removeListener('addDir', contentDirListener); viteServer.watcher.removeListener('addDir', contentDirListener);
} }
@ -51,12 +50,12 @@ export async function attachContentServerListeners({
const contentGenerator = await createContentTypesGenerator({ const contentGenerator = await createContentTypesGenerator({
fs, fs,
settings, settings,
logging, logger,
viteServer, viteServer,
contentConfigObserver: globalContentConfigObserver, contentConfigObserver: globalContentConfigObserver,
}); });
await contentGenerator.init(); await contentGenerator.init();
info(logging, 'content', 'Types generated'); logger.info('content', 'Types generated');
viteServer.watcher.on('add', (entry) => { viteServer.watcher.on('add', (entry) => {
contentGenerator.queueEvent({ name: 'add', entry }); contentGenerator.queueEvent({ name: 'add', entry });
@ -77,17 +76,15 @@ export async function attachContentServerListeners({
} }
function warnAllowJsIsFalse({ function warnAllowJsIsFalse({
logging, logger,
tsConfigFileName, tsConfigFileName,
contentConfigFileName, contentConfigFileName,
}: { }: {
logging: LogOptions; logger: Logger;
tsConfigFileName: string; tsConfigFileName: string;
contentConfigFileName: string; contentConfigFileName: string;
}) { }) {
if (!['info', 'warn'].includes(logging.level)) logger.warn(
warn(
logging,
'content', 'content',
`Make sure you have the ${bold('allowJs')} compiler option set to ${bold( `Make sure you have the ${bold('allowJs')} compiler option set to ${bold(
'true' 'true'

View file

@ -7,7 +7,6 @@ import { normalizePath, type ViteDevServer } from 'vite';
import type { AstroSettings, ContentEntryType } from '../@types/astro.js'; import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
import { AstroError } from '../core/errors/errors.js'; import { AstroError } from '../core/errors/errors.js';
import { AstroErrorData } from '../core/errors/index.js'; import { AstroErrorData } from '../core/errors/index.js';
import { info, warn, type LogOptions } from '../core/logger/core.js';
import { isRelativePath } from '../core/path.js'; import { isRelativePath } from '../core/path.js';
import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js'; import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js';
import { import {
@ -24,6 +23,7 @@ import {
type ContentObservable, type ContentObservable,
type ContentPaths, type ContentPaths,
} from './utils.js'; } from './utils.js';
import type { Logger } from '../core/logger/core';
type ChokidarEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'; type ChokidarEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir';
type RawContentEvent = { name: ChokidarEvent; entry: string }; type RawContentEvent = { name: ChokidarEvent; entry: string };
@ -49,7 +49,7 @@ type CollectionEntryMap = {
type CreateContentGeneratorParams = { type CreateContentGeneratorParams = {
contentConfigObserver: ContentObservable; contentConfigObserver: ContentObservable;
logging: LogOptions; logger: Logger;
settings: AstroSettings; settings: AstroSettings;
/** This is required for loading the content config */ /** This is required for loading the content config */
viteServer: ViteDevServer; viteServer: ViteDevServer;
@ -68,7 +68,7 @@ class UnsupportedFileTypeError extends Error {}
export async function createContentTypesGenerator({ export async function createContentTypesGenerator({
contentConfigObserver, contentConfigObserver,
fs, fs,
logging, logger,
settings, settings,
viteServer, viteServer,
}: CreateContentGeneratorParams) { }: CreateContentGeneratorParams) {
@ -140,7 +140,7 @@ export async function createContentTypesGenerator({
case 'addDir': case 'addDir':
collectionEntryMap[JSON.stringify(collection)] = { type: 'unknown', entries: {} }; collectionEntryMap[JSON.stringify(collection)] = { type: 'unknown', entries: {} };
if (logLevel === 'info') { if (logLevel === 'info') {
info(logging, 'content', `${cyan(collection)} collection added`); logger.info('content', `${cyan(collection)} collection added`);
} }
break; break;
case 'unlinkDir': case 'unlinkDir':
@ -186,8 +186,7 @@ export async function createContentTypesGenerator({
const collection = getEntryCollectionName({ entry, contentDir }); const collection = getEntryCollectionName({ entry, contentDir });
if (collection === undefined) { if (collection === undefined) {
if (['info', 'warn'].includes(logLevel)) { if (['info', 'warn'].includes(logLevel)) {
warn( logger.warn(
logging,
'content', 'content',
`${cyan( `${cyan(
normalizePath( normalizePath(
@ -350,8 +349,7 @@ export async function createContentTypesGenerator({
} }
} }
if (unsupportedFiles.length > 0 && ['info', 'warn'].includes(logLevel)) { if (unsupportedFiles.length > 0 && ['info', 'warn'].includes(logLevel)) {
warn( logger.warn(
logging,
'content', 'content',
`Unsupported file types found. Prefix with an underscore (\`_\`) to ignore:\n- ${unsupportedFiles.join( `Unsupported file types found. Prefix with an underscore (\`_\`) to ignore:\n- ${unsupportedFiles.join(
'\n' '\n'
@ -372,7 +370,7 @@ export async function createContentTypesGenerator({
invalidateVirtualMod(viteServer); invalidateVirtualMod(viteServer);
if (observable.status === 'loaded' && ['info', 'warn'].includes(logLevel)) { if (observable.status === 'loaded' && ['info', 'warn'].includes(logLevel)) {
warnNonexistentCollections({ warnNonexistentCollections({
logging, logger,
contentConfig: observable.config, contentConfig: observable.config,
collectionEntryMap, collectionEntryMap,
}); });
@ -505,16 +503,15 @@ async function writeContentFiles({
function warnNonexistentCollections({ function warnNonexistentCollections({
contentConfig, contentConfig,
collectionEntryMap, collectionEntryMap,
logging, logger,
}: { }: {
contentConfig: ContentConfig; contentConfig: ContentConfig;
collectionEntryMap: CollectionEntryMap; collectionEntryMap: CollectionEntryMap;
logging: LogOptions; logger: Logger;
}) { }) {
for (const configuredCollection in contentConfig.collections) { for (const configuredCollection in contentConfig.collections) {
if (!collectionEntryMap[JSON.stringify(configuredCollection)]) { if (!collectionEntryMap[JSON.stringify(configuredCollection)]) {
warn( logger.warn(
logging,
'content', 'content',
`The ${JSON.stringify( `The ${JSON.stringify(
configuredCollection configuredCollection

View file

@ -9,7 +9,7 @@ import type {
import type { SinglePageBuiltModule } from '../build/types'; import type { SinglePageBuiltModule } from '../build/types';
import { getSetCookiesFromResponse } from '../cookies/index.js'; import { getSetCookiesFromResponse } from '../cookies/index.js';
import { consoleLogDestination } from '../logger/console.js'; import { consoleLogDestination } from '../logger/console.js';
import { error, warn, type LogOptions } from '../logger/core.js'; import { Logger } from '../logger/core.js';
import { import {
collapseDuplicateSlashes, collapseDuplicateSlashes,
prependForwardSlash, prependForwardSlash,
@ -50,10 +50,10 @@ export class App {
#manifest: SSRManifest; #manifest: SSRManifest;
#manifestData: ManifestData; #manifestData: ManifestData;
#routeDataToRouteInfo: Map<RouteData, RouteInfo>; #routeDataToRouteInfo: Map<RouteData, RouteInfo>;
#logging: LogOptions = { #logger = new Logger({
dest: consoleLogDestination, dest: consoleLogDestination,
level: 'info', level: 'info',
}; });
#baseWithoutTrailingSlash: string; #baseWithoutTrailingSlash: string;
#pipeline: SSRRoutePipeline; #pipeline: SSRRoutePipeline;
#onRequest: MiddlewareEndpointHandler | undefined; #onRequest: MiddlewareEndpointHandler | undefined;
@ -83,7 +83,7 @@ export class App {
#createEnvironment(streaming = false) { #createEnvironment(streaming = false) {
return createEnvironment({ return createEnvironment({
adapterName: this.#manifest.adapterName, adapterName: this.#manifest.adapterName,
logging: this.#logging, logger: this.#logger,
mode: 'production', mode: 'production',
compressHTML: this.#manifest.compressHTML, compressHTML: this.#manifest.compressHTML,
renderers: this.#manifest.renderers, renderers: this.#manifest.renderers,
@ -103,7 +103,7 @@ export class App {
} }
} }
}, },
routeCache: new RouteCache(this.#logging), routeCache: new RouteCache(this.#logger),
site: this.#manifest.site, site: this.#manifest.site,
ssr: true, ssr: true,
streaming, streaming,
@ -138,7 +138,7 @@ export class App {
const middleware = await import(this.#manifest.middlewareEntryPoint); const middleware = await import(this.#manifest.middlewareEntryPoint);
this.#pipeline.setMiddlewareFunction(middleware.onRequest as MiddlewareEndpointHandler); this.#pipeline.setMiddlewareFunction(middleware.onRequest as MiddlewareEndpointHandler);
} catch (e) { } catch (e) {
warn(this.#logging, 'SSR', "Couldn't load the middleware entry point"); this.#logger.warn('SSR', "Couldn't load the middleware entry point");
} }
} }
this.#middlewareLoaded = true; this.#middlewareLoaded = true;
@ -178,7 +178,7 @@ export class App {
if (err instanceof EndpointNotFoundError) { if (err instanceof EndpointNotFoundError) {
return this.#renderError(request, { status: 404, response: err.originalResponse }); return this.#renderError(request, { status: 404, response: err.originalResponse });
} else { } else {
error(this.#logging, 'ssr', err.stack || err.message || String(err)); this.#logger.error('ssr', err.stack || err.message || String(err));
return this.#renderError(request, { status: 500 }); return this.#renderError(request, { status: 500 });
} }
} }

View file

@ -10,6 +10,7 @@ import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js';
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js'; import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js'; import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
import type { PageBuildData, StaticBuildOptions } from './types'; import type { PageBuildData, StaticBuildOptions } from './types';
import { Logger } from '../logger/core.js';
/** /**
* This pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files. * This pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files.
@ -28,7 +29,7 @@ export class BuildPipeline extends Pipeline {
super( super(
createEnvironment({ createEnvironment({
adapterName: manifest.adapterName, adapterName: manifest.adapterName,
logging: staticBuildOptions.logging, logger: staticBuildOptions.logger,
mode: staticBuildOptions.mode, mode: staticBuildOptions.mode,
renderers: manifest.renderers, renderers: manifest.renderers,
clientDirectives: manifest.clientDirectives, clientDirectives: manifest.clientDirectives,
@ -84,6 +85,10 @@ export class BuildPipeline extends Pipeline {
} }
} }
getLogger(): Logger {
return this.getEnvironment().logger;
}
/** /**
* The SSR build emits two important files: * The SSR build emits two important files:
* - dist/server/manifest.mjs * - dist/server/manifest.mjs

View file

@ -32,7 +32,6 @@ import { runHookBuildGenerated } from '../../integrations/index.js';
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { Logger, debug, info } from '../logger/core.js';
import { RedirectSinglePageBuiltModule, getRedirectLocationOrThrow } from '../redirects/index.js'; import { RedirectSinglePageBuiltModule, getRedirectLocationOrThrow } from '../redirects/index.js';
import { createRenderContext } from '../render/index.js'; import { createRenderContext } from '../render/index.js';
import { callGetStaticPaths } from '../render/route-cache.js'; import { callGetStaticPaths } from '../render/route-cache.js';
@ -120,7 +119,6 @@ export function chunkIsPage(
} }
export async function generatePages(opts: StaticBuildOptions, internals: BuildInternals) { export async function generatePages(opts: StaticBuildOptions, internals: BuildInternals) {
const logger = new Logger(opts.logging);
const timer = performance.now(); const timer = performance.now();
const ssr = isServerLikeOutput(opts.settings.config); const ssr = isServerLikeOutput(opts.settings.config);
let manifest: SSRManifest; let manifest: SSRManifest;
@ -136,12 +134,13 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
renderers.renderers as SSRLoadedRenderer[] renderers.renderers as SSRLoadedRenderer[]
); );
} }
const buildPipeline = new BuildPipeline(opts, internals, manifest); const pipeline = new BuildPipeline(opts, internals, manifest);
await buildPipeline.retrieveMiddlewareFunction(); await pipeline.retrieveMiddlewareFunction();
const outFolder = ssr const outFolder = ssr
? opts.settings.config.build.server ? opts.settings.config.build.server
: getOutDirWithinCwd(opts.settings.config.outDir); : getOutDirWithinCwd(opts.settings.config.outDir);
const logger = pipeline.getLogger();
// HACK! `astro:assets` relies on a global to know if its running in dev, prod, ssr, ssg, full moon // HACK! `astro:assets` relies on a global to know if its running in dev, prod, ssr, ssg, full moon
// If we don't delete it here, it's technically not impossible (albeit improbable) for it to leak // If we don't delete it here, it's technically not impossible (albeit improbable) for it to leak
if (ssr && !hasPrerenderedPages(internals)) { if (ssr && !hasPrerenderedPages(internals)) {
@ -150,9 +149,9 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
} }
const verb = ssr ? 'prerendering' : 'generating'; const verb = ssr ? 'prerendering' : 'generating';
info(opts.logging, null, `\n${bgGreen(black(` ${verb} static routes `))}`); logger.info(null, `\n${bgGreen(black(` ${verb} static routes `))}`);
const builtPaths = new Set<string>(); const builtPaths = new Set<string>();
const pagesToGenerate = buildPipeline.retrieveRoutesToGenerate(); const pagesToGenerate = pipeline.retrieveRoutesToGenerate();
if (ssr) { if (ssr) {
for (const [pageData, filePath] of pagesToGenerate) { for (const [pageData, filePath] of pagesToGenerate) {
if (pageData.route.prerender) { if (pageData.route.prerender) {
@ -166,7 +165,7 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
// forcing to use undefined, so we fail in an expected way if the module is not even there. // forcing to use undefined, so we fail in an expected way if the module is not even there.
const ssrEntry = ssrEntryPage?.manifest?.pageModule; const ssrEntry = ssrEntryPage?.manifest?.pageModule;
if (ssrEntry) { if (ssrEntry) {
await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger); await generatePage(pageData, ssrEntry, builtPaths, pipeline);
} else { } else {
throw new Error( throw new Error(
`Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.` `Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.`
@ -174,46 +173,47 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
} }
} else { } else {
const ssrEntry = ssrEntryPage as SinglePageBuiltModule; const ssrEntry = ssrEntryPage as SinglePageBuiltModule;
await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger); await generatePage(pageData, ssrEntry, builtPaths, pipeline);
} }
} }
if (pageData.route.type === 'redirect') { if (pageData.route.type === 'redirect') {
const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder); const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
await generatePage(pageData, entry, builtPaths, buildPipeline, logger); await generatePage(pageData, entry, builtPaths, pipeline);
} }
} }
} else { } else {
for (const [pageData, filePath] of pagesToGenerate) { for (const [pageData, filePath] of pagesToGenerate) {
if (pageData.route.type === 'redirect') { if (pageData.route.type === 'redirect') {
const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder); const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
await generatePage(pageData, entry, builtPaths, buildPipeline, logger); await generatePage(pageData, entry, builtPaths, pipeline);
} else { } else {
const ssrEntryURLPage = createEntryURL(filePath, outFolder); const ssrEntryURLPage = createEntryURL(filePath, outFolder);
const entry: SinglePageBuiltModule = await import(ssrEntryURLPage.toString()); const entry: SinglePageBuiltModule = await import(ssrEntryURLPage.toString());
await generatePage(pageData, entry, builtPaths, buildPipeline, logger); await generatePage(pageData, entry, builtPaths, pipeline);
} }
} }
} }
info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`); logger.info(null, `\n${bgGreen(black(` generating optimized images `))}`);
for (const imageData of getStaticImageList()) { for (const imageData of getStaticImageList()) {
await generateImage(opts, imageData[1].options, imageData[1].path); await generateImage(pipeline, imageData[1].options, imageData[1].path);
} }
delete globalThis?.astroAsset?.addStaticImage; delete globalThis?.astroAsset?.addStaticImage;
await runHookBuildGenerated({ await runHookBuildGenerated({
config: opts.settings.config, config: opts.settings.config,
logging: opts.logging, logger: pipeline.getLogger(),
}); });
info(opts.logging, null, dim(`Completed in ${getTimeStat(timer, performance.now())}.\n`)); logger.info(null, dim(`Completed in ${getTimeStat(timer, performance.now())}.\n`));
} }
async function generateImage(opts: StaticBuildOptions, transform: ImageTransform, path: string) { async function generateImage(pipeline: BuildPipeline, transform: ImageTransform, path: string) {
const logger = pipeline.getLogger();
let timeStart = performance.now(); let timeStart = performance.now();
const generationData = await generateImageInternal(opts, transform, path); const generationData = await generateImageInternal(pipeline, transform, path);
if (!generationData) { if (!generationData) {
return; return;
@ -225,18 +225,17 @@ async function generateImage(opts: StaticBuildOptions, transform: ImageTransform
const statsText = generationData.cached const statsText = generationData.cached
? `(reused cache entry)` ? `(reused cache entry)`
: `(before: ${generationData.weight.before}kb, after: ${generationData.weight.after}kb)`; : `(before: ${generationData.weight.before}kb, after: ${generationData.weight.after}kb)`;
info(opts.logging, null, ` ${green('▶')} ${path} ${dim(statsText)} ${dim(timeIncrease)}`); logger.info(null, ` ${green('▶')} ${path} ${dim(statsText)} ${dim(timeIncrease)}`);
} }
async function generatePage( async function generatePage(
pageData: PageBuildData, pageData: PageBuildData,
ssrEntry: SinglePageBuiltModule, ssrEntry: SinglePageBuiltModule,
builtPaths: Set<string>, builtPaths: Set<string>,
pipeline: BuildPipeline, pipeline: BuildPipeline
logger: Logger
) { ) {
let timeStart = performance.now(); let timeStart = performance.now();
const logger = pipeline.getLogger();
const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component); const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component);
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc. // may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
@ -281,12 +280,7 @@ async function generatePage(
} }
// Get paths for the route, calling getStaticPaths if needed. // Get paths for the route, calling getStaticPaths if needed.
const paths = await getPathsForRoute( const paths = await getPathsForRoute(pageData, pageModule, pipeline, builtPaths);
pageData,
pageModule,
pipeline.getStaticBuildOptions(),
builtPaths
);
let prevTimeEnd = timeStart; let prevTimeEnd = timeStart;
for (let i = 0; i < paths.length; i++) { for (let i = 0; i < paths.length; i++) {
@ -305,9 +299,11 @@ async function generatePage(
async function getPathsForRoute( async function getPathsForRoute(
pageData: PageBuildData, pageData: PageBuildData,
mod: ComponentInstance, mod: ComponentInstance,
opts: StaticBuildOptions, pipeline: BuildPipeline,
builtPaths: Set<string> builtPaths: Set<string>
): Promise<Array<string>> { ): Promise<Array<string>> {
const opts = pipeline.getStaticBuildOptions();
const logger = pipeline.getLogger();
let paths: Array<string> = []; let paths: Array<string> = [];
if (pageData.route.pathname) { if (pageData.route.pathname) {
paths.push(pageData.route.pathname); paths.push(pageData.route.pathname);
@ -318,15 +314,15 @@ async function getPathsForRoute(
mod, mod,
route, route,
routeCache: opts.routeCache, routeCache: opts.routeCache,
logging: opts.logging, logger,
ssr: isServerLikeOutput(opts.settings.config), ssr: isServerLikeOutput(opts.settings.config),
}).catch((err) => { }).catch((err) => {
debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`); logger.debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`);
throw err; throw err;
}); });
const label = staticPaths.length === 1 ? 'page' : 'pages'; const label = staticPaths.length === 1 ? 'page' : 'pages';
debug( logger.debug(
'build', 'build',
`├── ${colors.bold(colors.green('✔'))} ${route.component}${colors.magenta( `├── ${colors.bold(colors.green('✔'))} ${route.component}${colors.magenta(
`[${staticPaths.length} ${label}]` `[${staticPaths.length} ${label}]`
@ -473,7 +469,7 @@ async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeli
addPageName(pathname, pipeline.getStaticBuildOptions()); addPageName(pathname, pipeline.getStaticBuildOptions());
} }
debug('build', `Generating: ${pathname}`); pipeline.getEnvironment().logger.debug('build', `Generating: ${pathname}`);
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc. // may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
const links = new Set<never>(); const links = new Set<never>();
@ -520,7 +516,7 @@ async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeli
request: createRequest({ request: createRequest({
url, url,
headers: new Headers(), headers: new Headers(),
logging: pipeline.getStaticBuildOptions().logging, logger: pipeline.getLogger(),
ssr, ssr,
}), }),
componentMetadata: manifest.componentMetadata, componentMetadata: manifest.componentMetadata,

View file

@ -21,10 +21,10 @@ import {
} from '../../integrations/index.js'; } from '../../integrations/index.js';
import { isServerLikeOutput } from '../../prerender/utils.js'; import { isServerLikeOutput } from '../../prerender/utils.js';
import { resolveConfig } from '../config/config.js'; import { resolveConfig } from '../config/config.js';
import { createNodeLogging } from '../config/logging.js'; import { createNodeLogger } from '../config/logging.js';
import { createSettings } from '../config/settings.js'; import { createSettings } from '../config/settings.js';
import { createVite } from '../create-vite.js'; import { createVite } from '../create-vite.js';
import { debug, info, levels, timerMessage, warn, type LogOptions } from '../logger/core.js'; import { levels, timerMessage, Logger } from '../logger/core.js';
import { apply as applyPolyfill } from '../polyfill.js'; import { apply as applyPolyfill } from '../polyfill.js';
import { RouteCache } from '../render/route-cache.js'; import { RouteCache } from '../render/route-cache.js';
import { createRouteManifest } from '../routing/index.js'; import { createRouteManifest } from '../routing/index.js';
@ -55,7 +55,7 @@ export default async function build(
options?: BuildOptions options?: BuildOptions
): Promise<void> { ): Promise<void> {
applyPolyfill(); applyPolyfill();
const logging = createNodeLogging(inlineConfig); const logger = createNodeLogger(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'build'); const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'build');
telemetry.record(eventCliSession('build', userConfig)); telemetry.record(eventCliSession('build', userConfig));
@ -63,20 +63,20 @@ export default async function build(
const builder = new AstroBuilder(settings, { const builder = new AstroBuilder(settings, {
...options, ...options,
logging, logger,
mode: inlineConfig.mode, mode: inlineConfig.mode,
}); });
await builder.run(); await builder.run();
} }
interface AstroBuilderOptions extends BuildOptions { interface AstroBuilderOptions extends BuildOptions {
logging: LogOptions; logger: Logger;
mode?: RuntimeMode; mode?: RuntimeMode;
} }
class AstroBuilder { class AstroBuilder {
private settings: AstroSettings; private settings: AstroSettings;
private logging: LogOptions; private logger: Logger;
private mode: RuntimeMode = 'production'; private mode: RuntimeMode = 'production';
private origin: string; private origin: string;
private routeCache: RouteCache; private routeCache: RouteCache;
@ -89,9 +89,9 @@ class AstroBuilder {
this.mode = options.mode; this.mode = options.mode;
} }
this.settings = settings; this.settings = settings;
this.logging = options.logging; this.logger = options.logger;
this.teardownCompiler = options.teardownCompiler ?? true; this.teardownCompiler = options.teardownCompiler ?? true;
this.routeCache = new RouteCache(this.logging); this.routeCache = new RouteCache(this.logger);
this.origin = settings.config.site this.origin = settings.config.site
? new URL(settings.config.site).origin ? new URL(settings.config.site).origin
: `http://localhost:${settings.config.server.port}`; : `http://localhost:${settings.config.server.port}`;
@ -101,20 +101,20 @@ class AstroBuilder {
/** Setup Vite and run any async setup logic that couldn't run inside of the constructor. */ /** Setup Vite and run any async setup logic that couldn't run inside of the constructor. */
private async setup() { private async setup() {
debug('build', 'Initial setup...'); this.logger.debug('build', 'Initial setup...');
const { logging } = this; const { logger } = this;
this.timer.init = performance.now(); this.timer.init = performance.now();
this.settings = await runHookConfigSetup({ this.settings = await runHookConfigSetup({
settings: this.settings, settings: this.settings,
command: 'build', command: 'build',
logging, logger: logger,
}); });
if (isServerLikeOutput(this.settings.config)) { if (isServerLikeOutput(this.settings.config)) {
this.settings = injectImageEndpoint(this.settings); this.settings = injectImageEndpoint(this.settings);
} }
this.manifest = createRouteManifest({ settings: this.settings }, this.logging); this.manifest = createRouteManifest({ settings: this.settings }, this.logger);
const viteConfig = await createVite( const viteConfig = await createVite(
{ {
@ -124,12 +124,12 @@ class AstroBuilder {
middlewareMode: true, middlewareMode: true,
}, },
}, },
{ settings: this.settings, logging, mode: 'build', command: 'build' } { settings: this.settings, logger: this.logger, mode: 'build', command: 'build' }
); );
await runHookConfigDone({ settings: this.settings, logging }); await runHookConfigDone({ settings: this.settings, logger: logger });
const { syncInternal } = await import('../sync/index.js'); const { syncInternal } = await import('../sync/index.js');
const syncRet = await syncInternal(this.settings, { logging, fs }); const syncRet = await syncInternal(this.settings, { logger: logger, fs });
if (syncRet !== 0) { if (syncRet !== 0) {
return process.exit(syncRet); return process.exit(syncRet);
} }
@ -139,22 +139,22 @@ class AstroBuilder {
/** Run the build logic. build() is marked private because usage should go through ".run()" */ /** Run the build logic. build() is marked private because usage should go through ".run()" */
private async build({ viteConfig }: { viteConfig: vite.InlineConfig }) { private async build({ viteConfig }: { viteConfig: vite.InlineConfig }) {
await runHookBuildStart({ config: this.settings.config, logging: this.logging }); await runHookBuildStart({ config: this.settings.config, logging: this.logger });
this.validateConfig(); this.validateConfig();
info(this.logging, 'build', `output target: ${colors.green(this.settings.config.output)}`); this.logger.info('build', `output target: ${colors.green(this.settings.config.output)}`);
if (this.settings.adapter) { if (this.settings.adapter) {
info(this.logging, 'build', `deploy adapter: ${colors.green(this.settings.adapter.name)}`); this.logger.info('build', `deploy adapter: ${colors.green(this.settings.adapter.name)}`);
} }
info(this.logging, 'build', 'Collecting build info...'); this.logger.info('build', 'Collecting build info...');
this.timer.loadStart = performance.now(); this.timer.loadStart = performance.now();
const { assets, allPages } = await collectPagesData({ const { assets, allPages } = await collectPagesData({
settings: this.settings, settings: this.settings,
logging: this.logging, logger: this.logger,
manifest: this.manifest, manifest: this.manifest,
}); });
debug('build', timerMessage('All pages loaded', this.timer.loadStart)); this.logger.debug('build', timerMessage('All pages loaded', this.timer.loadStart));
// The names of each pages // The names of each pages
const pageNames: string[] = []; const pageNames: string[] = [];
@ -162,8 +162,7 @@ class AstroBuilder {
// Bundle the assets in your final build: This currently takes the HTML output // Bundle the assets in your final build: This currently takes the HTML output
// of every page (stored in memory) and bundles the assets pointed to on those pages. // of every page (stored in memory) and bundles the assets pointed to on those pages.
this.timer.buildStart = performance.now(); this.timer.buildStart = performance.now();
info( this.logger.info(
this.logging,
'build', 'build',
colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`) colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`)
); );
@ -171,7 +170,7 @@ class AstroBuilder {
const opts: StaticBuildOptions = { const opts: StaticBuildOptions = {
allPages, allPages,
settings: this.settings, settings: this.settings,
logging: this.logging, logger: this.logger,
manifest: this.manifest, manifest: this.manifest,
mode: this.mode, mode: this.mode,
origin: this.origin, origin: this.origin,
@ -193,19 +192,19 @@ class AstroBuilder {
fs.writeFileSync(filePath, assets[k], 'utf8'); fs.writeFileSync(filePath, assets[k], 'utf8');
delete assets[k]; // free up memory delete assets[k]; // free up memory
}); });
debug('build', timerMessage('Additional assets copied', this.timer.assetsStart)); this.logger.debug('build', timerMessage('Additional assets copied', this.timer.assetsStart));
// You're done! Time to clean up. // You're done! Time to clean up.
await runHookBuildDone({ await runHookBuildDone({
config: this.settings.config, config: this.settings.config,
pages: pageNames, pages: pageNames,
routes: Object.values(allPages).map((pd) => pd.route), routes: Object.values(allPages).map((pd) => pd.route),
logging: this.logging, logging: this.logger,
}); });
if (this.logging.level && levels[this.logging.level] <= levels['info']) { if (this.logger.level && levels[this.logger.level()] <= levels['info']) {
await this.printStats({ await this.printStats({
logging: this.logging, logger: this.logger,
timeStart: this.timer.init, timeStart: this.timer.init,
pageCount: pageNames.length, pageCount: pageNames.length,
buildMode: this.settings.config.output, buildMode: this.settings.config.output,
@ -238,8 +237,7 @@ class AstroBuilder {
if (config.build.split === true) { if (config.build.split === true) {
if (config.output === 'static') { if (config.output === 'static') {
warn( this.logger.warn(
this.logging,
'configuration', 'configuration',
'The option `build.split` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.' 'The option `build.split` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.'
); );
@ -247,8 +245,7 @@ class AstroBuilder {
} }
if (config.build.excludeMiddleware === true) { if (config.build.excludeMiddleware === true) {
if (config.output === 'static') { if (config.output === 'static') {
warn( this.logger.warn(
this.logging,
'configuration', 'configuration',
'The option `build.excludeMiddleware` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.' 'The option `build.excludeMiddleware` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.'
); );
@ -266,12 +263,12 @@ class AstroBuilder {
/** Stats */ /** Stats */
private async printStats({ private async printStats({
logging, logger,
timeStart, timeStart,
pageCount, pageCount,
buildMode, buildMode,
}: { }: {
logging: LogOptions; logger: Logger;
timeStart: number; timeStart: number;
pageCount: number; pageCount: number;
buildMode: AstroConfig['output']; buildMode: AstroConfig['output'];
@ -285,7 +282,7 @@ class AstroBuilder {
messages = ['Server built in', colors.bold(total)]; messages = ['Server built in', colors.bold(total)];
} }
info(logging, 'build', messages.join(' ')); logger.info('build', messages.join(' '));
info(logging, 'build', `${colors.bold('Complete!')}`); logger.info('build', `${colors.bold('Complete!')}`);
} }
} }

View file

@ -1,6 +1,5 @@
import type { AstroSettings, ManifestData } from '../../@types/astro'; import type { AstroSettings, ManifestData } from '../../@types/astro';
import type { LogOptions } from '../logger/core'; import type { Logger } from '../logger/core';
import { info } from '../logger/core.js';
import type { AllPagesData } from './types'; import type { AllPagesData } from './types';
import * as colors from 'kleur/colors'; import * as colors from 'kleur/colors';
@ -8,7 +7,7 @@ import { debug } from '../logger/core.js';
export interface CollectPagesDataOptions { export interface CollectPagesDataOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
manifest: ManifestData; manifest: ManifestData;
} }
@ -27,7 +26,7 @@ export async function collectPagesData(
const allPages: AllPagesData = {}; const allPages: AllPagesData = {};
const builtPaths = new Set<string>(); const builtPaths = new Set<string>();
const dataCollectionLogTimeout = setInterval(() => { const dataCollectionLogTimeout = setInterval(() => {
info(opts.logging, 'build', 'The data collection step may take longer for larger projects...'); opts.logger.info('build', 'The data collection step may take longer for larger projects...');
clearInterval(dataCollectionLogTimeout); clearInterval(dataCollectionLogTimeout);
}, 30000); }, 30000);
@ -39,8 +38,7 @@ export async function collectPagesData(
// static route: // static route:
if (route.pathname) { if (route.pathname) {
const routeCollectionLogTimeout = setInterval(() => { const routeCollectionLogTimeout = setInterval(() => {
info( opts.logger.info(
opts.logging,
'build', 'build',
`${colors.bold( `${colors.bold(
route.component route.component

View file

@ -100,7 +100,7 @@ export function pluginManifest(
await runHookBuildSsr({ await runHookBuildSsr({
config: options.settings.config, config: options.settings.config,
manifest, manifest,
logging: options.logging, logger: options.logger,
entryPoints: internals.entryPoints, entryPoints: internals.entryPoints,
middlewareEntryPoint: shouldPassMiddlewareEntryPoint middlewareEntryPoint: shouldPassMiddlewareEntryPoint
? internals.middlewareEntryPoint ? internals.middlewareEntryPoint

View file

@ -19,7 +19,6 @@ import { runHookBuildSetup } from '../../integrations/index.js';
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { info } from '../logger/core.js';
import { routeIsRedirect } from '../redirects/index.js'; import { routeIsRedirect } from '../redirects/index.js';
import { getOutDirWithinCwd } from './common.js'; import { getOutDirWithinCwd } from './common.js';
import { generatePages } from './generate.js'; import { generatePages } from './generate.js';
@ -80,9 +79,9 @@ export async function viteBuild(opts: StaticBuildOptions) {
// Build your project (SSR application code, assets, client JS, etc.) // Build your project (SSR application code, assets, client JS, etc.)
const ssrTime = performance.now(); const ssrTime = performance.now();
info(opts.logging, 'build', `Building ${settings.config.output} entrypoints...`); opts.logger.info('build', `Building ${settings.config.output} entrypoints...`);
const ssrOutput = await ssrBuild(opts, internals, pageInput, container); const ssrOutput = await ssrBuild(opts, internals, pageInput, container);
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(ssrTime, performance.now())}.`)); opts.logger.info('build', dim(`Completed in ${getTimeStat(ssrTime, performance.now())}.`));
settings.timer.end('SSR build'); settings.timer.end('SSR build');
settings.timer.start('Client build'); settings.timer.start('Client build');
@ -132,7 +131,7 @@ export async function staticBuild(opts: StaticBuildOptions, internals: BuildInte
settings.timer.start('Server generate'); settings.timer.start('Server generate');
await generatePages(opts, internals); await generatePages(opts, internals);
await cleanStaticOutput(opts, internals); await cleanStaticOutput(opts, internals);
info(opts.logging, null, `\n${bgMagenta(black(' finalizing server assets '))}\n`); opts.logger.info(null, `\n${bgMagenta(black(' finalizing server assets '))}\n`);
await ssrMoveAssets(opts); await ssrMoveAssets(opts);
settings.timer.end('Server generate'); settings.timer.end('Server generate');
return; return;
@ -214,7 +213,7 @@ async function ssrBuild(
pages: internals.pagesByComponent, pages: internals.pagesByComponent,
vite: viteBuildConfig, vite: viteBuildConfig,
target: 'server', target: 'server',
logging: opts.logging, logger: opts.logger,
}); });
return await vite.build(updatedViteBuildConfig); return await vite.build(updatedViteBuildConfig);
@ -242,7 +241,7 @@ async function clientBuild(
} }
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('client', input); const { lastVitePlugins, vitePlugins } = container.runBeforeHook('client', input);
info(opts.logging, null, `\n${bgGreen(black(' building client '))}`); opts.logger.info(null, `\n${bgGreen(black(' building client '))}`);
const viteBuildConfig: vite.InlineConfig = { const viteBuildConfig: vite.InlineConfig = {
...viteConfig, ...viteConfig,
@ -276,11 +275,11 @@ async function clientBuild(
pages: internals.pagesByComponent, pages: internals.pagesByComponent,
vite: viteBuildConfig, vite: viteBuildConfig,
target: 'client', target: 'client',
logging: opts.logging, logger: opts.logger,
}); });
const buildResult = await vite.build(viteBuildConfig); const buildResult = await vite.build(viteBuildConfig);
info(opts.logging, null, dim(`Completed in ${getTimeStat(timer, performance.now())}.\n`)); opts.logger.info(null, dim(`Completed in ${getTimeStat(timer, performance.now())}.\n`));
return buildResult; return buildResult;
} }
@ -403,7 +402,7 @@ async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles = false
} }
async function ssrMoveAssets(opts: StaticBuildOptions) { async function ssrMoveAssets(opts: StaticBuildOptions) {
info(opts.logging, 'build', 'Rearranging server assets...'); opts.logger.info('build', 'Rearranging server assets...');
const serverRoot = const serverRoot =
opts.settings.config.output === 'static' opts.settings.config.output === 'static'
? opts.settings.config.build.client ? opts.settings.config.build.client

View file

@ -8,7 +8,7 @@ import type {
RuntimeMode, RuntimeMode,
SSRLoadedRenderer, SSRLoadedRenderer,
} from '../../@types/astro'; } from '../../@types/astro';
import type { LogOptions } from '../logger/core'; import type { Logger } from '../logger/core';
import type { RouteCache } from '../render/route-cache'; import type { RouteCache } from '../render/route-cache';
export type ComponentPath = string; export type ComponentPath = string;
@ -34,7 +34,7 @@ export type AllPagesData = Record<ComponentPath, PageBuildData>;
export interface StaticBuildOptions { export interface StaticBuildOptions {
allPages: AllPagesData; allPages: AllPagesData;
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
manifest: ManifestData; manifest: ManifestData;
mode: RuntimeMode; mode: RuntimeMode;
origin: string; origin: string;

View file

@ -1,5 +1,5 @@
export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js'; export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js';
export { createNodeLogging } from './logging.js'; export { createNodeLogger } from './logging.js';
export { mergeConfig } from './merge.js'; export { mergeConfig } from './merge.js';
export type { AstroConfigType } from './schema'; export type { AstroConfigType } from './schema';
export { createSettings } from './settings.js'; export { createSettings } from './settings.js';

View file

@ -1,13 +1,12 @@
import type { AstroInlineConfig } from '../../@types/astro.js'; import type { AstroInlineConfig } from '../../@types/astro.js';
import type { LogOptions } from '../logger/core.js'; import { Logger } from '../logger/core.js';
import { nodeLogDestination } from '../logger/node.js'; import { nodeLogDestination } from '../logger/node.js';
export function createNodeLogging(inlineConfig: AstroInlineConfig): LogOptions { export function createNodeLogger(inlineConfig: AstroInlineConfig): Logger {
// For internal testing, the inline config can pass the raw `logging` object directly if (inlineConfig.logger) return inlineConfig.logger;
if (inlineConfig.logging) return inlineConfig.logging;
return { return new Logger({
dest: nodeLogDestination, dest: nodeLogDestination,
level: inlineConfig.logLevel ?? 'info', level: inlineConfig.logLevel ?? 'info',
}; });
} }

View file

@ -1,5 +1,5 @@
import type { AstroSettings } from '../@types/astro'; import type { AstroSettings } from '../@types/astro';
import type { LogOptions } from './logger/core'; import type { Logger } from './logger/core';
import nodeFs from 'node:fs'; import nodeFs from 'node:fs';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
@ -32,7 +32,7 @@ import { joinPaths } from './path.js';
interface CreateViteOptions { interface CreateViteOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
mode: 'dev' | 'build' | string; mode: 'dev' | 'build' | string;
// will be undefined when using `getViteConfig` // will be undefined when using `getViteConfig`
command?: 'dev' | 'build'; command?: 'dev' | 'build';
@ -66,7 +66,7 @@ const ONLY_DEV_EXTERNAL = [
/** Return a common starting point for all Vite actions */ /** Return a common starting point for all Vite actions */
export async function createVite( export async function createVite(
commandConfig: vite.InlineConfig, commandConfig: vite.InlineConfig,
{ settings, logging, mode, command, fs = nodeFs }: CreateViteOptions { settings, logger, mode, command, fs = nodeFs }: CreateViteOptions
): Promise<vite.InlineConfig> { ): Promise<vite.InlineConfig> {
const astroPkgsConfig = await crawlFrameworkPkgs({ const astroPkgsConfig = await crawlFrameworkPkgs({
root: fileURLToPath(settings.config.root), root: fileURLToPath(settings.config.root),
@ -113,26 +113,26 @@ export async function createVite(
plugins: [ plugins: [
configAliasVitePlugin({ settings }), configAliasVitePlugin({ settings }),
astroLoadFallbackPlugin({ fs, root: settings.config.root }), astroLoadFallbackPlugin({ fs, root: settings.config.root }),
astroVitePlugin({ settings, logging }), astroVitePlugin({ settings, logger }),
astroScriptsPlugin({ settings }), astroScriptsPlugin({ settings }),
// The server plugin is for dev only and having it run during the build causes // The server plugin is for dev only and having it run during the build causes
// the build to run very slow as the filewatcher is triggered often. // the build to run very slow as the filewatcher is triggered often.
mode !== 'build' && vitePluginAstroServer({ settings, logging, fs }), mode !== 'build' && vitePluginAstroServer({ settings, logger, fs }),
envVitePlugin({ settings }), envVitePlugin({ settings }),
markdownVitePlugin({ settings, logging }), markdownVitePlugin({ settings, logger }),
htmlVitePlugin(), htmlVitePlugin(),
mdxVitePlugin({ settings, logging }), mdxVitePlugin({ settings, logger }),
astroPostprocessVitePlugin(), astroPostprocessVitePlugin(),
astroIntegrationsContainerPlugin({ settings, logging }), astroIntegrationsContainerPlugin({ settings, logger }),
astroScriptsPageSSRPlugin({ settings }), astroScriptsPageSSRPlugin({ settings }),
astroHeadPlugin(), astroHeadPlugin(),
astroScannerPlugin({ settings, logging }), astroScannerPlugin({ settings, logger }),
astroInjectEnvTsPlugin({ settings, logging, fs }), astroInjectEnvTsPlugin({ settings, logger, fs }),
astroContentVirtualModPlugin({ settings }), astroContentVirtualModPlugin({ settings }),
astroContentImportPlugin({ fs, settings }), astroContentImportPlugin({ fs, settings }),
astroContentAssetPropagationPlugin({ mode, settings }), astroContentAssetPropagationPlugin({ mode, settings }),
vitePluginSSRManifest(), vitePluginSSRManifest(),
astroAssetsPlugin({ settings, logging, mode }), astroAssetsPlugin({ settings, logger, mode }),
astroTransitions({ config: settings.config }), astroTransitions({ config: settings.config }),
], ],
publicDir: fileURLToPath(settings.config.publicDir), publicDir: fileURLToPath(settings.config.publicDir),

View file

@ -12,12 +12,12 @@ import {
runHookServerStart, runHookServerStart,
} from '../../integrations/index.js'; } from '../../integrations/index.js';
import { createVite } from '../create-vite.js'; import { createVite } from '../create-vite.js';
import type { LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
import { apply as applyPolyfill } from '../polyfill.js'; import { apply as applyPolyfill } from '../polyfill.js';
export interface Container { export interface Container {
fs: typeof nodeFs; fs: typeof nodeFs;
logging: LogOptions; logger: Logger;
settings: AstroSettings; settings: AstroSettings;
viteServer: vite.ViteDevServer; viteServer: vite.ViteDevServer;
inlineConfig: AstroInlineConfig; inlineConfig: AstroInlineConfig;
@ -27,7 +27,7 @@ export interface Container {
} }
export interface CreateContainerParams { export interface CreateContainerParams {
logging: LogOptions; logger: Logger;
settings: AstroSettings; settings: AstroSettings;
inlineConfig?: AstroInlineConfig; inlineConfig?: AstroInlineConfig;
isRestart?: boolean; isRestart?: boolean;
@ -36,7 +36,7 @@ export interface CreateContainerParams {
export async function createContainer({ export async function createContainer({
isRestart = false, isRestart = false,
logging, logger,
inlineConfig, inlineConfig,
settings, settings,
fs = nodeFs, fs = nodeFs,
@ -46,7 +46,7 @@ export async function createContainer({
settings = await runHookConfigSetup({ settings = await runHookConfigSetup({
settings, settings,
command: 'dev', command: 'dev',
logging, logger: logger,
isRestart, isRestart,
}); });
@ -73,15 +73,15 @@ export async function createContainer({
include: rendererClientEntries, include: rendererClientEntries,
}, },
}, },
{ settings, logging, mode: 'dev', command: 'dev', fs } { settings, logger, mode: 'dev', command: 'dev', fs }
); );
await runHookConfigDone({ settings, logging }); await runHookConfigDone({ settings, logger });
const viteServer = await vite.createServer(viteConfig); const viteServer = await vite.createServer(viteConfig);
const container: Container = { const container: Container = {
inlineConfig: inlineConfig ?? {}, inlineConfig: inlineConfig ?? {},
fs, fs,
logging, logger,
restartInFlight: false, restartInFlight: false,
settings, settings,
viteServer, viteServer,
@ -97,18 +97,18 @@ export async function createContainer({
return container; return container;
} }
async function closeContainer({ viteServer, settings, logging }: Container) { async function closeContainer({ viteServer, settings, logger }: Container) {
await viteServer.close(); await viteServer.close();
await runHookServerDone({ await runHookServerDone({
config: settings.config, config: settings.config,
logging, logger,
}); });
} }
export async function startContainer({ export async function startContainer({
settings, settings,
viteServer, viteServer,
logging, logger,
}: Container): Promise<AddressInfo> { }: Container): Promise<AddressInfo> {
const { port } = settings.config.server; const { port } = settings.config.server;
await viteServer.listen(port); await viteServer.listen(port);
@ -116,7 +116,7 @@ export async function startContainer({
await runHookServerStart({ await runHookServerStart({
config: settings.config, config: settings.config,
address: devServerAddressInfo, address: devServerAddressInfo,
logging, logger,
}); });
return devServerAddressInfo; return devServerAddressInfo;

View file

@ -6,7 +6,6 @@ import type * as vite from 'vite';
import type { AstroInlineConfig } from '../../@types/astro'; import type { AstroInlineConfig } from '../../@types/astro';
import { attachContentServerListeners } from '../../content/index.js'; import { attachContentServerListeners } from '../../content/index.js';
import { telemetry } from '../../events/index.js'; import { telemetry } from '../../events/index.js';
import { info, warn } from '../logger/core.js';
import * as msg from '../messages.js'; import * as msg from '../messages.js';
import { startContainer } from './container.js'; import { startContainer } from './container.js';
import { createContainerWithAutomaticRestart } from './restart.js'; import { createContainerWithAutomaticRestart } from './restart.js';
@ -30,13 +29,12 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevS
// Create a container which sets up the Vite server. // Create a container which sets up the Vite server.
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs }); const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
const logging = restart.container.logging; const logger = restart.container.logger;
// Start listening to the port // Start listening to the port
const devServerAddressInfo = await startContainer(restart.container); const devServerAddressInfo = await startContainer(restart.container);
info( logger.info(
logging,
null, null,
msg.serverStart({ msg.serverStart({
startupTime: performance.now() - devStart, startupTime: performance.now() - devStart,
@ -48,10 +46,10 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevS
const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0'; const currentVersion = process.env.PACKAGE_VERSION ?? '0.0.0';
if (currentVersion.includes('-')) { if (currentVersion.includes('-')) {
warn(logging, null, msg.prerelease({ currentVersion })); logger.warn(null, msg.prerelease({ currentVersion }));
} }
if (restart.container.viteServer.config.server?.fs?.strict === false) { if (restart.container.viteServer.config.server?.fs?.strict === false) {
warn(logging, null, msg.fsStrictWarning()); logger.warn(null, msg.fsStrictWarning());
} }
await attachContentServerListeners(restart.container); await attachContentServerListeners(restart.container);

View file

@ -3,11 +3,10 @@ import { fileURLToPath } from 'node:url';
import * as vite from 'vite'; import * as vite from 'vite';
import type { AstroInlineConfig, AstroSettings } from '../../@types/astro'; import type { AstroInlineConfig, AstroSettings } from '../../@types/astro';
import { eventCliSession, telemetry } from '../../events/index.js'; import { eventCliSession, telemetry } from '../../events/index.js';
import { createNodeLogging, createSettings, resolveConfig } from '../config/index.js'; import { createNodeLogger, createSettings, resolveConfig } from '../config/index.js';
import { collectErrorMetadata } from '../errors/dev/utils.js'; import { collectErrorMetadata } from '../errors/dev/utils.js';
import { isAstroConfigZodError } from '../errors/errors.js'; import { isAstroConfigZodError } from '../errors/errors.js';
import { createSafeError } from '../errors/index.js'; import { createSafeError } from '../errors/index.js';
import { info, error as logError } from '../logger/core.js';
import { formatErrorMessage } from '../messages.js'; import { formatErrorMessage } from '../messages.js';
import type { Container } from './container'; import type { Container } from './container';
import { createContainer, startContainer } from './container.js'; import { createContainer, startContainer } from './container.js';
@ -16,10 +15,10 @@ async function createRestartedContainer(
container: Container, container: Container,
settings: AstroSettings settings: AstroSettings
): Promise<Container> { ): Promise<Container> {
const { logging, fs, inlineConfig } = container; const { logger, fs, inlineConfig } = container;
const newContainer = await createContainer({ const newContainer = await createContainer({
isRestart: true, isRestart: true,
logging, logger: logger,
settings, settings,
inlineConfig, inlineConfig,
fs, fs,
@ -60,7 +59,7 @@ export function shouldRestartContainer(
} }
export async function restartContainer(container: Container): Promise<Container | Error> { export async function restartContainer(container: Container): Promise<Container | Error> {
const { logging, close, settings: existingSettings } = container; const { logger, close, settings: existingSettings } = container;
container.restartInFlight = true; container.restartInFlight = true;
try { try {
@ -72,7 +71,7 @@ export async function restartContainer(container: Container): Promise<Container
const error = createSafeError(_err); const error = createSafeError(_err);
// Print all error messages except ZodErrors from AstroConfig as the pre-logged error is sufficient // Print all error messages except ZodErrors from AstroConfig as the pre-logged error is sufficient
if (!isAstroConfigZodError(_err)) { if (!isAstroConfigZodError(_err)) {
logError(logging, 'config', formatErrorMessage(collectErrorMetadata(error)) + '\n'); logger.error('config', formatErrorMessage(collectErrorMetadata(error)) + '\n');
} }
// Inform connected clients of the config error // Inform connected clients of the config error
container.viteServer.ws.send({ container.viteServer.ws.send({
@ -83,7 +82,7 @@ export async function restartContainer(container: Container): Promise<Container
}, },
}); });
container.restartInFlight = false; container.restartInFlight = false;
info(logging, 'astro', 'Continuing with previous valid configuration\n'); logger.error('astro', 'Continuing with previous valid configuration\n');
return error; return error;
} }
} }
@ -102,13 +101,13 @@ export async function createContainerWithAutomaticRestart({
inlineConfig, inlineConfig,
fs, fs,
}: CreateContainerWithAutomaticRestart): Promise<Restart> { }: CreateContainerWithAutomaticRestart): Promise<Restart> {
const logging = createNodeLogging(inlineConfig ?? {}); const logger = createNodeLogger(inlineConfig ?? {});
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev', fs); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev', fs);
telemetry.record(eventCliSession('dev', userConfig)); telemetry.record(eventCliSession('dev', userConfig));
const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root)); const settings = createSettings(astroConfig, fileURLToPath(astroConfig.root));
const initialContainer = await createContainer({ settings, logging, inlineConfig, fs }); const initialContainer = await createContainer({ settings, logger: logger, inlineConfig, fs });
let resolveRestart: (value: Error | null) => void; let resolveRestart: (value: Error | null) => void;
let restartComplete = new Promise<Error | null>((resolve) => { let restartComplete = new Promise<Error | null>((resolve) => {
@ -123,7 +122,7 @@ export async function createContainerWithAutomaticRestart({
}; };
async function handleServerRestart(logMsg: string) { async function handleServerRestart(logMsg: string) {
info(logging, 'astro', logMsg + '\n'); logger.info('astro', logMsg + '\n');
const container = restart.container; const container = restart.container;
const result = await restartContainer(container); const result = await restartContainer(container);
if (result instanceof Error) { if (result instanceof Error) {

View file

@ -11,7 +11,6 @@ import { renderEndpoint } from '../../runtime/server/index.js';
import { ASTRO_VERSION } from '../constants.js'; import { ASTRO_VERSION } from '../constants.js';
import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js'; import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js'; import { callMiddleware } from '../middleware/callMiddleware.js';
import type { Environment, RenderContext } from '../render/index'; import type { Environment, RenderContext } from '../render/index';
@ -132,23 +131,22 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
let response; let response;
if (onRequest) { if (onRequest) {
response = await callMiddleware<Response | EndpointOutput>( response = await callMiddleware<Response | EndpointOutput>(
env.logging, env.logger,
onRequest as MiddlewareEndpointHandler, onRequest as MiddlewareEndpointHandler,
context, context,
async () => { async () => {
return await renderEndpoint(mod, context, env.ssr, env.logging); return await renderEndpoint(mod, context, env.ssr, env.logger);
} }
); );
} else { } else {
response = await renderEndpoint(mod, context, env.ssr, env.logging); response = await renderEndpoint(mod, context, env.ssr, env.logger);
} }
const isEndpointSSR = env.ssr && !ctx.route?.prerender; const isEndpointSSR = env.ssr && !ctx.route?.prerender;
if (response instanceof Response) { if (response instanceof Response) {
if (isEndpointSSR && response.headers.get('X-Astro-Encoding')) { if (isEndpointSSR && response.headers.get('X-Astro-Encoding')) {
warn( env.logger.warn(
env.logging,
'ssr', 'ssr',
'`ResponseWithEncoding` is ignored in SSR. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.' '`ResponseWithEncoding` is ignored in SSR. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.'
); );
@ -160,24 +158,21 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
// The endpoint returned a simple object, convert it to a Response // The endpoint returned a simple object, convert it to a Response
// TODO: Remove in Astro 4.0 // TODO: Remove in Astro 4.0
warn( env.logger.warn(
env.logging,
'astro', 'astro',
`${ctx.route.component} returns a simple object which is deprecated. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.` `${ctx.route.component} returns a simple object which is deprecated. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.`
); );
if (isEndpointSSR) { if (isEndpointSSR) {
if (response.hasOwnProperty('headers')) { if (response.hasOwnProperty('headers')) {
warn( env.logger.warn(
env.logging,
'ssr', 'ssr',
'Setting headers is not supported when returning an object. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.' 'Setting headers is not supported when returning an object. Please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.'
); );
} }
if (response.encoding) { if (response.encoding) {
warn( env.logger.warn(
env.logging,
'ssr', 'ssr',
'`encoding` is ignored in SSR. To return a charset other than UTF-8, please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.' '`encoding` is ignored in SSR. To return a charset other than UTF-8, please return an instance of Response. See https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes for more information.'
); );

View file

@ -142,8 +142,16 @@ export class Logger {
error(label: string | null, message: string) { error(label: string | null, message: string) {
error(this.options, label, message); error(this.options, label, message);
} }
debug(label: string | null, message: string) { debug(label: string | null, message: string, ...args: any[]) {
debug(this.options, label, message); debug(this.options, label, message, args);
}
level() {
return this.options.level;
}
forkIntegrationLogger(label: string) {
return new AstroIntegrationLogger(this.options, label);
} }
} }

View file

@ -6,7 +6,6 @@ import type {
MiddlewareNext, MiddlewareNext,
} from '../../@types/astro'; } from '../../@types/astro';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn } from '../logger/core.js';
import type { Environment } from '../render'; import type { Environment } from '../render';
/** /**
@ -44,7 +43,7 @@ import type { Environment } from '../render';
* @param responseFunction A callback function that should return a promise with the response * @param responseFunction A callback function that should return a promise with the response
*/ */
export async function callMiddleware<R>( export async function callMiddleware<R>(
logging: Environment['logging'], logger: Environment['logger'],
onRequest: MiddlewareHandler<R>, onRequest: MiddlewareHandler<R>,
apiContext: APIContext, apiContext: APIContext,
responseFunction: () => Promise<R> responseFunction: () => Promise<R>
@ -61,8 +60,7 @@ export async function callMiddleware<R>(
return await Promise.resolve(middlewarePromise).then(async (value) => { return await Promise.resolve(middlewarePromise).then(async (value) => {
if (isEndpointOutput(value)) { if (isEndpointOutput(value)) {
warn( logger.warn(
logging,
'middleware', 'middleware',
'Using simple endpoints can cause unexpected issues in the chain of middleware functions.' + 'Using simple endpoints can cause unexpected issues in the chain of middleware functions.' +
`\nIt's strongly suggested to use full ${bold('Response')} objects.` `\nIt's strongly suggested to use full ${bold('Response')} objects.`

View file

@ -116,7 +116,7 @@ export class Pipeline {
case 'redirect': { case 'redirect': {
if (onRequest) { if (onRequest) {
return await callMiddleware<Response>( return await callMiddleware<Response>(
env.logging, env.logger,
onRequest as MiddlewareResponseHandler, onRequest as MiddlewareResponseHandler,
apiContext, apiContext,
() => { () => {

View file

@ -5,7 +5,7 @@ import { telemetry } from '../../events/index.js';
import { eventCliSession } from '../../events/session.js'; import { eventCliSession } from '../../events/session.js';
import { runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js'; import { runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js';
import { resolveConfig } from '../config/config.js'; import { resolveConfig } from '../config/config.js';
import { createNodeLogging } from '../config/logging.js'; import { createNodeLogger } from '../config/logging.js';
import { createSettings } from '../config/settings.js'; import { createSettings } from '../config/settings.js';
import createStaticPreviewServer from './static-preview-server.js'; import createStaticPreviewServer from './static-preview-server.js';
import { getResolvedHostForHttpServer } from './util.js'; import { getResolvedHostForHttpServer } from './util.js';
@ -17,7 +17,7 @@ import { getResolvedHostForHttpServer } from './util.js';
* @experimental The JavaScript API is experimental * @experimental The JavaScript API is experimental
*/ */
export default async function preview(inlineConfig: AstroInlineConfig): Promise<PreviewServer> { export default async function preview(inlineConfig: AstroInlineConfig): Promise<PreviewServer> {
const logging = createNodeLogging(inlineConfig); const logger = createNodeLogger(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview'); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview');
telemetry.record(eventCliSession('preview', userConfig)); telemetry.record(eventCliSession('preview', userConfig));
@ -26,12 +26,12 @@ export default async function preview(inlineConfig: AstroInlineConfig): Promise<
const settings = await runHookConfigSetup({ const settings = await runHookConfigSetup({
settings: _settings, settings: _settings,
command: 'preview', command: 'preview',
logging: logging, logger: logger,
}); });
await runHookConfigDone({ settings: settings, logging: logging }); await runHookConfigDone({ settings: settings, logger: logger });
if (settings.config.output === 'static') { if (settings.config.output === 'static') {
const server = await createStaticPreviewServer(settings, logging); const server = await createStaticPreviewServer(settings, logger);
return server; return server;
} }
if (!settings.adapter) { if (!settings.adapter) {

View file

@ -4,8 +4,7 @@ import { performance } from 'perf_hooks';
import enableDestroy from 'server-destroy'; import enableDestroy from 'server-destroy';
import { preview, type PreviewServer as VitePreviewServer } from 'vite'; import { preview, type PreviewServer as VitePreviewServer } from 'vite';
import type { AstroSettings } from '../../@types/astro'; import type { AstroSettings } from '../../@types/astro';
import type { LogOptions } from '../logger/core'; import type { Logger } from '../logger/core';
import { error, info } from '../logger/core.js';
import * as msg from '../messages.js'; import * as msg from '../messages.js';
import { getResolvedHostForHttpServer } from './util.js'; import { getResolvedHostForHttpServer } from './util.js';
import { vitePluginAstroPreview } from './vite-plugin-astro-preview.js'; import { vitePluginAstroPreview } from './vite-plugin-astro-preview.js';
@ -20,7 +19,7 @@ export interface PreviewServer {
export default async function createStaticPreviewServer( export default async function createStaticPreviewServer(
settings: AstroSettings, settings: AstroSettings,
logging: LogOptions logger: Logger
): Promise<PreviewServer> { ): Promise<PreviewServer> {
const startServerTime = performance.now(); const startServerTime = performance.now();
@ -43,7 +42,7 @@ export default async function createStaticPreviewServer(
}); });
} catch (err) { } catch (err) {
if (err instanceof Error) { if (err instanceof Error) {
error(logging, 'astro', err.stack || err.message); logger.error('astro', err.stack || err.message);
} }
throw err; throw err;
} }
@ -51,8 +50,7 @@ export default async function createStaticPreviewServer(
enableDestroy(previewServer.httpServer); enableDestroy(previewServer.httpServer);
// Log server start URLs // Log server start URLs
info( logger.info(
logging,
null, null,
msg.serverStart({ msg.serverStart({
startupTime: performance.now() - startServerTime, startupTime: performance.now() - startServerTime,

View file

@ -48,7 +48,7 @@ export async function createRenderContext(
route: options.route, route: options.route,
routeCache: options.env.routeCache, routeCache: options.env.routeCache,
pathname: pathname, pathname: pathname,
logging: options.env.logging, logger: options.env.logger,
ssr: options.env.ssr, ssr: options.env.ssr,
}); });

View file

@ -8,7 +8,6 @@ import type {
import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js'; import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js';
import { attachCookiesToResponse } from '../cookies/index.js'; import { attachCookiesToResponse } from '../cookies/index.js';
import { callEndpoint, createAPIContext } from '../endpoint/index.js'; import { callEndpoint, createAPIContext } from '../endpoint/index.js';
import { warn } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js'; import { callMiddleware } from '../middleware/callMiddleware.js';
import { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from '../redirects/index.js'; import { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from '../redirects/index.js';
import type { RenderContext } from './context.js'; import type { RenderContext } from './context.js';
@ -41,7 +40,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag
adapterName: env.adapterName, adapterName: env.adapterName,
links: renderContext.links, links: renderContext.links,
styles: renderContext.styles, styles: renderContext.styles,
logging: env.logging, logger: env.logger,
params: renderContext.params, params: renderContext.params,
pathname: renderContext.pathname, pathname: renderContext.pathname,
componentMetadata: renderContext.componentMetadata, componentMetadata: renderContext.componentMetadata,
@ -60,8 +59,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag
// TODO: Remove in Astro 4.0 // TODO: Remove in Astro 4.0
if (mod.frontmatter && typeof mod.frontmatter === 'object' && 'draft' in mod.frontmatter) { if (mod.frontmatter && typeof mod.frontmatter === 'object' && 'draft' in mod.frontmatter) {
warn( env.logger.warn(
env.logging,
'astro', 'astro',
`The drafts feature is deprecated and used in ${renderContext.route.component}. You should migrate to content collections instead. See https://docs.astro.build/en/guides/content-collections/#filtering-collection-queries for more information.` `The drafts feature is deprecated and used in ${renderContext.route.component}. You should migrate to content collections instead. See https://docs.astro.build/en/guides/content-collections/#filtering-collection-queries for more information.`
); );
@ -115,7 +113,7 @@ export async function tryRenderRoute<MiddlewareReturnType = Response>(
case 'redirect': { case 'redirect': {
if (onRequest) { if (onRequest) {
return await callMiddleware<Response>( return await callMiddleware<Response>(
env.logging, env.logger,
onRequest as MiddlewareResponseHandler, onRequest as MiddlewareResponseHandler,
apiContext, apiContext,
() => { () => {

View file

@ -1,5 +1,5 @@
import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro'; import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro';
import type { LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
import type { RouteCache } from './route-cache.js'; import type { RouteCache } from './route-cache.js';
/** /**
@ -13,7 +13,7 @@ export interface Environment {
*/ */
adapterName?: string; adapterName?: string;
/** logging options */ /** logging options */
logging: LogOptions; logger: Logger;
/** "development" or "production" */ /** "development" or "production" */
mode: RuntimeMode; mode: RuntimeMode;
compressHTML: boolean; compressHTML: boolean;

View file

@ -1,6 +1,6 @@
import type { ComponentInstance, Params, Props, RouteData } from '../../@types/astro'; import type { ComponentInstance, Params, Props, RouteData } from '../../@types/astro';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import type { LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
import { getParams } from '../routing/params.js'; import { getParams } from '../routing/params.js';
import { RouteCache, callGetStaticPaths, findPathItemByKey } from './route-cache.js'; import { RouteCache, callGetStaticPaths, findPathItemByKey } from './route-cache.js';
@ -9,12 +9,12 @@ interface GetParamsAndPropsOptions {
route?: RouteData | undefined; route?: RouteData | undefined;
routeCache: RouteCache; routeCache: RouteCache;
pathname: string; pathname: string;
logging: LogOptions; logger: Logger;
ssr: boolean; ssr: boolean;
} }
export async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise<[Params, Props]> { export async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise<[Params, Props]> {
const { logging, mod, route, routeCache, pathname, ssr } = opts; const { logger, mod, route, routeCache, pathname, ssr } = opts;
// If there's no route, or if there's a pathname (e.g. a static `src/pages/normal.astro` file), // If there's no route, or if there's a pathname (e.g. a static `src/pages/normal.astro` file),
// then we know for sure they don't have params and props, return a fallback value. // then we know for sure they don't have params and props, return a fallback value.
@ -33,11 +33,11 @@ export async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise
mod, mod,
route, route,
routeCache, routeCache,
logging, logger,
ssr, ssr,
}); });
const matchedStaticPath = findPathItemByKey(staticPaths, params, route); const matchedStaticPath = findPathItemByKey(staticPaths, params, route, logger);
if (!matchedStaticPath && (ssr ? route.prerender : true)) { if (!matchedStaticPath && (ssr ? route.prerender : true)) {
throw new AstroError({ throw new AstroError({
...AstroErrorData.NoMatchingStaticPathFound, ...AstroErrorData.NoMatchingStaticPathFound,

View file

@ -11,7 +11,7 @@ import { renderJSX } from '../../runtime/server/jsx.js';
import { chunkToString } from '../../runtime/server/render/index.js'; import { chunkToString } from '../../runtime/server/render/index.js';
import { AstroCookies } from '../cookies/index.js'; import { AstroCookies } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn, type LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
const clientAddressSymbol = Symbol.for('astro.clientAddress'); const clientAddressSymbol = Symbol.for('astro.clientAddress');
const responseSentSymbol = Symbol.for('astro.responseSent'); const responseSentSymbol = Symbol.for('astro.responseSent');
@ -25,7 +25,7 @@ export interface CreateResultArgs {
* Value of Astro config's `output` option, true if "server" or "hybrid" * Value of Astro config's `output` option, true if "server" or "hybrid"
*/ */
ssr: boolean; ssr: boolean;
logging: LogOptions; logger: Logger;
params: Params; params: Params;
pathname: string; pathname: string;
renderers: SSRLoadedRenderer[]; renderers: SSRLoadedRenderer[];
@ -55,12 +55,12 @@ function getFunctionExpression(slot: any) {
class Slots { class Slots {
#result: SSRResult; #result: SSRResult;
#slots: ComponentSlots | null; #slots: ComponentSlots | null;
#loggingOpts: LogOptions; #logger: Logger;
constructor(result: SSRResult, slots: ComponentSlots | null, logging: LogOptions) { constructor(result: SSRResult, slots: ComponentSlots | null, logger: Logger) {
this.#result = result; this.#result = result;
this.#slots = slots; this.#slots = slots;
this.#loggingOpts = logging; this.#logger = logger;
if (slots) { if (slots) {
for (const key of Object.keys(slots)) { for (const key of Object.keys(slots)) {
@ -90,8 +90,7 @@ class Slots {
const result = this.#result; const result = this.#result;
if (!Array.isArray(args)) { if (!Array.isArray(args)) {
warn( this.#logger.warn(
this.#loggingOpts,
'Astro.slots.render', 'Astro.slots.render',
`Expected second parameter to be an array, received a ${typeof args}. If you're trying to pass an array as a single argument and getting unexpected results, make sure you're passing your array as a item of an array. Ex: Astro.slots.render('default', [["Hello", "World"]])` `Expected second parameter to be an array, received a ${typeof args}. If you're trying to pass an array as a single argument and getting unexpected results, make sure you're passing your array as a item of an array. Ex: Astro.slots.render('default', [["Hello", "World"]])`
); );
@ -164,7 +163,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
props: Record<string, any>, props: Record<string, any>,
slots: Record<string, any> | null slots: Record<string, any> | null
) { ) {
const astroSlots = new Slots(result, slots, args.logging); const astroSlots = new Slots(result, slots, args.logger);
const Astro: AstroGlobal = { const Astro: AstroGlobal = {
// @ts-expect-error // @ts-expect-error

View file

@ -8,7 +8,7 @@ import type {
RuntimeMode, RuntimeMode,
} from '../../@types/astro'; } from '../../@types/astro';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import { debug, warn, type LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
import { stringifyParams } from '../routing/params.js'; import { stringifyParams } from '../routing/params.js';
import { validateDynamicRouteModule, validateGetStaticPathsResult } from '../routing/validation.js'; import { validateDynamicRouteModule, validateGetStaticPathsResult } from '../routing/validation.js';
@ -18,7 +18,7 @@ interface CallGetStaticPathsOptions {
mod: ComponentInstance; mod: ComponentInstance;
route: RouteData; route: RouteData;
routeCache: RouteCache; routeCache: RouteCache;
logging: LogOptions; logger: Logger;
ssr: boolean; ssr: boolean;
} }
@ -26,7 +26,7 @@ export async function callGetStaticPaths({
mod, mod,
route, route,
routeCache, routeCache,
logging, logger,
ssr, ssr,
}: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed> { }: CallGetStaticPathsOptions): Promise<GetStaticPathsResultKeyed> {
const cached = routeCache.get(route); const cached = routeCache.get(route);
@ -56,7 +56,7 @@ export async function callGetStaticPaths({
}, },
}); });
validateGetStaticPathsResult(staticPaths, logging, route); validateGetStaticPathsResult(staticPaths, logger, route);
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed; const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>(); keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
@ -80,12 +80,12 @@ interface RouteCacheEntry {
* responses during dev and only ever called once during build. * responses during dev and only ever called once during build.
*/ */
export class RouteCache { export class RouteCache {
private logging: LogOptions; private logger: Logger;
private cache: Record<string, RouteCacheEntry> = {}; private cache: Record<string, RouteCacheEntry> = {};
private mode: RuntimeMode; private mode: RuntimeMode;
constructor(logging: LogOptions, mode: RuntimeMode = 'production') { constructor(logger: Logger, mode: RuntimeMode = 'production') {
this.logging = logging; this.logger = logger;
this.mode = mode; this.mode = mode;
} }
@ -99,8 +99,7 @@ export class RouteCache {
// Warn here so that an unexpected double-call of getStaticPaths() // Warn here so that an unexpected double-call of getStaticPaths()
// isn't invisible and developer can track down the issue. // isn't invisible and developer can track down the issue.
if (this.mode === 'production' && this.cache[route.component]?.staticPaths) { if (this.mode === 'production' && this.cache[route.component]?.staticPaths) {
warn( this.logger.warn(
this.logging,
'routeCache', 'routeCache',
`Internal Warning: route cache overwritten. (${route.component})` `Internal Warning: route cache overwritten. (${route.component})`
); );
@ -116,12 +115,13 @@ export class RouteCache {
export function findPathItemByKey( export function findPathItemByKey(
staticPaths: GetStaticPathsResultKeyed, staticPaths: GetStaticPathsResultKeyed,
params: Params, params: Params,
route: RouteData route: RouteData,
logger: Logger
) { ) {
const paramsKey = stringifyParams(params, route); const paramsKey = stringifyParams(params, route);
const matchedStaticPath = staticPaths.keyed.get(paramsKey); const matchedStaticPath = staticPaths.keyed.get(paramsKey);
if (matchedStaticPath) { if (matchedStaticPath) {
return matchedStaticPath; return matchedStaticPath;
} }
debug('findPathItemByKey', `Unexpected cache miss looking for ${paramsKey}`); logger.debug('findPathItemByKey', `Unexpected cache miss looking for ${paramsKey}`);
} }

View file

@ -1,6 +1,5 @@
import type { IncomingHttpHeaders } from 'node:http'; import type { IncomingHttpHeaders } from 'node:http';
import type { LogOptions } from './logger/core'; import type { Logger } from './logger/core';
import { warn } from './logger/core.js';
type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders; type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData; type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData;
@ -11,7 +10,7 @@ export interface CreateRequestOptions {
headers: HeaderType; headers: HeaderType;
method?: string; method?: string;
body?: RequestBody | undefined; body?: RequestBody | undefined;
logging: LogOptions; logger: Logger;
ssr: boolean; ssr: boolean;
locals?: object | undefined; locals?: object | undefined;
} }
@ -25,7 +24,7 @@ export function createRequest({
clientAddress, clientAddress,
method = 'GET', method = 'GET',
body = undefined, body = undefined,
logging, logger,
ssr, ssr,
locals, locals,
}: CreateRequestOptions): Request { }: CreateRequestOptions): Request {
@ -43,7 +42,7 @@ export function createRequest({
Object.defineProperties(request, { Object.defineProperties(request, {
params: { params: {
get() { get() {
warn(logging, 'deprecation', `Astro.request.params has been moved to Astro.params`); logger.warn('deprecation', `Astro.request.params has been moved to Astro.params`);
return undefined; return undefined;
}, },
}, },
@ -56,8 +55,7 @@ export function createRequest({
Object.defineProperty(request, 'headers', { Object.defineProperty(request, 'headers', {
...headersDesc, ...headersDesc,
get() { get() {
warn( logger.warn(
logging,
'ssg', 'ssg',
`Headers are not exposed in static (SSG) output mode. To enable headers: set \`output: "server"\` in your config file.` `Headers are not exposed in static (SSG) output mode. To enable headers: set \`output: "server"\` in your config file.`
); );

View file

@ -6,7 +6,7 @@ import type {
RouteData, RouteData,
RoutePart, RoutePart,
} from '../../../@types/astro'; } from '../../../@types/astro';
import type { LogOptions } from '../../logger/core'; import type { Logger } from '../../logger/core';
import { createRequire } from 'module'; import { createRequire } from 'module';
import nodeFs from 'node:fs'; import nodeFs from 'node:fs';
@ -14,7 +14,6 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { getPrerenderDefault } from '../../../prerender/utils.js'; import { getPrerenderDefault } from '../../../prerender/utils.js';
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
import { warn } from '../../logger/core.js';
import { removeLeadingForwardSlash, slash } from '../../path.js'; import { removeLeadingForwardSlash, slash } from '../../path.js';
import { resolvePages } from '../../util.js'; import { resolvePages } from '../../util.js';
import { getRouteGenerator } from './generator.js'; import { getRouteGenerator } from './generator.js';
@ -221,7 +220,7 @@ export interface CreateRouteManifestParams {
/** Create manifest of all static routes */ /** Create manifest of all static routes */
export function createRouteManifest( export function createRouteManifest(
{ settings, cwd, fsMod }: CreateRouteManifestParams, { settings, cwd, fsMod }: CreateRouteManifestParams,
logging: LogOptions logger: Logger
): ManifestData { ): ManifestData {
const components: string[] = []; const components: string[] = [];
const routes: RouteData[] = []; const routes: RouteData[] = [];
@ -261,7 +260,7 @@ export function createRouteManifest(
if (!isDir && !validPageExtensions.has(ext) && !validEndpointExtensions.has(ext)) { if (!isDir && !validPageExtensions.has(ext) && !validEndpointExtensions.has(ext)) {
if (!foundInvalidFileExtensions.has(ext)) { if (!foundInvalidFileExtensions.has(ext)) {
foundInvalidFileExtensions.add(ext); foundInvalidFileExtensions.add(ext);
warn(logging, 'astro', `Invalid file extension for Pages: ${ext}`); logger.warn('astro', `Invalid file extension for Pages: ${ext}`);
} }
return; return;
@ -359,7 +358,7 @@ export function createRouteManifest(
} else if (settings.injectedRoutes.length === 0) { } else if (settings.injectedRoutes.length === 0) {
const pagesDirRootRelative = pages.href.slice(settings.config.root.href.length); const pagesDirRootRelative = pages.href.slice(settings.config.root.href.length);
warn(logging, 'astro', `Missing pages directory: ${pagesDirRootRelative}`); logger.warn('astro', `Missing pages directory: ${pagesDirRootRelative}`);
} }
settings.injectedRoutes settings.injectedRoutes

View file

@ -1,7 +1,6 @@
import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro'; import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro';
import { AstroError, AstroErrorData } from '../errors/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js';
import type { LogOptions } from '../logger/core'; import type { Logger } from '../logger/core';
import { warn } from '../logger/core.js';
const VALID_PARAM_TYPES = ['string', 'number', 'undefined']; const VALID_PARAM_TYPES = ['string', 'number', 'undefined'];
@ -40,7 +39,7 @@ export function validateDynamicRouteModule(
/** Throw error and log warnings for malformed getStaticPaths() response */ /** Throw error and log warnings for malformed getStaticPaths() response */
export function validateGetStaticPathsResult( export function validateGetStaticPathsResult(
result: GetStaticPathsResult, result: GetStaticPathsResult,
logging: LogOptions, logger: Logger,
route: RouteData route: RouteData
) { ) {
if (!Array.isArray(result)) { if (!Array.isArray(result)) {
@ -79,8 +78,7 @@ export function validateGetStaticPathsResult(
// TODO: Replace those with errors? They technically don't crash the build, but users might miss the warning. - erika, 2022-11-07 // TODO: Replace those with errors? They technically don't crash the build, but users might miss the warning. - erika, 2022-11-07
for (const [key, val] of Object.entries(pathObject.params)) { for (const [key, val] of Object.entries(pathObject.params)) {
if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) { if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) {
warn( logger.warn(
logging,
'getStaticPaths', 'getStaticPaths',
`invalid path param: ${key}. A string, number or undefined value was expected, but got \`${JSON.stringify( `invalid path param: ${key}. A string, number or undefined value was expected, but got \`${JSON.stringify(
val val
@ -88,8 +86,7 @@ export function validateGetStaticPathsResult(
); );
} }
if (typeof val === 'string' && val === '') { if (typeof val === 'string' && val === '') {
warn( logger.warn(
logging,
'getStaticPaths', 'getStaticPaths',
`invalid path param: ${key}. \`undefined\` expected for an optional param, but got empty string.` `invalid path param: ${key}. \`undefined\` expected for an optional param, but got empty string.`
); );

View file

@ -12,11 +12,11 @@ import { runHookConfigSetup } from '../../integrations/index.js';
import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js'; import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js';
import { getTimeStat } from '../build/util.js'; import { getTimeStat } from '../build/util.js';
import { resolveConfig } from '../config/config.js'; import { resolveConfig } from '../config/config.js';
import { createNodeLogging } from '../config/logging.js'; import { createNodeLogger } from '../config/logging.js';
import { createSettings } from '../config/settings.js'; import { createSettings } from '../config/settings.js';
import { createVite } from '../create-vite.js'; import { createVite } from '../create-vite.js';
import { AstroError, AstroErrorData, createSafeError, isAstroError } from '../errors/index.js'; import { AstroError, AstroErrorData, createSafeError, isAstroError } from '../errors/index.js';
import { info, type LogOptions } from '../logger/core.js'; import type { Logger } from '../logger/core.js';
export type ProcessExit = 0 | 1; export type ProcessExit = 0 | 1;
@ -28,7 +28,7 @@ export type SyncOptions = {
}; };
export type SyncInternalOptions = SyncOptions & { export type SyncInternalOptions = SyncOptions & {
logging: LogOptions; logger: Logger;
}; };
/** /**
@ -41,7 +41,7 @@ export default async function sync(
inlineConfig: AstroInlineConfig, inlineConfig: AstroInlineConfig,
options?: SyncOptions options?: SyncOptions
): Promise<ProcessExit> { ): Promise<ProcessExit> {
const logging = createNodeLogging(inlineConfig); const logger = createNodeLogger(inlineConfig);
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync');
telemetry.record(eventCliSession('sync', userConfig)); telemetry.record(eventCliSession('sync', userConfig));
@ -49,11 +49,11 @@ export default async function sync(
const settings = await runHookConfigSetup({ const settings = await runHookConfigSetup({
settings: _settings, settings: _settings,
logging: logging, logger: logger,
command: 'build', command: 'build',
}); });
return await syncInternal(settings, { ...options, logging }); return await syncInternal(settings, { ...options, logger });
} }
/** /**
@ -72,7 +72,7 @@ export default async function sync(
*/ */
export async function syncInternal( export async function syncInternal(
settings: AstroSettings, settings: AstroSettings,
{ logging, fs }: SyncInternalOptions { logger, fs }: SyncInternalOptions
): Promise<ProcessExit> { ): Promise<ProcessExit> {
const timerStart = performance.now(); const timerStart = performance.now();
// Needed to load content config // Needed to load content config
@ -84,7 +84,7 @@ export async function syncInternal(
ssr: { external: [] }, ssr: { external: [] },
logLevel: 'silent', logLevel: 'silent',
}, },
{ settings, logging, mode: 'build', command: 'build', fs } { settings, logger, mode: 'build', command: 'build', fs }
) )
); );
@ -101,7 +101,7 @@ export async function syncInternal(
try { try {
const contentTypesGenerator = await createContentTypesGenerator({ const contentTypesGenerator = await createContentTypesGenerator({
contentConfigObserver: globalContentConfigObserver, contentConfigObserver: globalContentConfigObserver,
logging, logger: logger,
fs: fs ?? fsMod, fs: fs ?? fsMod,
settings, settings,
viteServer: tempViteServer, viteServer: tempViteServer,
@ -117,7 +117,7 @@ export async function syncInternal(
switch (typesResult.reason) { switch (typesResult.reason) {
case 'no-content-dir': case 'no-content-dir':
default: default:
info(logging, 'content', 'No content directory found. Skipping type generation.'); logger.info('content', 'No content directory found. Skipping type generation.');
return 0; return 0;
} }
} }
@ -137,8 +137,8 @@ export async function syncInternal(
await tempViteServer.close(); await tempViteServer.close();
} }
info(logging, 'content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); logger.info('content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`);
await setUpEnvTs({ settings, logging, fs: fs ?? fsMod }); await setUpEnvTs({ settings, logger, fs: fs ?? fsMod });
return 0; return 0;
} }

View file

@ -4,7 +4,7 @@ import type {
AstroFeatureMap, AstroFeatureMap,
SupportsKind, SupportsKind,
} from '../@types/astro'; } from '../@types/astro';
import { error, warn, type LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
const STABLE = 'stable'; const STABLE = 'stable';
const DEPRECATED = 'deprecated'; const DEPRECATED = 'deprecated';
@ -40,7 +40,7 @@ export function validateSupportedFeatures(
adapterName: string, adapterName: string,
featureMap: AstroFeatureMap = ALL_UNSUPPORTED, featureMap: AstroFeatureMap = ALL_UNSUPPORTED,
config: AstroConfig, config: AstroConfig,
logging: LogOptions logger: Logger
): ValidationResult { ): ValidationResult {
const { const {
assets = UNSUPPORTED_ASSETS_FEATURE, assets = UNSUPPORTED_ASSETS_FEATURE,
@ -53,7 +53,7 @@ export function validateSupportedFeatures(
validationResult.staticOutput = validateSupportKind( validationResult.staticOutput = validateSupportKind(
staticOutput, staticOutput,
adapterName, adapterName,
logging, logger,
'staticOutput', 'staticOutput',
() => config?.output === 'static' () => config?.output === 'static'
); );
@ -61,7 +61,7 @@ export function validateSupportedFeatures(
validationResult.hybridOutput = validateSupportKind( validationResult.hybridOutput = validateSupportKind(
hybridOutput, hybridOutput,
adapterName, adapterName,
logging, logger,
'hybridOutput', 'hybridOutput',
() => config?.output === 'hybrid' () => config?.output === 'hybrid'
); );
@ -69,11 +69,11 @@ export function validateSupportedFeatures(
validationResult.serverOutput = validateSupportKind( validationResult.serverOutput = validateSupportKind(
serverOutput, serverOutput,
adapterName, adapterName,
logging, logger,
'serverOutput', 'serverOutput',
() => config?.output === 'server' () => config?.output === 'server'
); );
validationResult.assets = validateAssetsFeature(assets, adapterName, config, logging); validationResult.assets = validateAssetsFeature(assets, adapterName, config, logger);
return validationResult; return validationResult;
} }
@ -81,44 +81,39 @@ export function validateSupportedFeatures(
function validateSupportKind( function validateSupportKind(
supportKind: SupportsKind, supportKind: SupportsKind,
adapterName: string, adapterName: string,
logging: LogOptions, logger: Logger,
featureName: string, featureName: string,
hasCorrectConfig: () => boolean hasCorrectConfig: () => boolean
): boolean { ): boolean {
if (supportKind === STABLE) { if (supportKind === STABLE) {
return true; return true;
} else if (supportKind === DEPRECATED) { } else if (supportKind === DEPRECATED) {
featureIsDeprecated(adapterName, logging); featureIsDeprecated(adapterName, logger);
} else if (supportKind === EXPERIMENTAL) { } else if (supportKind === EXPERIMENTAL) {
featureIsExperimental(adapterName, logging); featureIsExperimental(adapterName, logger);
} }
if (hasCorrectConfig() && supportKind === UNSUPPORTED) { if (hasCorrectConfig() && supportKind === UNSUPPORTED) {
featureIsUnsupported(adapterName, logging, featureName); featureIsUnsupported(adapterName, logger, featureName);
return false; return false;
} else { } else {
return true; return true;
} }
} }
function featureIsUnsupported(adapterName: string, logging: LogOptions, featureName: string) { function featureIsUnsupported(adapterName: string, logger: Logger, featureName: string) {
error( logger.error(
logging,
`${adapterName}`, `${adapterName}`,
`The feature ${featureName} is not supported by the adapter ${adapterName}.` `The feature ${featureName} is not supported by the adapter ${adapterName}.`
); );
} }
function featureIsExperimental(adapterName: string, logging: LogOptions) { function featureIsExperimental(adapterName: string, logger: Logger) {
warn(logging, `${adapterName}`, 'The feature is experimental and subject to issues or changes.'); logger.warn(`${adapterName}`, 'The feature is experimental and subject to issues or changes.');
} }
function featureIsDeprecated(adapterName: string, logging: LogOptions) { function featureIsDeprecated(adapterName: string, logger: Logger) {
warn( logger.warn(`${adapterName}`, 'The feature is deprecated and will be moved in the next release.');
logging,
`${adapterName}`,
'The feature is deprecated and will be moved in the next release.'
);
} }
const SHARP_SERVICE = 'astro/assets/services/sharp'; const SHARP_SERVICE = 'astro/assets/services/sharp';
@ -128,7 +123,7 @@ function validateAssetsFeature(
assets: AstroAssetsFeature, assets: AstroAssetsFeature,
adapterName: string, adapterName: string,
config: AstroConfig, config: AstroConfig,
logging: LogOptions logger: Logger
): boolean { ): boolean {
const { const {
supportKind = UNSUPPORTED, supportKind = UNSUPPORTED,
@ -136,8 +131,7 @@ function validateAssetsFeature(
isSquooshCompatible = false, isSquooshCompatible = false,
} = assets; } = assets;
if (config?.image?.service?.entrypoint === SHARP_SERVICE && !isSharpCompatible) { if (config?.image?.service?.entrypoint === SHARP_SERVICE && !isSharpCompatible) {
error( logger.error(
logging,
'astro', 'astro',
`The currently selected adapter \`${adapterName}\` is not compatible with the image service "Sharp".` `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Sharp".`
); );
@ -145,13 +139,12 @@ function validateAssetsFeature(
} }
if (config?.image?.service?.entrypoint === SQUOOSH_SERVICE && !isSquooshCompatible) { if (config?.image?.service?.entrypoint === SQUOOSH_SERVICE && !isSquooshCompatible) {
error( logger.error(
logging,
'astro', 'astro',
`The currently selected adapter \`${adapterName}\` is not compatible with the image service "Squoosh".` `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Squoosh".`
); );
return false; return false;
} }
return validateSupportKind(supportKind, adapterName, logging, 'assets', () => true); return validateSupportKind(supportKind, adapterName, logger, 'assets', () => true);
} }

View file

@ -18,7 +18,7 @@ import type { SerializedSSRManifest } from '../core/app/types';
import type { PageBuildData } from '../core/build/types'; import type { PageBuildData } from '../core/build/types';
import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js'; import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js';
import { mergeConfig } from '../core/config/index.js'; import { mergeConfig } from '../core/config/index.js';
import { AstroIntegrationLogger, error, info, warn, type LogOptions } from '../core/logger/core.js'; import { AstroIntegrationLogger, type Logger } from '../core/logger/core.js';
import { isServerLikeOutput } from '../prerender/utils.js'; import { isServerLikeOutput } from '../prerender/utils.js';
import { validateSupportedFeatures } from './astroFeaturesValidation.js'; import { validateSupportedFeatures } from './astroFeaturesValidation.js';
@ -26,15 +26,15 @@ async function withTakingALongTimeMsg<T>({
name, name,
hookResult, hookResult,
timeoutMs = 3000, timeoutMs = 3000,
logging, logger,
}: { }: {
name: string; name: string;
hookResult: T | Promise<T>; hookResult: T | Promise<T>;
timeoutMs?: number; timeoutMs?: number;
logging: LogOptions; logger: Logger;
}): Promise<T> { }): Promise<T> {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
info(logging, 'build', `Waiting for the ${bold(name)} integration...`); logger.info('build', `Waiting for the ${bold(name)} integration...`);
}, timeoutMs); }, timeoutMs);
const result = await hookResult; const result = await hookResult;
clearTimeout(timeout); clearTimeout(timeout);
@ -44,25 +44,25 @@ async function withTakingALongTimeMsg<T>({
// Used internally to store instances of loggers. // Used internally to store instances of loggers.
const Loggers = new WeakMap<AstroIntegration, AstroIntegrationLogger>(); const Loggers = new WeakMap<AstroIntegration, AstroIntegrationLogger>();
function getLogger(integration: AstroIntegration, logging: LogOptions) { function getLogger(integration: AstroIntegration, logger: Logger) {
if (Loggers.has(integration)) { if (Loggers.has(integration)) {
// SAFETY: we check the existence in the if block // SAFETY: we check the existence in the if block
return Loggers.get(integration)!; return Loggers.get(integration)!;
} }
const logger = new AstroIntegrationLogger(logging, integration.name); const integrationLogger = logger.forkIntegrationLogger(integration.name);
Loggers.set(integration, logger); Loggers.set(integration, integrationLogger);
return logger; return integrationLogger;
} }
export async function runHookConfigSetup({ export async function runHookConfigSetup({
settings, settings,
command, command,
logging, logger,
isRestart = false, isRestart = false,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
command: 'dev' | 'build' | 'preview'; command: 'dev' | 'build' | 'preview';
logging: LogOptions; logger: Logger;
isRestart?: boolean; isRestart?: boolean;
}): Promise<AstroSettings> { }): Promise<AstroSettings> {
// An adapter is an integration, so if one is provided push it. // An adapter is an integration, so if one is provided push it.
@ -88,7 +88,7 @@ export async function runHookConfigSetup({
* ``` * ```
*/ */
if (integration.hooks?.['astro:config:setup']) { if (integration.hooks?.['astro:config:setup']) {
const logger = getLogger(integration, logging); const integrationLogger = getLogger(integration, logger);
const hooks: HookParameters<'astro:config:setup'> = { const hooks: HookParameters<'astro:config:setup'> = {
config: updatedConfig, config: updatedConfig,
@ -125,7 +125,7 @@ export async function runHookConfigSetup({
} }
addedClientDirectives.set(name, buildClientDirectiveEntrypoint(name, entrypoint)); addedClientDirectives.set(name, buildClientDirectiveEntrypoint(name, entrypoint));
}, },
logger, logger: integrationLogger,
}; };
// --- // ---
@ -164,7 +164,7 @@ export async function runHookConfigSetup({
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:config:setup'](hooks), hookResult: integration.hooks['astro:config:setup'](hooks),
logging, logger,
}); });
// Add custom client directives to settings, waiting for compiled code by esbuild // Add custom client directives to settings, waiting for compiled code by esbuild
@ -180,13 +180,12 @@ export async function runHookConfigSetup({
export async function runHookConfigDone({ export async function runHookConfigDone({
settings, settings,
logging, logger,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
}) { }) {
for (const integration of settings.config.integrations) { for (const integration of settings.config.integrations) {
const logger = getLogger(integration, logging);
if (integration?.hooks?.['astro:config:done']) { if (integration?.hooks?.['astro:config:done']) {
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
@ -200,8 +199,7 @@ export async function runHookConfigDone({
} }
if (!adapter.supportedAstroFeatures) { if (!adapter.supportedAstroFeatures) {
// NOTE: throw an error in Astro 4.0 // NOTE: throw an error in Astro 4.0
warn( logger.warn(
logging,
'astro', 'astro',
`The adapter ${adapter.name} doesn't provide a feature map. From Astro 3.0, an adapter can provide a feature map. Not providing a feature map will cause an error in Astro 4.0.` `The adapter ${adapter.name} doesn't provide a feature map. From Astro 3.0, an adapter can provide a feature map. Not providing a feature map will cause an error in Astro 4.0.`
); );
@ -210,20 +208,18 @@ export async function runHookConfigDone({
adapter.name, adapter.name,
adapter.supportedAstroFeatures, adapter.supportedAstroFeatures,
settings.config, settings.config,
logging logger
); );
for (const [featureName, supported] of Object.entries(validationResult)) { for (const [featureName, supported] of Object.entries(validationResult)) {
if (!supported) { if (!supported) {
error( logger.error(
logging,
'astro', 'astro',
`The adapter ${adapter.name} doesn't support the feature ${featureName}. Your project won't be built. You should not use it.` `The adapter ${adapter.name} doesn't support the feature ${featureName}. Your project won't be built. You should not use it.`
); );
} }
} }
if (!validationResult.assets) { if (!validationResult.assets) {
info( logger.info(
logging,
'astro', 'astro',
`The selected adapter ${adapter.name} does not support Sharp or Squoosh for image processing. To ensure your project is still able to build, image processing has been disabled.` `The selected adapter ${adapter.name} does not support Sharp or Squoosh for image processing. To ensure your project is still able to build, image processing has been disabled.`
); );
@ -235,9 +231,9 @@ export async function runHookConfigDone({
} }
settings.adapter = adapter; settings.adapter = adapter;
}, },
logger, logger: getLogger(integration, logger),
}), }),
logging, logger,
}); });
} }
} }
@ -246,19 +242,21 @@ export async function runHookConfigDone({
export async function runHookServerSetup({ export async function runHookServerSetup({
config, config,
server, server,
logging, logger,
}: { }: {
config: AstroConfig; config: AstroConfig;
server: ViteDevServer; server: ViteDevServer;
logging: LogOptions; logger: Logger;
}) { }) {
for (const integration of config.integrations) { for (const integration of config.integrations) {
if (integration?.hooks?.['astro:server:setup']) { if (integration?.hooks?.['astro:server:setup']) {
const logger = getLogger(integration, logging);
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:server:setup']({ server, logger }), hookResult: integration.hooks['astro:server:setup']({
logging, server,
logger: getLogger(integration, logger),
}),
logger,
}); });
} }
} }
@ -267,20 +265,21 @@ export async function runHookServerSetup({
export async function runHookServerStart({ export async function runHookServerStart({
config, config,
address, address,
logging, logger,
}: { }: {
config: AstroConfig; config: AstroConfig;
address: AddressInfo; address: AddressInfo;
logging: LogOptions; logger: Logger;
}) { }) {
for (const integration of config.integrations) { for (const integration of config.integrations) {
const logger = getLogger(integration, logging);
if (integration?.hooks?.['astro:server:start']) { if (integration?.hooks?.['astro:server:start']) {
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:server:start']({ address, logger }), hookResult: integration.hooks['astro:server:start']({
logging, address,
logger: getLogger(integration, logger),
}),
logger,
}); });
} }
} }
@ -288,19 +287,19 @@ export async function runHookServerStart({
export async function runHookServerDone({ export async function runHookServerDone({
config, config,
logging, logger,
}: { }: {
config: AstroConfig; config: AstroConfig;
logging: LogOptions; logger: Logger;
}) { }) {
for (const integration of config.integrations) { for (const integration of config.integrations) {
const logger = getLogger(integration, logging);
if (integration?.hooks?.['astro:server:done']) { if (integration?.hooks?.['astro:server:done']) {
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:server:done']({ logger }), hookResult: integration.hooks['astro:server:done']({
logging, logger: getLogger(integration, logger),
}),
logger,
}); });
} }
} }
@ -311,7 +310,7 @@ export async function runHookBuildStart({
logging, logging,
}: { }: {
config: AstroConfig; config: AstroConfig;
logging: LogOptions; logging: Logger;
}) { }) {
for (const integration of config.integrations) { for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:start']) { if (integration?.hooks?.['astro:build:start']) {
@ -320,7 +319,7 @@ export async function runHookBuildStart({
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:build:start']({ logger }), hookResult: integration.hooks['astro:build:start']({ logger }),
logging, logger: logging,
}); });
} }
} }
@ -331,20 +330,18 @@ export async function runHookBuildSetup({
vite, vite,
pages, pages,
target, target,
logging, logger,
}: { }: {
config: AstroConfig; config: AstroConfig;
vite: InlineConfig; vite: InlineConfig;
pages: Map<string, PageBuildData>; pages: Map<string, PageBuildData>;
target: 'server' | 'client'; target: 'server' | 'client';
logging: LogOptions; logger: Logger;
}): Promise<InlineConfig> { }): Promise<InlineConfig> {
let updatedConfig = vite; let updatedConfig = vite;
for (const integration of config.integrations) { for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:setup']) { if (integration?.hooks?.['astro:build:setup']) {
const logger = getLogger(integration, logging);
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:build:setup']({ hookResult: integration.hooks['astro:build:setup']({
@ -354,9 +351,9 @@ export async function runHookBuildSetup({
updateConfig: (newConfig) => { updateConfig: (newConfig) => {
updatedConfig = mergeConfig(updatedConfig, newConfig); updatedConfig = mergeConfig(updatedConfig, newConfig);
}, },
logger, logger: getLogger(integration, logger),
}), }),
logging, logger,
}); });
} }
} }
@ -367,7 +364,7 @@ export async function runHookBuildSetup({
type RunHookBuildSsr = { type RunHookBuildSsr = {
config: AstroConfig; config: AstroConfig;
manifest: SerializedSSRManifest; manifest: SerializedSSRManifest;
logging: LogOptions; logger: Logger;
entryPoints: Map<RouteData, URL>; entryPoints: Map<RouteData, URL>;
middlewareEntryPoint: URL | undefined; middlewareEntryPoint: URL | undefined;
}; };
@ -375,23 +372,21 @@ type RunHookBuildSsr = {
export async function runHookBuildSsr({ export async function runHookBuildSsr({
config, config,
manifest, manifest,
logging, logger,
entryPoints, entryPoints,
middlewareEntryPoint, middlewareEntryPoint,
}: RunHookBuildSsr) { }: RunHookBuildSsr) {
for (const integration of config.integrations) { for (const integration of config.integrations) {
if (integration?.hooks?.['astro:build:ssr']) { if (integration?.hooks?.['astro:build:ssr']) {
const logger = getLogger(integration, logging);
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:build:ssr']({ hookResult: integration.hooks['astro:build:ssr']({
manifest, manifest,
entryPoints, entryPoints,
middlewareEntryPoint, middlewareEntryPoint,
logger, logger: getLogger(integration, logger),
}), }),
logging, logger,
}); });
} }
} }
@ -399,21 +394,22 @@ export async function runHookBuildSsr({
export async function runHookBuildGenerated({ export async function runHookBuildGenerated({
config, config,
logging, logger,
}: { }: {
config: AstroConfig; config: AstroConfig;
logging: LogOptions; logger: Logger;
}) { }) {
const dir = isServerLikeOutput(config) ? config.build.client : config.outDir; const dir = isServerLikeOutput(config) ? config.build.client : config.outDir;
for (const integration of config.integrations) { for (const integration of config.integrations) {
const logger = getLogger(integration, logging);
if (integration?.hooks?.['astro:build:generated']) { if (integration?.hooks?.['astro:build:generated']) {
await withTakingALongTimeMsg({ await withTakingALongTimeMsg({
name: integration.name, name: integration.name,
hookResult: integration.hooks['astro:build:generated']({ dir, logger }), hookResult: integration.hooks['astro:build:generated']({
logging, dir,
logger: getLogger(integration, logger),
}),
logger,
}); });
} }
} }
@ -423,7 +419,7 @@ type RunHookBuildDone = {
config: AstroConfig; config: AstroConfig;
pages: string[]; pages: string[];
routes: RouteData[]; routes: RouteData[];
logging: LogOptions; logging: Logger;
}; };
export async function runHookBuildDone({ config, pages, routes, logging }: RunHookBuildDone) { export async function runHookBuildDone({ config, pages, routes, logging }: RunHookBuildDone) {
@ -442,7 +438,7 @@ export async function runHookBuildDone({ config, pages, routes, logging }: RunHo
routes, routes,
logger, logger,
}), }),
logging, logger: logging,
}); });
} }
} }

View file

@ -1,13 +1,12 @@
import type { APIContext, EndpointHandler, Params } from '../../@types/astro'; import type { APIContext, EndpointHandler, Params } from '../../@types/astro';
import { warn, type LogOptions } from '../../core/logger/core.js'; import type { Logger } from '../../core/logger/core.js';
function getHandlerFromModule(mod: EndpointHandler, method: string, logging: LogOptions) { function getHandlerFromModule(mod: EndpointHandler, method: string, logger: Logger) {
const lowerCaseMethod = method.toLowerCase(); const lowerCaseMethod = method.toLowerCase();
// TODO: remove in Astro 4.0 // TODO: remove in Astro 4.0
if (mod[lowerCaseMethod]) { if (mod[lowerCaseMethod]) {
warn( logger.warn(
logging,
'astro', 'astro',
`Lower case endpoint names are deprecated and will not be supported in Astro 4.0. Rename the endpoint ${lowerCaseMethod} to ${method}.` `Lower case endpoint names are deprecated and will not be supported in Astro 4.0. Rename the endpoint ${lowerCaseMethod} to ${method}.`
); );
@ -43,12 +42,12 @@ export async function renderEndpoint(
mod: EndpointHandler, mod: EndpointHandler,
context: APIContext, context: APIContext,
ssr: boolean, ssr: boolean,
logging: LogOptions logger: Logger
) { ) {
const { request } = context; const { request } = context;
const chosenMethod = request.method?.toUpperCase(); const chosenMethod = request.method?.toUpperCase();
const handler = getHandlerFromModule(mod, chosenMethod, logging); const handler = getHandlerFromModule(mod, chosenMethod, logger);
// TODO: remove the 'get' check in Astro 4.0 // TODO: remove the 'get' check in Astro 4.0
if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'GET' && chosenMethod !== 'get') { if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'GET' && chosenMethod !== 'get') {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console

View file

@ -2,14 +2,14 @@ import type * as vite from 'vite';
import type { AstroSettings } from '../@types/astro'; import type { AstroSettings } from '../@types/astro';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import { warn, type LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js'; import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
import { log404 } from './common.js'; import { log404 } from './common.js';
import { writeHtmlResponse } from './response.js'; import { writeHtmlResponse } from './response.js';
export function baseMiddleware( export function baseMiddleware(
settings: AstroSettings, settings: AstroSettings,
logging: LogOptions logger: Logger
): vite.Connect.NextHandleFunction { ): vite.Connect.NextHandleFunction {
const { config } = settings; const { config } = settings;
const site = config.site ? new URL(config.base, config.site) : undefined; const site = config.site ? new URL(config.base, config.site) : undefined;
@ -28,13 +28,13 @@ export function baseMiddleware(
} }
if (pathname === '/' || pathname === '/index.html') { if (pathname === '/' || pathname === '/index.html') {
log404(logging, pathname); log404(logger, pathname);
const html = subpathNotUsedTemplate(devRoot, pathname); const html = subpathNotUsedTemplate(devRoot, pathname);
return writeHtmlResponse(res, 404, html); return writeHtmlResponse(res, 404, html);
} }
if (req.headers.accept?.includes('text/html')) { if (req.headers.accept?.includes('text/html')) {
log404(logging, pathname); log404(logger, pathname);
const html = notFoundTemplate({ const html = notFoundTemplate({
statusCode: 404, statusCode: 404,
title: 'Not found', title: 'Not found',
@ -49,8 +49,7 @@ export function baseMiddleware(
fs.stat(publicPath, (_err, stats) => { fs.stat(publicPath, (_err, stats) => {
if (stats) { if (stats) {
const expectedLocation = new URL('.' + url, devRootURL).pathname; const expectedLocation = new URL('.' + url, devRootURL).pathname;
warn( logger.warn(
logging,
'dev', 'dev',
`Requests for items in your public folder must also include your base. ${url} should be ${expectedLocation}. Omitting the base will break in production.` `Requests for items in your public folder must also include your base. ${url} should be ${expectedLocation}. Omitting the base will break in production.`
); );

View file

@ -1,6 +1,6 @@
import { info, type LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import * as msg from '../core/messages.js'; import * as msg from '../core/messages.js';
export function log404(logging: LogOptions, pathname: string) { export function log404(logger: Logger, pathname: string) {
info(logging, 'serve', msg.req({ url: pathname, statusCode: 404 })); logger.info('serve', msg.req({ url: pathname, statusCode: 404 }));
} }

View file

@ -5,8 +5,7 @@ import type {
SSRLoadedRenderer, SSRLoadedRenderer,
SSRManifest, SSRManifest,
} from '../@types/astro'; } from '../@types/astro';
import type { LogOptions } from '../core/logger/core'; import type { Logger } from '../core/logger/core';
import { Logger } from '../core/logger/core.js';
import type { ModuleLoader } from '../core/module-loader'; import type { ModuleLoader } from '../core/module-loader';
import { Pipeline } from '../core/pipeline.js'; import { Pipeline } from '../core/pipeline.js';
import type { Environment } from '../core/render'; import type { Environment } from '../core/render';
@ -22,18 +21,18 @@ export default class DevPipeline extends Pipeline {
constructor({ constructor({
manifest, manifest,
logging, logger,
settings, settings,
loader, loader,
}: { }: {
manifest: SSRManifest; manifest: SSRManifest;
logging: LogOptions; logger: Logger;
settings: AstroSettings; settings: AstroSettings;
loader: ModuleLoader; loader: ModuleLoader;
}) { }) {
const env = DevPipeline.createDevelopmentEnvironment(manifest, settings, logging, loader); const env = DevPipeline.createDevelopmentEnvironment(manifest, settings, logger, loader);
super(env); super(env);
this.#devLogger = new Logger(logging); this.#devLogger = logger;
this.#settings = settings; this.#settings = settings;
this.#loader = loader; this.#loader = loader;
this.setEndpointHandler(this.#handleEndpointResult); this.setEndpointHandler(this.#handleEndpointResult);
@ -69,21 +68,20 @@ export default class DevPipeline extends Pipeline {
static createDevelopmentEnvironment( static createDevelopmentEnvironment(
manifest: SSRManifest, manifest: SSRManifest,
settings: AstroSettings, settings: AstroSettings,
logging: LogOptions, logger: Logger,
loader: ModuleLoader loader: ModuleLoader
): Environment { ): Environment {
const mode: RuntimeMode = 'development'; const mode: RuntimeMode = 'development';
return createEnvironment({ return createEnvironment({
adapterName: manifest.adapterName, adapterName: manifest.adapterName,
logging, logger,
mode, mode,
// This will be overridden in the dev server // This will be overridden in the dev server
renderers: [], renderers: [],
clientDirectives: manifest.clientDirectives, clientDirectives: manifest.clientDirectives,
compressHTML: manifest.compressHTML, compressHTML: manifest.compressHTML,
resolve: createResolve(loader, settings.config.root), resolve: createResolve(loader, settings.config.root),
routeCache: new RouteCache(logging, mode), routeCache: new RouteCache(logger, mode),
site: manifest.site, site: manifest.site,
ssr: isServerLikeOutput(settings.config), ssr: isServerLikeOutput(settings.config),
streaming: true, streaming: true,

View file

@ -1,31 +0,0 @@
import type { AstroSettings, RuntimeMode, SSRManifest } from '../@types/astro.js';
import type { LogOptions } from '../core/logger/core.js';
import type { ModuleLoader } from '../core/module-loader';
import type { Environment } from '../core/render';
import { createEnvironment } from '../core/render/index.js';
import { RouteCache } from '../core/render/route-cache.js';
import { isServerLikeOutput } from '../prerender/utils.js';
import { createResolve } from './resolve.js';
export function createDevelopmentEnvironment(
manifest: SSRManifest,
settings: AstroSettings,
logging: LogOptions,
loader: ModuleLoader
): Environment {
const mode: RuntimeMode = 'development';
return createEnvironment({
adapterName: manifest.adapterName,
logging,
mode,
// This will be overridden in the dev server
renderers: [],
clientDirectives: manifest.clientDirectives,
compressHTML: manifest.compressHTML,
resolve: createResolve(loader, settings.config.root),
routeCache: new RouteCache(logging, mode),
site: manifest.site,
ssr: isServerLikeOutput(settings.config),
streaming: true,
});
}

View file

@ -2,7 +2,7 @@ import type fs from 'node:fs';
import type * as vite from 'vite'; import type * as vite from 'vite';
import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro'; import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro';
import { patchOverlay } from '../core/errors/overlay.js'; import { patchOverlay } from '../core/errors/overlay.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { createViteLoader } from '../core/module-loader/index.js'; import { createViteLoader } from '../core/module-loader/index.js';
import { createRouteManifest } from '../core/routing/index.js'; import { createRouteManifest } from '../core/routing/index.js';
import { baseMiddleware } from './base.js'; import { baseMiddleware } from './base.js';
@ -12,13 +12,13 @@ import { handleRequest } from './request.js';
export interface AstroPluginOptions { export interface AstroPluginOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
fs: typeof fs; fs: typeof fs;
} }
export default function createVitePluginAstroServer({ export default function createVitePluginAstroServer({
settings, settings,
logging, logger,
fs: fsMod, fs: fsMod,
}: AstroPluginOptions): vite.Plugin { }: AstroPluginOptions): vite.Plugin {
return { return {
@ -26,15 +26,15 @@ export default function createVitePluginAstroServer({
configureServer(viteServer) { configureServer(viteServer) {
const loader = createViteLoader(viteServer); const loader = createViteLoader(viteServer);
const manifest = createDevelopmentManifest(settings); const manifest = createDevelopmentManifest(settings);
const pipeline = new DevPipeline({ logging, manifest, settings, loader }); const pipeline = new DevPipeline({ logger, manifest, settings, loader });
let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logging); let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logger);
const controller = createController({ loader }); const controller = createController({ loader });
/** rebuild the route cache + manifest, as needed. */ /** rebuild the route cache + manifest, as needed. */
function rebuildManifest(needsManifestRebuild: boolean) { function rebuildManifest(needsManifestRebuild: boolean) {
pipeline.clearRouteCache(); pipeline.clearRouteCache();
if (needsManifestRebuild) { if (needsManifestRebuild) {
manifestData = createRouteManifest({ settings }, logging); manifestData = createRouteManifest({ settings }, logger);
} }
} }
// Rebuild route manifest on file change, if needed. // Rebuild route manifest on file change, if needed.
@ -47,7 +47,7 @@ export default function createVitePluginAstroServer({
// fix(#6067): always inject this to ensure zombie base handling is killed after restarts // fix(#6067): always inject this to ensure zombie base handling is killed after restarts
viteServer.middlewares.stack.unshift({ viteServer.middlewares.stack.unshift({
route: '', route: '',
handle: baseMiddleware(settings, logging), handle: baseMiddleware(settings, logger),
}); });
// Note that this function has a name so other middleware can find it. // Note that this function has a name so other middleware can find it.
viteServer.middlewares.use(async function astroDevHandler(request, response) { viteServer.middlewares.use(async function astroDevHandler(request, response) {

View file

@ -51,7 +51,7 @@ export async function matchRoute(
pipeline: DevPipeline pipeline: DevPipeline
): Promise<MatchedRoute | undefined> { ): Promise<MatchedRoute | undefined> {
const env = pipeline.getEnvironment(); const env = pipeline.getEnvironment();
const { routeCache, logging } = env; const { routeCache, logger } = env;
const matches = matchAllRoutes(pathname, manifestData); const matches = matchAllRoutes(pathname, manifestData);
const preloadedMatches = await getSortedPreloadedMatches({ const preloadedMatches = await getSortedPreloadedMatches({
pipeline, pipeline,
@ -68,7 +68,7 @@ export async function matchRoute(
route: maybeRoute, route: maybeRoute,
routeCache, routeCache,
pathname: pathname, pathname: pathname,
logging, logger,
ssr: isServerLikeOutput(pipeline.getConfig()), ssr: isServerLikeOutput(pipeline.getConfig()),
}); });
return { return {
@ -106,7 +106,7 @@ export async function matchRoute(
); );
} }
log404(logging, pathname); log404(logger, pathname);
const custom404 = getCustom404Route(manifestData); const custom404 = getCustom404Route(manifestData);
if (custom404) { if (custom404) {
@ -156,7 +156,7 @@ export async function handleRoute({
const settings = pipeline.getSettings(); const settings = pipeline.getSettings();
const config = pipeline.getConfig(); const config = pipeline.getConfig();
const moduleLoader = pipeline.getModuleLoader(); const moduleLoader = pipeline.getModuleLoader();
const { logging } = env; const { logger } = env;
if (!matchedRoute) { if (!matchedRoute) {
return handle404Response(origin, incomingRequest, incomingResponse); return handle404Response(origin, incomingRequest, incomingResponse);
} }
@ -171,7 +171,7 @@ export async function handleRoute({
headers: buildingToSSR ? incomingRequest.headers : new Headers(), headers: buildingToSSR ? incomingRequest.headers : new Headers(),
method: incomingRequest.method, method: incomingRequest.method,
body, body,
logging, logger,
ssr: buildingToSSR, ssr: buildingToSSR,
clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined, clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined,
locals: Reflect.get(incomingRequest, clientLocalsSymbol), // Allows adapters to pass in locals in dev mode. locals: Reflect.get(incomingRequest, clientLocalsSymbol), // Allows adapters to pass in locals in dev mode.

View file

@ -1,12 +1,12 @@
import { transformWithEsbuild, type ESBuildTransformResult } from 'vite'; import { transformWithEsbuild, type ESBuildTransformResult } from 'vite';
import type { AstroConfig } from '../@types/astro'; import type { AstroConfig } from '../@types/astro';
import { cachedCompilation, type CompileProps, type CompileResult } from '../core/compile/index.js'; import { cachedCompilation, type CompileProps, type CompileResult } from '../core/compile/index.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { getFileInfo } from '../vite-plugin-utils/index.js'; import { getFileInfo } from '../vite-plugin-utils/index.js';
interface CachedFullCompilation { interface CachedFullCompilation {
compileProps: CompileProps; compileProps: CompileProps;
logging: LogOptions; logger: Logger;
} }
interface FullCompileResult extends Omit<CompileResult, 'map'> { interface FullCompileResult extends Omit<CompileResult, 'map'> {
@ -18,14 +18,14 @@ interface EnhanceCompilerErrorOptions {
id: string; id: string;
source: string; source: string;
config: AstroConfig; config: AstroConfig;
logging: LogOptions; logger: Logger;
} }
const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
export async function cachedFullCompilation({ export async function cachedFullCompilation({
compileProps, compileProps,
logging, logger,
}: CachedFullCompilation): Promise<FullCompileResult> { }: CachedFullCompilation): Promise<FullCompileResult> {
let transformResult: CompileResult; let transformResult: CompileResult;
let esbuildResult: ESBuildTransformResult; let esbuildResult: ESBuildTransformResult;
@ -52,7 +52,7 @@ export async function cachedFullCompilation({
id: compileProps.filename, id: compileProps.filename,
source: compileProps.source, source: compileProps.source,
config: compileProps.astroConfig, config: compileProps.astroConfig,
logging: logging, logger: logger,
}); });
throw err; throw err;
} }

View file

@ -7,8 +7,7 @@ import {
isCached, isCached,
type CompileResult, type CompileResult,
} from '../core/compile/index.js'; } from '../core/compile/index.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { info } from '../core/logger/core.js';
import * as msg from '../core/messages.js'; import * as msg from '../core/messages.js';
import { isAstroScript } from './query.js'; import { isAstroScript } from './query.js';
@ -20,14 +19,15 @@ const isPkgFile = (id: string | null) => {
export interface HandleHotUpdateOptions { export interface HandleHotUpdateOptions {
config: AstroConfig; config: AstroConfig;
logging: LogOptions; logger: Logger;
compile: () => ReturnType<typeof cachedCompilation>; compile: () => ReturnType<typeof cachedCompilation>;
source: string; source: string;
} }
export async function handleHotUpdate( export async function handleHotUpdate(
ctx: HmrContext, ctx: HmrContext,
{ config, logging, compile, source }: HandleHotUpdateOptions { config, logger, compile, source }: HandleHotUpdateOptions
) { ) {
let isStyleOnlyChange = false; let isStyleOnlyChange = false;
if (ctx.file.endsWith('.astro') && isCached(config, ctx.file)) { if (ctx.file.endsWith('.astro') && isCached(config, ctx.file)) {
@ -95,7 +95,7 @@ export async function handleHotUpdate(
// If only styles are changed, remove the component file from the update list // If only styles are changed, remove the component file from the update list
if (isStyleOnlyChange) { if (isStyleOnlyChange) {
info(logging, 'astro', msg.hmr({ file, style: true })); logger.info('astro', msg.hmr({ file, style: true }));
// remove base file and hoisted scripts // remove base file and hoisted scripts
return mods.filter((mod) => mod.id !== ctx.file && !mod.id?.endsWith('.ts')); return mods.filter((mod) => mod.id !== ctx.file && !mod.id?.endsWith('.ts'));
} }
@ -124,9 +124,9 @@ export async function handleHotUpdate(
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte')); const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
if (isSelfAccepting) { if (isSelfAccepting) {
if (/astro\.config\.[cm][jt]s$/.test(file)) return mods; if (/astro\.config\.[cm][jt]s$/.test(file)) return mods;
info(logging, 'astro', msg.hmr({ file })); logger.info('astro', msg.hmr({ file }));
} else { } else {
info(logging, 'astro', msg.reload({ file })); logger.info('astro', msg.reload({ file }));
} }
return mods; return mods;

View file

@ -1,7 +1,7 @@
import type { SourceDescription } from 'rollup'; import type { SourceDescription } from 'rollup';
import type * as vite from 'vite'; import type * as vite from 'vite';
import type { AstroSettings } from '../@types/astro'; import type { AstroSettings } from '../@types/astro';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import type { PluginMetadata as AstroPluginMetadata } from './types'; import type { PluginMetadata as AstroPluginMetadata } from './types';
import { normalizePath } from 'vite'; import { normalizePath } from 'vite';
@ -20,11 +20,11 @@ export type { AstroPluginMetadata };
interface AstroPluginOptions { interface AstroPluginOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
} }
/** Transform .astro files for Vite */ /** Transform .astro files for Vite */
export default function astro({ settings, logging }: AstroPluginOptions): vite.Plugin[] { export default function astro({ settings, logger }: AstroPluginOptions): vite.Plugin[] {
const { config } = settings; const { config } = settings;
let resolvedConfig: vite.ResolvedConfig; let resolvedConfig: vite.ResolvedConfig;
@ -143,7 +143,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P
source, source,
}; };
const transformResult = await cachedFullCompilation({ compileProps, logging }); const transformResult = await cachedFullCompilation({ compileProps, logger });
for (const dep of transformResult.cssDeps) { for (const dep of transformResult.cssDeps) {
this.addWatchFile(dep); this.addWatchFile(dep);
@ -182,7 +182,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P
const compile = () => cachedCompilation(compileProps); const compile = () => cachedCompilation(compileProps);
return handleHotUpdate(context, { return handleHotUpdate(context, {
config, config,
logging, logger,
compile, compile,
source: compileProps.source, source: compileProps.source,
}); });

View file

@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url';
import { normalizePath, type Plugin } from 'vite'; import { normalizePath, type Plugin } from 'vite';
import type { AstroSettings } from '../@types/astro.js'; import type { AstroSettings } from '../@types/astro.js';
import { getContentPaths, getDotAstroTypeReference } from '../content/index.js'; import { getContentPaths, getDotAstroTypeReference } from '../content/index.js';
import { info, type LogOptions } from '../core/logger/core.js'; import { type Logger } from '../core/logger/core.js';
export function getEnvTsPath({ srcDir }: { srcDir: URL }) { export function getEnvTsPath({ srcDir }: { srcDir: URL }) {
return new URL('env.d.ts', srcDir); return new URL('env.d.ts', srcDir);
@ -13,11 +13,11 @@ export function getEnvTsPath({ srcDir }: { srcDir: URL }) {
export function astroInjectEnvTsPlugin({ export function astroInjectEnvTsPlugin({
settings, settings,
logging, logger,
fs, fs,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
fs: typeof fsMod; fs: typeof fsMod;
}): Plugin { }): Plugin {
return { return {
@ -26,18 +26,18 @@ export function astroInjectEnvTsPlugin({
// Ex. `.astro` types have been written // Ex. `.astro` types have been written
enforce: 'post', enforce: 'post',
async config() { async config() {
await setUpEnvTs({ settings, logging, fs }); await setUpEnvTs({ settings, logger, fs });
}, },
}; };
} }
export async function setUpEnvTs({ export async function setUpEnvTs({
settings, settings,
logging, logger,
fs, fs,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
fs: typeof fsMod; fs: typeof fsMod;
}) { }) {
const envTsPath = getEnvTsPath(settings.config); const envTsPath = getEnvTsPath(settings.config);
@ -57,7 +57,7 @@ export async function setUpEnvTs({
'types="astro/client"' 'types="astro/client"'
); );
await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8'); await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
info(logging, 'assets', `Removed ${bold(envTsPathRelativetoRoot)} types`); logger.info('assets', `Removed ${bold(envTsPathRelativetoRoot)} types`);
} }
if (!fs.existsSync(dotAstroDir)) if (!fs.existsSync(dotAstroDir))
@ -68,7 +68,7 @@ export async function setUpEnvTs({
if (!typesEnvContents.includes(expectedTypeReference)) { if (!typesEnvContents.includes(expectedTypeReference)) {
typesEnvContents = `${expectedTypeReference}\n${typesEnvContents}`; typesEnvContents = `${expectedTypeReference}\n${typesEnvContents}`;
await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8'); await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
info(logging, 'content', `Added ${bold(envTsPathRelativetoRoot)} types`); logger.info('content', `Added ${bold(envTsPathRelativetoRoot)} types`);
} }
} else { } else {
// Otherwise, inject the `env.d.ts` file // Otherwise, inject the `env.d.ts` file
@ -81,6 +81,6 @@ export async function setUpEnvTs({
await fs.promises.mkdir(settings.config.srcDir, { recursive: true }); await fs.promises.mkdir(settings.config.srcDir, { recursive: true });
await fs.promises.writeFile(envTsPath, referenceDefs.join('\n'), 'utf-8'); await fs.promises.writeFile(envTsPath, referenceDefs.join('\n'), 'utf-8');
info(logging, 'astro', `Added ${bold(envTsPathRelativetoRoot)} types`); logger.info('astro', `Added ${bold(envTsPathRelativetoRoot)} types`);
} }
} }

View file

@ -1,7 +1,7 @@
import type { PluginContext } from 'rollup'; import type { PluginContext } from 'rollup';
import type { Plugin as VitePlugin } from 'vite'; import type { Plugin as VitePlugin } from 'vite';
import type { AstroSettings, InjectedRoute, ResolvedInjectedRoute } from '../@types/astro.js'; import type { AstroSettings, InjectedRoute, ResolvedInjectedRoute } from '../@types/astro.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { normalizePath } from 'vite'; import { normalizePath } from 'vite';
import { runHookServerSetup } from '../integrations/index.js'; import { runHookServerSetup } from '../integrations/index.js';
@ -9,16 +9,16 @@ import { runHookServerSetup } from '../integrations/index.js';
/** Connect Astro integrations into Vite, as needed. */ /** Connect Astro integrations into Vite, as needed. */
export default function astroIntegrationsContainerPlugin({ export default function astroIntegrationsContainerPlugin({
settings, settings,
logging, logger,
}: { }: {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
}): VitePlugin { }): VitePlugin {
return { return {
name: 'astro:integration-container', name: 'astro:integration-container',
async configureServer(server) { async configureServer(server) {
if (server.config.isProduction) return; if (server.config.isProduction) return;
await runHookServerSetup({ config: settings.config, server, logging }); await runHookServerSetup({ config: settings.config, server, logger });
}, },
async buildStart() { async buildStart() {
if (settings.injectedRoutes.length === settings.resolvedInjectedRoutes.length) return; if (settings.injectedRoutes.length === settings.resolvedInjectedRoutes.length) return;

View file

@ -11,15 +11,14 @@ import type { Plugin } from 'vite';
import { normalizePath } from 'vite'; import { normalizePath } from 'vite';
import type { AstroSettings } from '../@types/astro'; import type { AstroSettings } from '../@types/astro';
import { AstroError, AstroErrorData, MarkdownError } from '../core/errors/index.js'; import { AstroError, AstroErrorData, MarkdownError } from '../core/errors/index.js';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import { warn } from '../core/logger/core.js';
import { isMarkdownFile, rootRelativePath } from '../core/util.js'; import { isMarkdownFile, rootRelativePath } from '../core/util.js';
import type { PluginMetadata } from '../vite-plugin-astro/types.js'; import type { PluginMetadata } from '../vite-plugin-astro/types.js';
import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js'; import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js';
interface AstroPluginOptions { interface AstroPluginOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
} }
function safeMatter(source: string, id: string) { function safeMatter(source: string, id: string) {
@ -57,7 +56,7 @@ const astroErrorModulePath = normalizePath(
fileURLToPath(new URL('../core/errors/index.js', import.meta.url)) fileURLToPath(new URL('../core/errors/index.js', import.meta.url))
); );
export default function markdown({ settings, logging }: AstroPluginOptions): Plugin { export default function markdown({ settings, logger }: AstroPluginOptions): Plugin {
return { return {
enforce: 'pre', enforce: 'pre',
name: 'astro:markdown', name: 'astro:markdown',
@ -101,8 +100,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
const { layout } = frontmatter; const { layout } = frontmatter;
if (frontmatter.setup) { if (frontmatter.setup) {
warn( logger.warn(
logging,
'markdown', 'markdown',
`[${id}] Astro now supports MDX! Support for components in ".md" (or alternative extensions like ".markdown") files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX.` `[${id}] Astro now supports MDX! Support for components in ".md" (or alternative extensions like ".markdown") files using the "setup" frontmatter is no longer enabled by default. Migrate this file to MDX.`
); );

View file

@ -1,7 +1,7 @@
import type { TransformResult } from 'rollup'; import type { TransformResult } from 'rollup';
import { transformWithEsbuild, type Plugin, type ResolvedConfig } from 'vite'; import { transformWithEsbuild, type Plugin, type ResolvedConfig } from 'vite';
import type { AstroRenderer, AstroSettings } from '../@types/astro'; import type { AstroRenderer, AstroSettings } from '../@types/astro';
import type { LogOptions } from '../core/logger/core.js'; import type { Logger } from '../core/logger/core.js';
import type { PluginMetadata } from '../vite-plugin-astro/types'; import type { PluginMetadata } from '../vite-plugin-astro/types';
import babel from '@babel/core'; import babel from '@babel/core';
@ -73,7 +73,7 @@ async function transformJSX({
interface AstroPluginJSXOptions { interface AstroPluginJSXOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
} }
// Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54 // Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54

View file

@ -1,25 +1,23 @@
import type { Plugin as VitePlugin } from 'vite'; import type { Plugin as VitePlugin } from 'vite';
import type { AstroSettings } from '../@types/astro.js'; import type { AstroSettings } from '../@types/astro.js';
import { type LogOptions } from '../core/logger/core.js'; import { type Logger } from '../core/logger/core.js';
import { bold } from 'kleur/colors'; import { bold } from 'kleur/colors';
import { extname } from 'node:path'; import { extname } from 'node:path';
import { normalizePath } from 'vite'; import { normalizePath } from 'vite';
import { warn } from '../core/logger/core.js';
import { isEndpoint, isPage, rootRelativePath } from '../core/util.js'; import { isEndpoint, isPage, rootRelativePath } from '../core/util.js';
import { getPrerenderDefault, isServerLikeOutput } from '../prerender/utils.js'; import { getPrerenderDefault, isServerLikeOutput } from '../prerender/utils.js';
import { scan } from './scan.js'; import { scan } from './scan.js';
export interface AstroPluginScannerOptions { export interface AstroPluginScannerOptions {
settings: AstroSettings; settings: AstroSettings;
logging: LogOptions; logger: Logger;
} }
const KNOWN_FILE_EXTENSIONS = ['.astro', '.js', '.ts']; const KNOWN_FILE_EXTENSIONS = ['.astro', '.js', '.ts'];
export default function astroScannerPlugin({ export default function astroScannerPlugin({
settings, settings,
logging, logger,
}: AstroPluginScannerOptions): VitePlugin { }: AstroPluginScannerOptions): VitePlugin {
return { return {
name: 'astro:scanner', name: 'astro:scanner',
@ -55,8 +53,7 @@ export default function astroScannerPlugin({
KNOWN_FILE_EXTENSIONS.includes(extname(filename)) KNOWN_FILE_EXTENSIONS.includes(extname(filename))
) { ) {
const reason = ` because \`output: "${settings.config.output}"\` is set`; const reason = ` because \`output: "${settings.config.output}"\` is set`;
warn( logger.warn(
logging,
'getStaticPaths', 'getStaticPaths',
`The getStaticPaths() statement in ${bold( `The getStaticPaths() statement in ${bold(
rootRelativePath(settings.config.root, fileURL, true) rootRelativePath(settings.config.root, fileURL, true)

View file

@ -6,6 +6,7 @@ import { removeDir } from '../dist/core/fs/index.js';
import testAdapter from './test-adapter.js'; import testAdapter from './test-adapter.js';
import { testImageService } from './test-image-service.js'; import { testImageService } from './test-image-service.js';
import { loadFixture } from './test-utils.js'; import { loadFixture } from './test-utils.js';
import { Logger } from '../dist/core/logger/core.js';
describe('astro:image', () => { describe('astro:image', () => {
/** @type {import('./test-utils').Fixture} */ /** @type {import('./test-utils').Fixture} */
@ -27,7 +28,7 @@ describe('astro:image', () => {
}); });
devServer = await fixture.startDevServer({ devServer = await fixture.startDevServer({
logging: { logger: new Logger({
level: 'error', level: 'error',
dest: new Writable({ dest: new Writable({
objectMode: true, objectMode: true,
@ -36,7 +37,7 @@ describe('astro:image', () => {
callback(); callback();
}, },
}), }),
}, }),
}); });
}); });
@ -447,7 +448,7 @@ describe('astro:image', () => {
}); });
devServer = await fixture.startDevServer({ devServer = await fixture.startDevServer({
logging: { logger: new Logger({
level: 'error', level: 'error',
dest: new Writable({ dest: new Writable({
objectMode: true, objectMode: true,
@ -456,7 +457,7 @@ describe('astro:image', () => {
callback(); callback();
}, },
}), }),
}, }),
}); });
}); });

View file

@ -1,6 +1,7 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { load as cheerioLoad } from 'cheerio'; import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from './test-utils.js'; import { loadFixture } from './test-utils.js';
import { Logger } from '../dist/core/logger/core.js';
function addLeadingSlash(path) { function addLeadingSlash(path) {
return path.startsWith('/') ? path : '/' + path; return path.startsWith('/') ? path : '/' + path;
@ -22,22 +23,22 @@ describe('Static build', () => {
let logs = []; let logs = [];
before(async () => { before(async () => {
/** @type {import('../src/core/logger/core').LogOptions} */ /** @type {import('../src/core/logger/core').Logger} */
const logging = { const logger = new Logger({
dest: { dest: {
write(chunk) { write(chunk) {
logs.push(chunk); logs.push(chunk);
}, },
}, },
level: 'warn', level: 'warn',
}; });
fixture = await loadFixture({ fixture = await loadFixture({
root: './fixtures/static-build/', root: './fixtures/static-build/',
// test suite was authored when inlineStylesheets defaulted to never // test suite was authored when inlineStylesheets defaulted to never
build: { inlineStylesheets: 'never' }, build: { inlineStylesheets: 'never' },
}); });
await fixture.build({ logging }); await fixture.build({ logger });
}); });
it('Builds out .astro pages', async () => { it('Builds out .astro pages', async () => {

View file

@ -1,7 +1,7 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { runHookBuildSetup } from '../../../dist/integrations/index.js'; import { runHookBuildSetup } from '../../../dist/integrations/index.js';
import { validateSupportedFeatures } from '../../../dist/integrations/astroFeaturesValidation.js'; import { validateSupportedFeatures } from '../../../dist/integrations/astroFeaturesValidation.js';
import { defaultLogging } from '../test-utils.js'; import { defaultLogger } from '../test-utils.js';
describe('Integration API', () => { describe('Integration API', () => {
it('runHookBuildSetup should work', async () => { it('runHookBuildSetup should work', async () => {
@ -23,7 +23,7 @@ describe('Integration API', () => {
], ],
}, },
vite: {}, vite: {},
logging: {}, logger: defaultLogger,
pages: new Map(), pages: new Map(),
target: 'server', target: 'server',
}); });
@ -41,7 +41,7 @@ describe('Astro feature map', function () {
{ {
output: 'hybrid', output: 'hybrid',
}, },
defaultLogging defaultLogger
); );
expect(result['hybridOutput']).to.be.true; expect(result['hybridOutput']).to.be.true;
}); });
@ -53,7 +53,7 @@ describe('Astro feature map', function () {
{ {
output: 'hybrid', output: 'hybrid',
}, },
defaultLogging defaultLogger
); );
expect(result['hybridOutput']).to.be.false; expect(result['hybridOutput']).to.be.false;
}); });
@ -65,7 +65,7 @@ describe('Astro feature map', function () {
{ {
output: 'hybrid', output: 'hybrid',
}, },
defaultLogging defaultLogger
); );
expect(result['hybridOutput']).to.be.false; expect(result['hybridOutput']).to.be.false;
}); });
@ -78,7 +78,7 @@ describe('Astro feature map', function () {
{ {
output: 'static', output: 'static',
}, },
defaultLogging defaultLogger
); );
expect(result['staticOutput']).to.be.true; expect(result['staticOutput']).to.be.true;
}); });
@ -90,7 +90,7 @@ describe('Astro feature map', function () {
{ {
output: 'static', output: 'static',
}, },
defaultLogging defaultLogger
); );
expect(result['staticOutput']).to.be.false; expect(result['staticOutput']).to.be.false;
}); });
@ -103,7 +103,7 @@ describe('Astro feature map', function () {
{ {
output: 'hybrid', output: 'hybrid',
}, },
defaultLogging defaultLogger
); );
expect(result['hybridOutput']).to.be.true; expect(result['hybridOutput']).to.be.true;
}); });
@ -117,7 +117,7 @@ describe('Astro feature map', function () {
{ {
output: 'hybrid', output: 'hybrid',
}, },
defaultLogging defaultLogger
); );
expect(result['hybridOutput']).to.be.false; expect(result['hybridOutput']).to.be.false;
}); });
@ -130,7 +130,7 @@ describe('Astro feature map', function () {
{ {
output: 'server', output: 'server',
}, },
defaultLogging defaultLogger
); );
expect(result['serverOutput']).to.be.true; expect(result['serverOutput']).to.be.true;
}); });
@ -144,7 +144,7 @@ describe('Astro feature map', function () {
{ {
output: 'server', output: 'server',
}, },
defaultLogging defaultLogger
); );
expect(result['serverOutput']).to.be.false; expect(result['serverOutput']).to.be.false;
}); });
@ -167,7 +167,7 @@ describe('Astro feature map', function () {
}, },
}, },
}, },
defaultLogging defaultLogger
); );
expect(result['assets']).to.be.true; expect(result['assets']).to.be.true;
}); });
@ -187,7 +187,7 @@ describe('Astro feature map', function () {
}, },
}, },
}, },
defaultLogging defaultLogger
); );
expect(result['assets']).to.be.true; expect(result['assets']).to.be.true;
}); });
@ -208,7 +208,7 @@ describe('Astro feature map', function () {
}, },
}, },
}, },
defaultLogging defaultLogger
); );
expect(result['assets']).to.be.false; expect(result['assets']).to.be.false;
}); });

View file

@ -2,7 +2,7 @@ import { expect } from 'chai';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { createRouteManifest } from '../../../dist/core/routing/manifest/create.js'; import { createRouteManifest } from '../../../dist/core/routing/manifest/create.js';
import { createBasicSettings, createFs, defaultLogging } from '../test-utils.js'; import { createBasicSettings, createFs, defaultLogger } from '../test-utils.js';
const root = new URL('../../fixtures/alias/', import.meta.url); const root = new URL('../../fixtures/alias/', import.meta.url);
@ -77,7 +77,7 @@ describe('routing - createRouteManifest', () => {
settings, settings,
fsMod: fs, fsMod: fs,
}, },
defaultLogging defaultLogger
); );
expect(manifest.routes[0].route).to.equal('/foo'); expect(manifest.routes[0].route).to.equal('/foo');

View file

@ -2,7 +2,7 @@ import {
createBasicSettings, createBasicSettings,
createFs, createFs,
createRequestAndResponse, createRequestAndResponse,
defaultLogging, defaultLogger,
} from '../test-utils.js'; } from '../test-utils.js';
import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js'; import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
@ -140,19 +140,19 @@ describe('Route matching', () => {
container = await createContainer({ container = await createContainer({
fs, fs,
settings, settings,
logging: defaultLogging, logger: defaultLogger,
}); });
const loader = createViteLoader(container.viteServer); const loader = createViteLoader(container.viteServer);
const manifest = createDevelopmentManifest(container.settings); const manifest = createDevelopmentManifest(container.settings);
pipeline = new DevPipeline({ manifest, logging: defaultLogging, settings, loader }); pipeline = new DevPipeline({ manifest, logger: defaultLogger, settings, loader });
manifestData = createRouteManifest( manifestData = createRouteManifest(
{ {
cwd: fileURLToPath(root), cwd: fileURLToPath(root),
settings, settings,
fsMod: fs, fsMod: fs,
}, },
defaultLogging defaultLogger
); );
}); });

View file

@ -2,7 +2,7 @@ import { expect } from 'chai';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { createContainer } from '../../../dist/core/dev/index.js'; import { createContainer } from '../../../dist/core/dev/index.js';
import { createViteLoader } from '../../../dist/core/module-loader/index.js'; import { createViteLoader } from '../../../dist/core/module-loader/index.js';
import { createBasicSettings, defaultLogging } from '../test-utils.js'; import { createBasicSettings, defaultLogger } from '../test-utils.js';
const root = new URL('../../fixtures/alias/', import.meta.url); const root = new URL('../../fixtures/alias/', import.meta.url);
@ -12,7 +12,7 @@ describe('<Code />', () => {
let mod; let mod;
before(async () => { before(async () => {
const settings = await createBasicSettings({ root: fileURLToPath(root) }); const settings = await createBasicSettings({ root: fileURLToPath(root) });
container = await createContainer({ settings, logging: defaultLogging }); container = await createContainer({ settings, logger: defaultLogger });
const loader = createViteLoader(container.viteServer); const loader = createViteLoader(container.viteServer);
mod = await loader.import('astro/components/Shiki.js'); mod = await loader.import('astro/components/Shiki.js');
}); });

View file

@ -12,12 +12,13 @@ import { resolveConfig } from '../../dist/core/config/index.js';
import { createBaseSettings } from '../../dist/core/config/settings.js'; import { createBaseSettings } from '../../dist/core/config/settings.js';
import { createContainer } from '../../dist/core/dev/container.js'; import { createContainer } from '../../dist/core/dev/container.js';
import { unixify } from './correct-path.js'; import { unixify } from './correct-path.js';
import { Logger } from '../../dist/core/logger/core.js';
/** @type {import('../../src/core/logger/core').LogOptions} */ /** @type {import('../../src/core/logger/core').Logger} */
export const defaultLogging = { export const defaultLogger = new Logger({
dest: nodeLogDestination, dest: nodeLogDestination,
level: 'error', level: 'error',
}; });
/** @type {import('../../src/core/logger/core').LogOptions} */ /** @type {import('../../src/core/logger/core').LogOptions} */
export const silentLogging = { export const silentLogging = {
@ -187,7 +188,7 @@ export function createBasicEnvironment(options = {}) {
clientDirectives: getDefaultClientDirectives(), clientDirectives: getDefaultClientDirectives(),
resolve: options.resolve ?? ((s) => Promise.resolve(s)), resolve: options.resolve ?? ((s) => Promise.resolve(s)),
routeCache: new RouteCache(options.logging, mode), routeCache: new RouteCache(options.logging, mode),
logging: options.logging ?? defaultLogging, logger: options.logger ?? defaultLogger,
ssr: options.ssr ?? true, ssr: options.ssr ?? true,
streaming: options.streaming ?? true, streaming: options.streaming ?? true,
}); });
@ -223,7 +224,7 @@ export async function runInContainer(options = {}, callback) {
fs: options?.fs ?? realFS, fs: options?.fs ?? realFS,
settings, settings,
inlineConfig: options.inlineConfig ?? {}, inlineConfig: options.inlineConfig ?? {},
logging: defaultLogging, logger: defaultLogger,
}); });
try { try {
await callback(container); await callback(container);

View file

@ -8,7 +8,7 @@ import {
createBasicSettings, createBasicSettings,
createFs, createFs,
createRequestAndResponse, createRequestAndResponse,
defaultLogging, defaultLogger,
} from '../test-utils.js'; } from '../test-utils.js';
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js'; import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
import DevPipeline from '../../../dist/vite-plugin-astro-server/devPipeline.js'; import DevPipeline from '../../../dist/vite-plugin-astro-server/devPipeline.js';
@ -21,7 +21,7 @@ async function createDevPipeline(overrides = {}) {
return new DevPipeline({ return new DevPipeline({
manifest, manifest,
settings, settings,
logging: defaultLogging, logging: defaultLogger,
loader, loader,
}); });
} }
@ -53,7 +53,7 @@ describe('vite-plugin-astro-server', () => {
fsMod: fs, fsMod: fs,
settings: pipeline.getSettings(), settings: pipeline.getSettings(),
}, },
defaultLogging defaultLogger
); );
try { try {