From f91acd8fcae91cad2429c477310acfa2a2adc2c5 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 25 Aug 2023 15:57:47 +0100 Subject: [PATCH] refactor: internal refactor to use the `Logger` (#8227) --- packages/astro/src/@types/astro.ts | 6 +- packages/astro/src/assets/build/generate.ts | 36 ++--- packages/astro/src/cli/add/index.ts | 102 +++++++------- packages/astro/src/cli/check/index.ts | 14 +- packages/astro/src/cli/flags.ts | 6 +- packages/astro/src/cli/install-package.ts | 16 +-- packages/astro/src/config/index.ts | 14 +- .../src/config/vite-plugin-content-listen.ts | 8 +- .../astro/src/content/server-listeners.ts | 39 +++--- packages/astro/src/content/types-generator.ts | 23 ++-- packages/astro/src/core/app/index.ts | 14 +- .../astro/src/core/build/buildPipeline.ts | 7 +- packages/astro/src/core/build/generate.ts | 62 ++++----- packages/astro/src/core/build/index.ts | 69 +++++----- packages/astro/src/core/build/page-data.ts | 10 +- .../src/core/build/plugins/plugin-manifest.ts | 2 +- packages/astro/src/core/build/static-build.ts | 17 ++- packages/astro/src/core/build/types.ts | 4 +- packages/astro/src/core/config/index.ts | 2 +- packages/astro/src/core/config/logging.ts | 11 +- packages/astro/src/core/create-vite.ts | 22 ++-- packages/astro/src/core/dev/container.ts | 24 ++-- packages/astro/src/core/dev/dev.ts | 10 +- packages/astro/src/core/dev/restart.ts | 19 ++- packages/astro/src/core/endpoint/index.ts | 19 +-- packages/astro/src/core/logger/core.ts | 12 +- .../src/core/middleware/callMiddleware.ts | 6 +- packages/astro/src/core/pipeline.ts | 2 +- packages/astro/src/core/preview/index.ts | 10 +- .../src/core/preview/static-preview-server.ts | 10 +- packages/astro/src/core/render/context.ts | 2 +- packages/astro/src/core/render/core.ts | 8 +- packages/astro/src/core/render/environment.ts | 4 +- .../astro/src/core/render/params-and-props.ts | 10 +- packages/astro/src/core/render/result.ts | 15 +-- packages/astro/src/core/render/route-cache.ts | 22 ++-- packages/astro/src/core/request.ts | 12 +- .../astro/src/core/routing/manifest/create.ts | 9 +- packages/astro/src/core/routing/validation.ts | 11 +- packages/astro/src/core/sync/index.ts | 24 ++-- .../integrations/astroFeaturesValidation.ts | 47 +++---- packages/astro/src/integrations/index.ts | 124 +++++++++--------- packages/astro/src/runtime/server/endpoint.ts | 11 +- .../src/vite-plugin-astro-server/base.ts | 11 +- .../src/vite-plugin-astro-server/common.ts | 6 +- .../vite-plugin-astro-server/devPipeline.ts | 18 ++- .../vite-plugin-astro-server/environment.ts | 31 ----- .../src/vite-plugin-astro-server/plugin.ts | 14 +- .../src/vite-plugin-astro-server/route.ts | 10 +- .../astro/src/vite-plugin-astro/compile.ts | 10 +- packages/astro/src/vite-plugin-astro/hmr.ts | 14 +- packages/astro/src/vite-plugin-astro/index.ts | 10 +- .../src/vite-plugin-inject-env-ts/index.ts | 18 +-- .../index.ts | 8 +- .../astro/src/vite-plugin-markdown/index.ts | 10 +- packages/astro/src/vite-plugin-mdx/index.ts | 4 +- .../astro/src/vite-plugin-scanner/index.ts | 11 +- packages/astro/test/core-image.test.js | 9 +- packages/astro/test/static-build.test.js | 9 +- .../astro/test/units/integrations/api.test.js | 28 ++-- .../astro/test/units/routing/manifest.test.js | 4 +- .../test/units/routing/route-matching.test.js | 8 +- packages/astro/test/units/shiki/shiki.test.js | 4 +- packages/astro/test/units/test-utils.js | 11 +- .../vite-plugin-astro-server/request.test.js | 6 +- 65 files changed, 529 insertions(+), 620 deletions(-) delete mode 100644 packages/astro/src/vite-plugin-astro-server/environment.ts diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 3231b6622..302616fde 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -20,7 +20,7 @@ import type { AstroConfigType } from '../core/config'; import type { AstroTimer } from '../core/config/timer'; import type { AstroCookies } from '../core/cookies'; 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 { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js'; @@ -1399,7 +1399,7 @@ export interface AstroInlineOnlyConfig { /** * @internal for testing only, use `logLevel` instead. */ - logging?: LogOptions; + logger?: Logger; } export type ContentEntryModule = { @@ -2067,7 +2067,7 @@ export type AstroMiddlewareInstance = { export interface AstroPluginOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; } export type RouteType = 'page' | 'endpoint' | 'redirect'; diff --git a/packages/astro/src/assets/build/generate.ts b/packages/astro/src/assets/build/generate.ts index b78800a43..fe7b093b5 100644 --- a/packages/astro/src/assets/build/generate.ts +++ b/packages/astro/src/assets/build/generate.ts @@ -1,13 +1,12 @@ import fs, { readFileSync } from 'node:fs'; 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 { isServerLikeOutput } from '../../prerender/utils.js'; import { getConfiguredImageService, isESMImportedImage } from '../internal.js'; import type { LocalImageService } from '../services/service.js'; import type { ImageMetadata, ImageTransform } from '../types.js'; import { loadRemoteImage, type RemoteCacheEntry } from './remote.js'; +import type { BuildPipeline } from '../../core/build/buildPipeline'; interface GenerationDataUncached { cached: false; @@ -24,19 +23,20 @@ interface GenerationDataCached { type GenerationData = GenerationDataUncached | GenerationDataCached; export async function generateImage( - buildOpts: StaticBuildOptions, + pipeline: BuildPipeline, options: ImageTransform, filepath: string ): Promise { + const config = pipeline.getConfig(); + const logger = pipeline.getLogger(); 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 try { await fs.promises.mkdir(assetsCacheDir, { recursive: true }); } catch (err) { - warn( - buildOpts.logging, + logger.warn( 'astro:assets', `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; - if (isServerLikeOutput(buildOpts.settings.config)) { - serverRoot = buildOpts.settings.config.build.server; - clientRoot = buildOpts.settings.config.build.client; + if (isServerLikeOutput(config)) { + serverRoot = config.build.server; + clientRoot = config.build.client; } else { - serverRoot = buildOpts.settings.config.outDir; - clientRoot = buildOpts.settings.config.outDir; + serverRoot = config.outDir; + clientRoot = config.outDir; } const isLocalImage = isESMImportedImage(options.src); @@ -105,10 +105,7 @@ export async function generateImage( if (isLocalImage) { imageData = await fs.promises.readFile( new URL( - '.' + - prependForwardSlash( - join(buildOpts.settings.config.build.assets, basename(originalImagePath)) - ), + '.' + prependForwardSlash(join(config.build.assets, basename(originalImagePath))), serverRoot ) ); @@ -120,11 +117,7 @@ export async function generateImage( const imageService = (await getConfiguredImageService()) as LocalImageService; resultData.data = ( - await imageService.transform( - imageData, - { ...options, src: originalImagePath }, - buildOpts.settings.config.image - ) + await imageService.transform(imageData, { ...options, src: originalImagePath }, config.image) ).data; try { @@ -143,8 +136,7 @@ export async function generateImage( } } } catch (e) { - warn( - buildOpts.logging, + logger.warn( 'astro:assets', `An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}` ); diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts index fcaeb07c7..07fc7b1a8 100644 --- a/packages/astro/src/cli/add/index.ts +++ b/packages/astro/src/cli/add/index.ts @@ -16,14 +16,14 @@ import { updateTSConfigForFramework, type frameworkWithTSSettings, } 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 { printHelp } from '../../core/messages.js'; import { appendForwardSlash } from '../../core/path.js'; import { apply as applyPolyfill } from '../../core/polyfill.js'; import { parseNpmName } from '../../core/util.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 { ensureImport } from './imports.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. 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 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 root = pathToFileURL(rootPath); // 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')) { await setupIntegrationConfig({ root, - logging, + logger, + flags, integrationName: 'Tailwind', possibleConfigFiles: [ @@ -159,7 +160,7 @@ export async function add(names: string[], { flags }: AddOptions) { if (integrations.find((integration) => integration.id === 'svelte')) { await setupIntegrationConfig({ root, - logging, + logger, flags, integrationName: 'Svelte', possibleConfigFiles: ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'], @@ -175,7 +176,7 @@ export async function add(names: string[], { flags }: AddOptions) { ) { await setupIntegrationConfig({ root, - logging, + logger, flags, integrationName: 'Lit', possibleConfigFiles: ['./.npmrc'], @@ -186,8 +187,7 @@ export async function add(names: string[], { flags }: AddOptions) { break; } case UpdateResult.cancelled: { - info( - logging, + logger.info( null, msg.cancelled( `Dependencies ${bold('NOT')} installed.`, @@ -209,9 +209,9 @@ export async function add(names: string[], { flags }: AddOptions) { let configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined; if (configURL) { - debug('add', `Found config at ${configURL}`); + logger.debug('add', `Found config at ${configURL}`); } 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); await fs.writeFile(fileURLToPath(configURL), ASTRO_CONFIG_STUB, { encoding: 'utf-8' }); } @@ -220,7 +220,7 @@ export async function add(names: string[], { flags }: AddOptions) { try { ast = await parseAstroConfig(configURL); - debug('add', 'Parsed astro config'); + logger.debug('add', 'Parsed astro config'); const defineConfig = t.identifier('defineConfig'); ensureImport( @@ -232,7 +232,7 @@ export async function add(names: string[], { flags }: AddOptions) { ); wrapDefaultExport(ast, defineConfig); - debug('add', 'Astro config ensured `defineConfig`'); + logger.debug('add', 'Astro config ensured `defineConfig`'); for (const integration of integrations) { if (isAdapter(integration)) { @@ -240,8 +240,7 @@ export async function add(names: string[], { flags }: AddOptions) { if (officialExportName) { await setAdapter(ast, integration, officialExportName); } else { - info( - logging, + logger.info( null, `\n ${magenta( `Check our deployment docs for ${bold( @@ -253,10 +252,10 @@ export async function add(names: string[], { flags }: AddOptions) { } else { await addIntegration(ast, integration); } - debug('add', `Astro config added integration ${integration.id}`); + logger.debug('add', `Astro config added integration ${integration.id}`); } } catch (err) { - debug('add', 'Error parsing/modifying astro config: ', err); + logger.debug('add', 'Error parsing/modifying astro config: ', err); throw createPrettyError(err as Error); } @@ -268,18 +267,18 @@ export async function add(names: string[], { flags }: AddOptions) { configURL, ast, flags, - logging, + logger, logAdapterInstructions: integrations.some(isAdapter), }); } catch (err) { - debug('add', 'Error updating astro config', err); + logger.debug('add', 'Error updating astro config', err); throw createPrettyError(err as Error); } } switch (configResult) { 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; } case UpdateResult.none: { @@ -293,18 +292,17 @@ export async function add(names: string[], { flags }: AddOptions) { (integration) => !deps.includes(integration.packageName) ); if (missingDeps.length === 0) { - info(logging, null, msg.success(`Configuration up-to-date.`)); + logger.info(null, msg.success(`Configuration up-to-date.`)); break; } } - info(logging, null, msg.success(`Configuration up-to-date.`)); + logger.info(null, msg.success(`Configuration up-to-date.`)); break; } default: { const list = integrations.map((integration) => ` - ${integration.packageName}`).join('\n'); - info( - logging, + logger.info( null, msg.success( `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) { case UpdateResult.none: { break; } case UpdateResult.cancelled: { - info( - logging, + logger.info( null, msg.cancelled(`Your TypeScript configuration has ${bold('NOT')} been updated.`) ); @@ -335,7 +332,7 @@ export async function add(names: string[], { flags }: AddOptions) { ); } 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, ast, flags, - logging, + logger, logAdapterInstructions, }: { configURL: URL; ast: t.File; flags: yargs.Arguments; - logging: LogOptions; + logger: Logger; logAdapterInstructions: boolean; }): Promise { const input = await fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' }); @@ -562,15 +559,13 @@ async function updateAstroConfig({ title: configURL.pathname.split('/').pop(), })}\n`; - info( - logging, + logger.info( null, `\n ${magenta('Astro will make the following changes to your config file:')}\n${message}` ); if (logAdapterInstructions) { - info( - logging, + logger.info( null, magenta( ` For complete deployment options, visit\n ${bold( @@ -582,7 +577,7 @@ async function updateAstroConfig({ if (await askToContinue({ flags })) { await fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' }); - debug('add', `Updated astro config`); + logger.debug('add', `Updated astro config`); return UpdateResult.updated; } else { return UpdateResult.cancelled; @@ -598,13 +593,15 @@ interface InstallCommand { async function getInstallIntegrationsCommand({ integrations, + logger, cwd = process.cwd(), }: { integrations: IntegrationInfo[]; + logger: Logger; cwd?: string; }): Promise { const pm = await preferredPM(cwd); - debug('add', `package manager: ${JSON.stringify(pm)}`); + logger.debug('add', `package manager: ${JSON.stringify(pm)}`); if (!pm) return null; let dependencies = integrations @@ -644,14 +641,14 @@ async function tryToInstallIntegrations({ integrations, cwd, flags, - logging, + logger, }: { integrations: IntegrationInfo[]; cwd?: string; flags: yargs.Arguments; - logging: LogOptions; + logger: Logger; }): Promise { - const installCommand = await getInstallIntegrationsCommand({ integrations, cwd }); + const installCommand = await getInstallIntegrationsCommand({ integrations, cwd, logger }); const inheritedFlags = Object.entries(flags) .map(([flag]) => { @@ -677,8 +674,7 @@ async function tryToInstallIntegrations({ padding: 0.5, borderStyle: 'round', })}\n`; - info( - logging, + logger.info( null, `\n ${magenta('Astro will run the following command:')}\n ${dim( 'If you skip this step, you can always run it yourself later' @@ -702,7 +698,7 @@ async function tryToInstallIntegrations({ return UpdateResult.updated; } catch (err) { spinner.fail(); - debug('add', 'Error installing dependencies', err); + logger.debug('add', 'Error installing dependencies', err); // eslint-disable-next-line no-console console.error('\n', (err as any).stdout, '\n'); return UpdateResult.failure; @@ -829,7 +825,7 @@ export async function validateIntegrations(integrations: string[]): Promise { @@ -852,7 +848,7 @@ async function updateTSConfig( } 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( @@ -875,8 +871,7 @@ async function updateTSConfig( title: configFileName, })}\n`; - info( - logging, + logger.info( null, `\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; if (hasConflictingIntegrations) { - info( - logging, + logger.info( null, red( ` ${bold( @@ -907,7 +901,7 @@ async function updateTSConfig( await fs.writeFile(inputConfig?.path ?? path.join(cwd, 'tsconfig.json'), output, { encoding: 'utf-8', }); - debug('add', `Updated ${configFileName} file`); + logger.debug('add', `Updated ${configFileName} file`); return UpdateResult.updated; } else { return UpdateResult.cancelled; @@ -971,13 +965,14 @@ function getDiffContent(input: string, output: string): string | null { async function setupIntegrationConfig(opts: { root: URL; - logging: LogOptions; + logger: Logger; flags: yargs.Arguments; integrationName: string; possibleConfigFiles: string[]; defaultConfigFile: string; defaultConfigContent: string; }) { + const logger = opts.logger; const possibleConfigFiles = opts.possibleConfigFiles.map((p) => fileURLToPath(new URL(p, opts.root)) ); @@ -989,8 +984,7 @@ async function setupIntegrationConfig(opts: { } } if (!alreadyConfigured) { - info( - opts.logging, + logger.info( null, `\n ${magenta(`Astro will generate a minimal ${bold(opts.defaultConfigFile)} file.`)}\n` ); @@ -1002,9 +996,9 @@ async function setupIntegrationConfig(opts: { encoding: 'utf-8', } ); - debug('add', `Generated default ${opts.defaultConfigFile} file`); + logger.debug('add', `Generated default ${opts.defaultConfigFile} file`); } } else { - debug('add', `Using existing ${opts.integrationName} configuration`); + logger.debug('add', `Using existing ${opts.integrationName} configuration`); } } diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index 6ae11d576..6ce3bf71e 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -1,23 +1,21 @@ import path from 'node:path'; import type { Arguments } from 'yargs-parser'; -import { error, info } from '../../core/logger/core.js'; -import { createLoggingFromFlags, flagsToAstroInlineConfig } from '../flags.js'; +import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; import { getPackage } from '../install-package.js'; 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 checkPackage = await getPackage( '@astrojs/check', - logging, + logger, getPackageOpts, ['typescript'] ); - const typescript = await getPackage('typescript', logging, getPackageOpts); + const typescript = await getPackage('typescript', logger, getPackageOpts); if (!checkPackage || !typescript) { - error( - logging, + logger.error( 'check', '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); - 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); } diff --git a/packages/astro/src/cli/flags.ts b/packages/astro/src/cli/flags.ts index 3d7360a29..54177e998 100644 --- a/packages/astro/src/cli/flags.ts +++ b/packages/astro/src/cli/flags.ts @@ -1,6 +1,6 @@ import type { Arguments as Flags } from 'yargs-parser'; 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'; 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` * 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 = { dest: nodeLogDestination, level: 'info', @@ -42,5 +42,5 @@ export function createLoggingFromFlags(flags: Flags): LogOptions { logging.level = 'silent'; } - return logging; + return new Logger(logging); } diff --git a/packages/astro/src/cli/install-package.ts b/packages/astro/src/cli/install-package.ts index 8793d9985..919ede0e2 100644 --- a/packages/astro/src/cli/install-package.ts +++ b/packages/astro/src/cli/install-package.ts @@ -5,7 +5,7 @@ import { createRequire } from 'node:module'; import ora from 'ora'; import prompts from 'prompts'; 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 = { skipAsk?: boolean; @@ -14,7 +14,7 @@ type GetPackageOptions = { export async function getPackage( packageName: string, - logging: LogOptions, + logger: Logger, options: GetPackageOptions, otherDeps: string[] = [] ): Promise { @@ -27,12 +27,11 @@ export async function getPackage( // The `require.resolve` is required as to avoid Node caching the failed `import` packageImport = await import(packageName); } catch (e) { - info( - logging, + logger.info( '', `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) { packageImport = await import(packageName); @@ -60,7 +59,7 @@ function getInstallCommand(packages: string[], packageManager: string) { async function installPackage( packageNames: string[], options: GetPackageOptions, - logging: LogOptions + logger: Logger ): Promise { const cwd = options.cwd ?? process.cwd(); const packageManager = (await whichPm(cwd)).name ?? 'npm'; @@ -79,8 +78,7 @@ async function installPackage( padding: 0.5, borderStyle: 'round', })}\n`; - info( - logging, + logger.info( null, `\n ${magenta('Astro will run the following command:')}\n ${dim( 'If you skip this step, you can always run it yourself later' @@ -113,7 +111,7 @@ async function installPackage( return true; } catch (err) { - debug('add', 'Error installing dependencies', err); + logger.debug('add', 'Error installing dependencies', err); spinner.fail(); return false; diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index d32af35b8..c5f045a5f 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,6 +1,6 @@ import type { UserConfig } from 'vite'; import type { AstroUserConfig } from '../@types/astro'; -import type { LogOptions } from '../core/logger/core'; +import { Logger } from '../core/logger/core'; export function defineConfig(config: AstroUserConfig) { return config; @@ -30,24 +30,24 @@ export function getViteConfig(inlineConfig: UserConfig) { import('../integrations/index.js'), import('./vite-plugin-content-listen.js'), ]); - const logging: LogOptions = { + const logger = new Logger({ dest: nodeLogDestination, level: 'info', - }; + }); const { astroConfig: config } = await resolveConfig({}, cmd); const settings = createSettings(config, inlineConfig.root); - await runHookConfigSetup({ settings, command: cmd, logging }); + await runHookConfigSetup({ settings, command: cmd, logger }); const viteConfig = await createVite( { mode, plugins: [ // 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); }; } diff --git a/packages/astro/src/config/vite-plugin-content-listen.ts b/packages/astro/src/config/vite-plugin-content-listen.ts index ecd9ea68b..bb3cd9d2b 100644 --- a/packages/astro/src/config/vite-plugin-content-listen.ts +++ b/packages/astro/src/config/vite-plugin-content-listen.ts @@ -2,7 +2,7 @@ import type fsMod from 'node:fs'; import type { Plugin, ViteDevServer } from 'vite'; import type { AstroSettings } from '../@types/astro'; 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. @@ -14,11 +14,11 @@ import type { LogOptions } from '../core/logger/core.js'; */ export function astroContentListenPlugin({ settings, - logging, + logger, fs, }: { settings: AstroSettings; - logging: LogOptions; + logger: Logger; fs: typeof fsMod; }): Plugin { let server: ViteDevServer; @@ -33,7 +33,7 @@ export function astroContentListenPlugin({ await attachContentServerListeners({ fs: fs, settings, - logging, + logger, viteServer: server, }); }, diff --git a/packages/astro/src/content/server-listeners.ts b/packages/astro/src/content/server-listeners.ts index 53deffaf8..c5e3da2c4 100644 --- a/packages/astro/src/content/server-listeners.ts +++ b/packages/astro/src/content/server-listeners.ts @@ -5,14 +5,14 @@ import { fileURLToPath, pathToFileURL } from 'node:url'; import type { ViteDevServer } from 'vite'; import type { AstroSettings } from '../@types/astro.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 { createContentTypesGenerator } from './types-generator.js'; import { getContentPaths, globalContentConfigObserver, type ContentPaths } from './utils.js'; interface ContentServerListenerParams { fs: typeof fsMod; - logging: LogOptions; + logger: Logger; settings: AstroSettings; viteServer: ViteDevServer; } @@ -20,27 +20,26 @@ interface ContentServerListenerParams { export async function attachContentServerListeners({ viteServer, fs, - logging, + logger, settings, }: ContentServerListenerParams) { const contentPaths = getContentPaths(settings.config, fs); if (fs.existsSync(contentPaths.contentDir)) { - info( - logging, + logger.info( 'content', `Watching ${cyan( contentPaths.contentDir.href.replace(settings.config.root.href, '') )} for changes` ); const maybeTsConfigStats = getTSConfigStatsWhenAllowJsFalse({ contentPaths, settings }); - if (maybeTsConfigStats) warnAllowJsIsFalse({ ...maybeTsConfigStats, logging }); + if (maybeTsConfigStats) warnAllowJsIsFalse({ ...maybeTsConfigStats, logger }); await attachListeners(); } else { viteServer.watcher.on('addDir', contentDirListener); async function contentDirListener(dir: string) { 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(); viteServer.watcher.removeListener('addDir', contentDirListener); } @@ -51,12 +50,12 @@ export async function attachContentServerListeners({ const contentGenerator = await createContentTypesGenerator({ fs, settings, - logging, + logger, viteServer, contentConfigObserver: globalContentConfigObserver, }); await contentGenerator.init(); - info(logging, 'content', 'Types generated'); + logger.info('content', 'Types generated'); viteServer.watcher.on('add', (entry) => { contentGenerator.queueEvent({ name: 'add', entry }); @@ -77,26 +76,24 @@ export async function attachContentServerListeners({ } function warnAllowJsIsFalse({ - logging, + logger, tsConfigFileName, contentConfigFileName, }: { - logging: LogOptions; + logger: Logger; tsConfigFileName: string; contentConfigFileName: string; }) { - if (!['info', 'warn'].includes(logging.level)) - warn( - logging, - 'content', - `Make sure you have the ${bold('allowJs')} compiler option set to ${bold( - 'true' - )} in your ${bold(tsConfigFileName)} file to have autocompletion in your ${bold( - contentConfigFileName - )} file. + logger.warn( + 'content', + `Make sure you have the ${bold('allowJs')} compiler option set to ${bold( + 'true' + )} in your ${bold(tsConfigFileName)} file to have autocompletion in your ${bold( + contentConfigFileName + )} file. See ${bold('https://www.typescriptlang.org/tsconfig#allowJs')} for more information. ` - ); + ); } function getTSConfigStatsWhenAllowJsFalse({ diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index 078197cd0..105672a86 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -7,7 +7,6 @@ import { normalizePath, type ViteDevServer } from 'vite'; import type { AstroSettings, ContentEntryType } from '../@types/astro.js'; import { AstroError } from '../core/errors/errors.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 { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js'; import { @@ -24,6 +23,7 @@ import { type ContentObservable, type ContentPaths, } from './utils.js'; +import type { Logger } from '../core/logger/core'; type ChokidarEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'; type RawContentEvent = { name: ChokidarEvent; entry: string }; @@ -49,7 +49,7 @@ type CollectionEntryMap = { type CreateContentGeneratorParams = { contentConfigObserver: ContentObservable; - logging: LogOptions; + logger: Logger; settings: AstroSettings; /** This is required for loading the content config */ viteServer: ViteDevServer; @@ -68,7 +68,7 @@ class UnsupportedFileTypeError extends Error {} export async function createContentTypesGenerator({ contentConfigObserver, fs, - logging, + logger, settings, viteServer, }: CreateContentGeneratorParams) { @@ -140,7 +140,7 @@ export async function createContentTypesGenerator({ case 'addDir': collectionEntryMap[JSON.stringify(collection)] = { type: 'unknown', entries: {} }; if (logLevel === 'info') { - info(logging, 'content', `${cyan(collection)} collection added`); + logger.info('content', `${cyan(collection)} collection added`); } break; case 'unlinkDir': @@ -186,8 +186,7 @@ export async function createContentTypesGenerator({ const collection = getEntryCollectionName({ entry, contentDir }); if (collection === undefined) { if (['info', 'warn'].includes(logLevel)) { - warn( - logging, + logger.warn( 'content', `${cyan( normalizePath( @@ -350,8 +349,7 @@ export async function createContentTypesGenerator({ } } if (unsupportedFiles.length > 0 && ['info', 'warn'].includes(logLevel)) { - warn( - logging, + logger.warn( 'content', `Unsupported file types found. Prefix with an underscore (\`_\`) to ignore:\n- ${unsupportedFiles.join( '\n' @@ -372,7 +370,7 @@ export async function createContentTypesGenerator({ invalidateVirtualMod(viteServer); if (observable.status === 'loaded' && ['info', 'warn'].includes(logLevel)) { warnNonexistentCollections({ - logging, + logger, contentConfig: observable.config, collectionEntryMap, }); @@ -505,16 +503,15 @@ async function writeContentFiles({ function warnNonexistentCollections({ contentConfig, collectionEntryMap, - logging, + logger, }: { contentConfig: ContentConfig; collectionEntryMap: CollectionEntryMap; - logging: LogOptions; + logger: Logger; }) { for (const configuredCollection in contentConfig.collections) { if (!collectionEntryMap[JSON.stringify(configuredCollection)]) { - warn( - logging, + logger.warn( 'content', `The ${JSON.stringify( configuredCollection diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index 2d738389d..8fa3f5f14 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -9,7 +9,7 @@ import type { import type { SinglePageBuiltModule } from '../build/types'; import { getSetCookiesFromResponse } from '../cookies/index.js'; import { consoleLogDestination } from '../logger/console.js'; -import { error, warn, type LogOptions } from '../logger/core.js'; +import { Logger } from '../logger/core.js'; import { collapseDuplicateSlashes, prependForwardSlash, @@ -50,10 +50,10 @@ export class App { #manifest: SSRManifest; #manifestData: ManifestData; #routeDataToRouteInfo: Map; - #logging: LogOptions = { + #logger = new Logger({ dest: consoleLogDestination, level: 'info', - }; + }); #baseWithoutTrailingSlash: string; #pipeline: SSRRoutePipeline; #onRequest: MiddlewareEndpointHandler | undefined; @@ -83,7 +83,7 @@ export class App { #createEnvironment(streaming = false) { return createEnvironment({ adapterName: this.#manifest.adapterName, - logging: this.#logging, + logger: this.#logger, mode: 'production', compressHTML: this.#manifest.compressHTML, 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, ssr: true, streaming, @@ -138,7 +138,7 @@ export class App { const middleware = await import(this.#manifest.middlewareEntryPoint); this.#pipeline.setMiddlewareFunction(middleware.onRequest as MiddlewareEndpointHandler); } 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; @@ -178,7 +178,7 @@ export class App { if (err instanceof EndpointNotFoundError) { return this.#renderError(request, { status: 404, response: err.originalResponse }); } 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 }); } } diff --git a/packages/astro/src/core/build/buildPipeline.ts b/packages/astro/src/core/build/buildPipeline.ts index ea6e9ecf4..bc13e2c62 100644 --- a/packages/astro/src/core/build/buildPipeline.ts +++ b/packages/astro/src/core/build/buildPipeline.ts @@ -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 { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js'; 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. @@ -28,7 +29,7 @@ export class BuildPipeline extends Pipeline { super( createEnvironment({ adapterName: manifest.adapterName, - logging: staticBuildOptions.logging, + logger: staticBuildOptions.logger, mode: staticBuildOptions.mode, renderers: manifest.renderers, 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: * - dist/server/manifest.mjs diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 73bb4a40f..0a3d80000 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -32,7 +32,6 @@ import { runHookBuildGenerated } from '../../integrations/index.js'; import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/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 { createRenderContext } from '../render/index.js'; import { callGetStaticPaths } from '../render/route-cache.js'; @@ -120,7 +119,6 @@ export function chunkIsPage( } export async function generatePages(opts: StaticBuildOptions, internals: BuildInternals) { - const logger = new Logger(opts.logging); const timer = performance.now(); const ssr = isServerLikeOutput(opts.settings.config); let manifest: SSRManifest; @@ -136,12 +134,13 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn renderers.renderers as SSRLoadedRenderer[] ); } - const buildPipeline = new BuildPipeline(opts, internals, manifest); - await buildPipeline.retrieveMiddlewareFunction(); + const pipeline = new BuildPipeline(opts, internals, manifest); + await pipeline.retrieveMiddlewareFunction(); const outFolder = ssr ? opts.settings.config.build.server : 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 // If we don't delete it here, it's technically not impossible (albeit improbable) for it to leak if (ssr && !hasPrerenderedPages(internals)) { @@ -150,9 +149,9 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn } 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(); - const pagesToGenerate = buildPipeline.retrieveRoutesToGenerate(); + const pagesToGenerate = pipeline.retrieveRoutesToGenerate(); if (ssr) { for (const [pageData, filePath] of pagesToGenerate) { 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. const ssrEntry = ssrEntryPage?.manifest?.pageModule; if (ssrEntry) { - await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger); + await generatePage(pageData, ssrEntry, builtPaths, pipeline); } else { throw new Error( `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 { const ssrEntry = ssrEntryPage as SinglePageBuiltModule; - await generatePage(pageData, ssrEntry, builtPaths, buildPipeline, logger); + await generatePage(pageData, ssrEntry, builtPaths, pipeline); } } if (pageData.route.type === 'redirect') { const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder); - await generatePage(pageData, entry, builtPaths, buildPipeline, logger); + await generatePage(pageData, entry, builtPaths, pipeline); } } } else { for (const [pageData, filePath] of pagesToGenerate) { if (pageData.route.type === 'redirect') { const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder); - await generatePage(pageData, entry, builtPaths, buildPipeline, logger); + await generatePage(pageData, entry, builtPaths, pipeline); } else { const ssrEntryURLPage = createEntryURL(filePath, outFolder); 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()) { - await generateImage(opts, imageData[1].options, imageData[1].path); + await generateImage(pipeline, imageData[1].options, imageData[1].path); } delete globalThis?.astroAsset?.addStaticImage; await runHookBuildGenerated({ 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(); - const generationData = await generateImageInternal(opts, transform, path); + const generationData = await generateImageInternal(pipeline, transform, path); if (!generationData) { return; @@ -225,18 +225,17 @@ async function generateImage(opts: StaticBuildOptions, transform: ImageTransform const statsText = generationData.cached ? `(reused cache entry)` : `(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( pageData: PageBuildData, ssrEntry: SinglePageBuiltModule, builtPaths: Set, - pipeline: BuildPipeline, - logger: Logger + pipeline: BuildPipeline ) { let timeStart = performance.now(); - + const logger = pipeline.getLogger(); const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component); // 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. - const paths = await getPathsForRoute( - pageData, - pageModule, - pipeline.getStaticBuildOptions(), - builtPaths - ); + const paths = await getPathsForRoute(pageData, pageModule, pipeline, builtPaths); let prevTimeEnd = timeStart; for (let i = 0; i < paths.length; i++) { @@ -305,9 +299,11 @@ async function generatePage( async function getPathsForRoute( pageData: PageBuildData, mod: ComponentInstance, - opts: StaticBuildOptions, + pipeline: BuildPipeline, builtPaths: Set ): Promise> { + const opts = pipeline.getStaticBuildOptions(); + const logger = pipeline.getLogger(); let paths: Array = []; if (pageData.route.pathname) { paths.push(pageData.route.pathname); @@ -318,15 +314,15 @@ async function getPathsForRoute( mod, route, routeCache: opts.routeCache, - logging: opts.logging, + logger, ssr: isServerLikeOutput(opts.settings.config), }).catch((err) => { - debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`); + logger.debug('build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`); throw err; }); const label = staticPaths.length === 1 ? 'page' : 'pages'; - debug( + logger.debug( 'build', `├── ${colors.bold(colors.green('✔'))} ${route.component} → ${colors.magenta( `[${staticPaths.length} ${label}]` @@ -473,7 +469,7 @@ async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeli 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. const links = new Set(); @@ -520,7 +516,7 @@ async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeli request: createRequest({ url, headers: new Headers(), - logging: pipeline.getStaticBuildOptions().logging, + logger: pipeline.getLogger(), ssr, }), componentMetadata: manifest.componentMetadata, diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 894a5e6e2..ddb81fd4a 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -21,10 +21,10 @@ import { } from '../../integrations/index.js'; import { isServerLikeOutput } from '../../prerender/utils.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 { 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 { RouteCache } from '../render/route-cache.js'; import { createRouteManifest } from '../routing/index.js'; @@ -55,7 +55,7 @@ export default async function build( options?: BuildOptions ): Promise { applyPolyfill(); - const logging = createNodeLogging(inlineConfig); + const logger = createNodeLogger(inlineConfig); const { userConfig, astroConfig } = await resolveConfig(inlineConfig, 'build'); telemetry.record(eventCliSession('build', userConfig)); @@ -63,20 +63,20 @@ export default async function build( const builder = new AstroBuilder(settings, { ...options, - logging, + logger, mode: inlineConfig.mode, }); await builder.run(); } interface AstroBuilderOptions extends BuildOptions { - logging: LogOptions; + logger: Logger; mode?: RuntimeMode; } class AstroBuilder { private settings: AstroSettings; - private logging: LogOptions; + private logger: Logger; private mode: RuntimeMode = 'production'; private origin: string; private routeCache: RouteCache; @@ -89,9 +89,9 @@ class AstroBuilder { this.mode = options.mode; } this.settings = settings; - this.logging = options.logging; + this.logger = options.logger; this.teardownCompiler = options.teardownCompiler ?? true; - this.routeCache = new RouteCache(this.logging); + this.routeCache = new RouteCache(this.logger); this.origin = settings.config.site ? new URL(settings.config.site).origin : `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. */ private async setup() { - debug('build', 'Initial setup...'); - const { logging } = this; + this.logger.debug('build', 'Initial setup...'); + const { logger } = this; this.timer.init = performance.now(); this.settings = await runHookConfigSetup({ settings: this.settings, command: 'build', - logging, + logger: logger, }); if (isServerLikeOutput(this.settings.config)) { 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( { @@ -124,12 +124,12 @@ class AstroBuilder { 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 syncRet = await syncInternal(this.settings, { logging, fs }); + const syncRet = await syncInternal(this.settings, { logger: logger, fs }); if (syncRet !== 0) { return process.exit(syncRet); } @@ -139,22 +139,22 @@ class AstroBuilder { /** Run the build logic. build() is marked private because usage should go through ".run()" */ 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(); - 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) { - 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(); const { assets, allPages } = await collectPagesData({ settings: this.settings, - logging: this.logging, + logger: this.logger, 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 const pageNames: string[] = []; @@ -162,8 +162,7 @@ class AstroBuilder { // 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. this.timer.buildStart = performance.now(); - info( - this.logging, + this.logger.info( 'build', colors.dim(`Completed in ${getTimeStat(this.timer.init, performance.now())}.`) ); @@ -171,7 +170,7 @@ class AstroBuilder { const opts: StaticBuildOptions = { allPages, settings: this.settings, - logging: this.logging, + logger: this.logger, manifest: this.manifest, mode: this.mode, origin: this.origin, @@ -193,19 +192,19 @@ class AstroBuilder { fs.writeFileSync(filePath, assets[k], 'utf8'); 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. await runHookBuildDone({ config: this.settings.config, pages: pageNames, 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({ - logging: this.logging, + logger: this.logger, timeStart: this.timer.init, pageCount: pageNames.length, buildMode: this.settings.config.output, @@ -238,8 +237,7 @@ class AstroBuilder { if (config.build.split === true) { if (config.output === 'static') { - warn( - this.logging, + this.logger.warn( 'configuration', '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.output === 'static') { - warn( - this.logging, + this.logger.warn( 'configuration', 'The option `build.excludeMiddleware` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.' ); @@ -266,12 +263,12 @@ class AstroBuilder { /** Stats */ private async printStats({ - logging, + logger, timeStart, pageCount, buildMode, }: { - logging: LogOptions; + logger: Logger; timeStart: number; pageCount: number; buildMode: AstroConfig['output']; @@ -285,7 +282,7 @@ class AstroBuilder { messages = ['Server built in', colors.bold(total)]; } - info(logging, 'build', messages.join(' ')); - info(logging, 'build', `${colors.bold('Complete!')}`); + logger.info('build', messages.join(' ')); + logger.info('build', `${colors.bold('Complete!')}`); } } diff --git a/packages/astro/src/core/build/page-data.ts b/packages/astro/src/core/build/page-data.ts index 0a53745c5..ea75a0c0b 100644 --- a/packages/astro/src/core/build/page-data.ts +++ b/packages/astro/src/core/build/page-data.ts @@ -1,6 +1,5 @@ import type { AstroSettings, ManifestData } from '../../@types/astro'; -import type { LogOptions } from '../logger/core'; -import { info } from '../logger/core.js'; +import type { Logger } from '../logger/core'; import type { AllPagesData } from './types'; import * as colors from 'kleur/colors'; @@ -8,7 +7,7 @@ import { debug } from '../logger/core.js'; export interface CollectPagesDataOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; manifest: ManifestData; } @@ -27,7 +26,7 @@ export async function collectPagesData( const allPages: AllPagesData = {}; const builtPaths = new Set(); 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); }, 30000); @@ -39,8 +38,7 @@ export async function collectPagesData( // static route: if (route.pathname) { const routeCollectionLogTimeout = setInterval(() => { - info( - opts.logging, + opts.logger.info( 'build', `${colors.bold( route.component diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index def2ef7ac..7f6846a63 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -100,7 +100,7 @@ export function pluginManifest( await runHookBuildSsr({ config: options.settings.config, manifest, - logging: options.logging, + logger: options.logger, entryPoints: internals.entryPoints, middlewareEntryPoint: shouldPassMiddlewareEntryPoint ? internals.middlewareEntryPoint diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 6227e99c6..0bfb4e3ae 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -19,7 +19,6 @@ import { runHookBuildSetup } from '../../integrations/index.js'; import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import { info } from '../logger/core.js'; import { routeIsRedirect } from '../redirects/index.js'; import { getOutDirWithinCwd } from './common.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.) 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); - 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.start('Client build'); @@ -132,7 +131,7 @@ export async function staticBuild(opts: StaticBuildOptions, internals: BuildInte settings.timer.start('Server generate'); await generatePages(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); settings.timer.end('Server generate'); return; @@ -214,7 +213,7 @@ async function ssrBuild( pages: internals.pagesByComponent, vite: viteBuildConfig, target: 'server', - logging: opts.logging, + logger: opts.logger, }); return await vite.build(updatedViteBuildConfig); @@ -242,7 +241,7 @@ async function clientBuild( } 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 = { ...viteConfig, @@ -276,11 +275,11 @@ async function clientBuild( pages: internals.pagesByComponent, vite: viteBuildConfig, target: 'client', - logging: opts.logging, + logger: opts.logger, }); 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; } @@ -403,7 +402,7 @@ async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles = false } async function ssrMoveAssets(opts: StaticBuildOptions) { - info(opts.logging, 'build', 'Rearranging server assets...'); + opts.logger.info('build', 'Rearranging server assets...'); const serverRoot = opts.settings.config.output === 'static' ? opts.settings.config.build.client diff --git a/packages/astro/src/core/build/types.ts b/packages/astro/src/core/build/types.ts index 35451cacb..c45249e7e 100644 --- a/packages/astro/src/core/build/types.ts +++ b/packages/astro/src/core/build/types.ts @@ -8,7 +8,7 @@ import type { RuntimeMode, SSRLoadedRenderer, } from '../../@types/astro'; -import type { LogOptions } from '../logger/core'; +import type { Logger } from '../logger/core'; import type { RouteCache } from '../render/route-cache'; export type ComponentPath = string; @@ -34,7 +34,7 @@ export type AllPagesData = Record; export interface StaticBuildOptions { allPages: AllPagesData; settings: AstroSettings; - logging: LogOptions; + logger: Logger; manifest: ManifestData; mode: RuntimeMode; origin: string; diff --git a/packages/astro/src/core/config/index.ts b/packages/astro/src/core/config/index.ts index 4699a624c..758e832bf 100644 --- a/packages/astro/src/core/config/index.ts +++ b/packages/astro/src/core/config/index.ts @@ -1,5 +1,5 @@ export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js'; -export { createNodeLogging } from './logging.js'; +export { createNodeLogger } from './logging.js'; export { mergeConfig } from './merge.js'; export type { AstroConfigType } from './schema'; export { createSettings } from './settings.js'; diff --git a/packages/astro/src/core/config/logging.ts b/packages/astro/src/core/config/logging.ts index ea0b29b88..004283f85 100644 --- a/packages/astro/src/core/config/logging.ts +++ b/packages/astro/src/core/config/logging.ts @@ -1,13 +1,12 @@ 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'; -export function createNodeLogging(inlineConfig: AstroInlineConfig): LogOptions { - // For internal testing, the inline config can pass the raw `logging` object directly - if (inlineConfig.logging) return inlineConfig.logging; +export function createNodeLogger(inlineConfig: AstroInlineConfig): Logger { + if (inlineConfig.logger) return inlineConfig.logger; - return { + return new Logger({ dest: nodeLogDestination, level: inlineConfig.logLevel ?? 'info', - }; + }); } diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 22643b694..76a598d8f 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -1,5 +1,5 @@ import type { AstroSettings } from '../@types/astro'; -import type { LogOptions } from './logger/core'; +import type { Logger } from './logger/core'; import nodeFs from 'node:fs'; import { fileURLToPath } from 'node:url'; @@ -32,7 +32,7 @@ import { joinPaths } from './path.js'; interface CreateViteOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; mode: 'dev' | 'build' | string; // will be undefined when using `getViteConfig` command?: 'dev' | 'build'; @@ -66,7 +66,7 @@ const ONLY_DEV_EXTERNAL = [ /** Return a common starting point for all Vite actions */ export async function createVite( commandConfig: vite.InlineConfig, - { settings, logging, mode, command, fs = nodeFs }: CreateViteOptions + { settings, logger, mode, command, fs = nodeFs }: CreateViteOptions ): Promise { const astroPkgsConfig = await crawlFrameworkPkgs({ root: fileURLToPath(settings.config.root), @@ -113,26 +113,26 @@ export async function createVite( plugins: [ configAliasVitePlugin({ settings }), astroLoadFallbackPlugin({ fs, root: settings.config.root }), - astroVitePlugin({ settings, logging }), + astroVitePlugin({ settings, logger }), astroScriptsPlugin({ settings }), // 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. - mode !== 'build' && vitePluginAstroServer({ settings, logging, fs }), + mode !== 'build' && vitePluginAstroServer({ settings, logger, fs }), envVitePlugin({ settings }), - markdownVitePlugin({ settings, logging }), + markdownVitePlugin({ settings, logger }), htmlVitePlugin(), - mdxVitePlugin({ settings, logging }), + mdxVitePlugin({ settings, logger }), astroPostprocessVitePlugin(), - astroIntegrationsContainerPlugin({ settings, logging }), + astroIntegrationsContainerPlugin({ settings, logger }), astroScriptsPageSSRPlugin({ settings }), astroHeadPlugin(), - astroScannerPlugin({ settings, logging }), - astroInjectEnvTsPlugin({ settings, logging, fs }), + astroScannerPlugin({ settings, logger }), + astroInjectEnvTsPlugin({ settings, logger, fs }), astroContentVirtualModPlugin({ settings }), astroContentImportPlugin({ fs, settings }), astroContentAssetPropagationPlugin({ mode, settings }), vitePluginSSRManifest(), - astroAssetsPlugin({ settings, logging, mode }), + astroAssetsPlugin({ settings, logger, mode }), astroTransitions({ config: settings.config }), ], publicDir: fileURLToPath(settings.config.publicDir), diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index cd7ca3b0e..ed318622f 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -12,12 +12,12 @@ import { runHookServerStart, } from '../../integrations/index.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'; export interface Container { fs: typeof nodeFs; - logging: LogOptions; + logger: Logger; settings: AstroSettings; viteServer: vite.ViteDevServer; inlineConfig: AstroInlineConfig; @@ -27,7 +27,7 @@ export interface Container { } export interface CreateContainerParams { - logging: LogOptions; + logger: Logger; settings: AstroSettings; inlineConfig?: AstroInlineConfig; isRestart?: boolean; @@ -36,7 +36,7 @@ export interface CreateContainerParams { export async function createContainer({ isRestart = false, - logging, + logger, inlineConfig, settings, fs = nodeFs, @@ -46,7 +46,7 @@ export async function createContainer({ settings = await runHookConfigSetup({ settings, command: 'dev', - logging, + logger: logger, isRestart, }); @@ -73,15 +73,15 @@ export async function createContainer({ 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 container: Container = { inlineConfig: inlineConfig ?? {}, fs, - logging, + logger, restartInFlight: false, settings, viteServer, @@ -97,18 +97,18 @@ export async function createContainer({ return container; } -async function closeContainer({ viteServer, settings, logging }: Container) { +async function closeContainer({ viteServer, settings, logger }: Container) { await viteServer.close(); await runHookServerDone({ config: settings.config, - logging, + logger, }); } export async function startContainer({ settings, viteServer, - logging, + logger, }: Container): Promise { const { port } = settings.config.server; await viteServer.listen(port); @@ -116,7 +116,7 @@ export async function startContainer({ await runHookServerStart({ config: settings.config, address: devServerAddressInfo, - logging, + logger, }); return devServerAddressInfo; diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts index 115cbe825..95555a533 100644 --- a/packages/astro/src/core/dev/dev.ts +++ b/packages/astro/src/core/dev/dev.ts @@ -6,7 +6,6 @@ import type * as vite from 'vite'; import type { AstroInlineConfig } from '../../@types/astro'; import { attachContentServerListeners } from '../../content/index.js'; import { telemetry } from '../../events/index.js'; -import { info, warn } from '../logger/core.js'; import * as msg from '../messages.js'; import { startContainer } from './container.js'; import { createContainerWithAutomaticRestart } from './restart.js'; @@ -30,13 +29,12 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise { - const { logging, fs, inlineConfig } = container; + const { logger, fs, inlineConfig } = container; const newContainer = await createContainer({ isRestart: true, - logging, + logger: logger, settings, inlineConfig, fs, @@ -60,7 +59,7 @@ export function shouldRestartContainer( } export async function restartContainer(container: Container): Promise { - const { logging, close, settings: existingSettings } = container; + const { logger, close, settings: existingSettings } = container; container.restartInFlight = true; try { @@ -72,7 +71,7 @@ export async function restartContainer(container: Container): Promise { - const logging = createNodeLogging(inlineConfig ?? {}); + const logger = createNodeLogger(inlineConfig ?? {}); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'dev', fs); telemetry.record(eventCliSession('dev', userConfig)); 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 restartComplete = new Promise((resolve) => { @@ -123,7 +122,7 @@ export async function createContainerWithAutomaticRestart({ }; async function handleServerRestart(logMsg: string) { - info(logging, 'astro', logMsg + '\n'); + logger.info('astro', logMsg + '\n'); const container = restart.container; const result = await restartContainer(container); if (result instanceof Error) { diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 11ade7f33..a6e062727 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -11,7 +11,6 @@ import { renderEndpoint } from '../../runtime/server/index.js'; import { ASTRO_VERSION } from '../constants.js'; import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import { warn } from '../logger/core.js'; import { callMiddleware } from '../middleware/callMiddleware.js'; import type { Environment, RenderContext } from '../render/index'; @@ -132,23 +131,22 @@ export async function callEndpoint let response; if (onRequest) { response = await callMiddleware( - env.logging, + env.logger, onRequest as MiddlewareEndpointHandler, context, async () => { - return await renderEndpoint(mod, context, env.ssr, env.logging); + return await renderEndpoint(mod, context, env.ssr, env.logger); } ); } 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; if (response instanceof Response) { if (isEndpointSSR && response.headers.get('X-Astro-Encoding')) { - warn( - env.logging, + env.logger.warn( '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.' ); @@ -160,24 +158,21 @@ export async function callEndpoint // The endpoint returned a simple object, convert it to a Response // TODO: Remove in Astro 4.0 - warn( - env.logging, + env.logger.warn( '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.` ); if (isEndpointSSR) { if (response.hasOwnProperty('headers')) { - warn( - env.logging, + env.logger.warn( '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.' ); } if (response.encoding) { - warn( - env.logging, + env.logger.warn( '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.' ); diff --git a/packages/astro/src/core/logger/core.ts b/packages/astro/src/core/logger/core.ts index c92cdbb24..a79784835 100644 --- a/packages/astro/src/core/logger/core.ts +++ b/packages/astro/src/core/logger/core.ts @@ -142,8 +142,16 @@ export class Logger { error(label: string | null, message: string) { error(this.options, label, message); } - debug(label: string | null, message: string) { - debug(this.options, label, message); + debug(label: string | null, message: string, ...args: any[]) { + debug(this.options, label, message, args); + } + + level() { + return this.options.level; + } + + forkIntegrationLogger(label: string) { + return new AstroIntegrationLogger(this.options, label); } } diff --git a/packages/astro/src/core/middleware/callMiddleware.ts b/packages/astro/src/core/middleware/callMiddleware.ts index afa0156c9..b83fa4322 100644 --- a/packages/astro/src/core/middleware/callMiddleware.ts +++ b/packages/astro/src/core/middleware/callMiddleware.ts @@ -6,7 +6,6 @@ import type { MiddlewareNext, } from '../../@types/astro'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import { warn } from '../logger/core.js'; 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 */ export async function callMiddleware( - logging: Environment['logging'], + logger: Environment['logger'], onRequest: MiddlewareHandler, apiContext: APIContext, responseFunction: () => Promise @@ -61,8 +60,7 @@ export async function callMiddleware( return await Promise.resolve(middlewarePromise).then(async (value) => { if (isEndpointOutput(value)) { - warn( - logging, + logger.warn( 'middleware', 'Using simple endpoints can cause unexpected issues in the chain of middleware functions.' + `\nIt's strongly suggested to use full ${bold('Response')} objects.` diff --git a/packages/astro/src/core/pipeline.ts b/packages/astro/src/core/pipeline.ts index 238f19fbf..0042c288c 100644 --- a/packages/astro/src/core/pipeline.ts +++ b/packages/astro/src/core/pipeline.ts @@ -116,7 +116,7 @@ export class Pipeline { case 'redirect': { if (onRequest) { return await callMiddleware( - env.logging, + env.logger, onRequest as MiddlewareResponseHandler, apiContext, () => { diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index d5b2b2db7..a4e7e7a7b 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -5,7 +5,7 @@ import { telemetry } from '../../events/index.js'; import { eventCliSession } from '../../events/session.js'; import { runHookConfigDone, runHookConfigSetup } from '../../integrations/index.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 createStaticPreviewServer from './static-preview-server.js'; import { getResolvedHostForHttpServer } from './util.js'; @@ -17,7 +17,7 @@ import { getResolvedHostForHttpServer } from './util.js'; * @experimental The JavaScript API is experimental */ export default async function preview(inlineConfig: AstroInlineConfig): Promise { - const logging = createNodeLogging(inlineConfig); + const logger = createNodeLogger(inlineConfig); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'preview'); telemetry.record(eventCliSession('preview', userConfig)); @@ -26,12 +26,12 @@ export default async function preview(inlineConfig: AstroInlineConfig): Promise< const settings = await runHookConfigSetup({ settings: _settings, command: 'preview', - logging: logging, + logger: logger, }); - await runHookConfigDone({ settings: settings, logging: logging }); + await runHookConfigDone({ settings: settings, logger: logger }); if (settings.config.output === 'static') { - const server = await createStaticPreviewServer(settings, logging); + const server = await createStaticPreviewServer(settings, logger); return server; } if (!settings.adapter) { diff --git a/packages/astro/src/core/preview/static-preview-server.ts b/packages/astro/src/core/preview/static-preview-server.ts index 1fdc90c2a..b1c882714 100644 --- a/packages/astro/src/core/preview/static-preview-server.ts +++ b/packages/astro/src/core/preview/static-preview-server.ts @@ -4,8 +4,7 @@ import { performance } from 'perf_hooks'; import enableDestroy from 'server-destroy'; import { preview, type PreviewServer as VitePreviewServer } from 'vite'; import type { AstroSettings } from '../../@types/astro'; -import type { LogOptions } from '../logger/core'; -import { error, info } from '../logger/core.js'; +import type { Logger } from '../logger/core'; import * as msg from '../messages.js'; import { getResolvedHostForHttpServer } from './util.js'; import { vitePluginAstroPreview } from './vite-plugin-astro-preview.js'; @@ -20,7 +19,7 @@ export interface PreviewServer { export default async function createStaticPreviewServer( settings: AstroSettings, - logging: LogOptions + logger: Logger ): Promise { const startServerTime = performance.now(); @@ -43,7 +42,7 @@ export default async function createStaticPreviewServer( }); } catch (err) { if (err instanceof Error) { - error(logging, 'astro', err.stack || err.message); + logger.error('astro', err.stack || err.message); } throw err; } @@ -51,8 +50,7 @@ export default async function createStaticPreviewServer( enableDestroy(previewServer.httpServer); // Log server start URLs - info( - logging, + logger.info( null, msg.serverStart({ startupTime: performance.now() - startServerTime, diff --git a/packages/astro/src/core/render/context.ts b/packages/astro/src/core/render/context.ts index d767d7910..d6806d682 100644 --- a/packages/astro/src/core/render/context.ts +++ b/packages/astro/src/core/render/context.ts @@ -48,7 +48,7 @@ export async function createRenderContext( route: options.route, routeCache: options.env.routeCache, pathname: pathname, - logging: options.env.logging, + logger: options.env.logger, ssr: options.env.ssr, }); diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts index fb10ccc80..3efbddb99 100644 --- a/packages/astro/src/core/render/core.ts +++ b/packages/astro/src/core/render/core.ts @@ -8,7 +8,6 @@ import type { import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js'; import { attachCookiesToResponse } from '../cookies/index.js'; import { callEndpoint, createAPIContext } from '../endpoint/index.js'; -import { warn } from '../logger/core.js'; import { callMiddleware } from '../middleware/callMiddleware.js'; import { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from '../redirects/index.js'; import type { RenderContext } from './context.js'; @@ -41,7 +40,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag adapterName: env.adapterName, links: renderContext.links, styles: renderContext.styles, - logging: env.logging, + logger: env.logger, params: renderContext.params, pathname: renderContext.pathname, componentMetadata: renderContext.componentMetadata, @@ -60,8 +59,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag // TODO: Remove in Astro 4.0 if (mod.frontmatter && typeof mod.frontmatter === 'object' && 'draft' in mod.frontmatter) { - warn( - env.logging, + env.logger.warn( '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.` ); @@ -115,7 +113,7 @@ export async function tryRenderRoute( case 'redirect': { if (onRequest) { return await callMiddleware( - env.logging, + env.logger, onRequest as MiddlewareResponseHandler, apiContext, () => { diff --git a/packages/astro/src/core/render/environment.ts b/packages/astro/src/core/render/environment.ts index f38d98551..a41a0b09e 100644 --- a/packages/astro/src/core/render/environment.ts +++ b/packages/astro/src/core/render/environment.ts @@ -1,5 +1,5 @@ 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'; /** @@ -13,7 +13,7 @@ export interface Environment { */ adapterName?: string; /** logging options */ - logging: LogOptions; + logger: Logger; /** "development" or "production" */ mode: RuntimeMode; compressHTML: boolean; diff --git a/packages/astro/src/core/render/params-and-props.ts b/packages/astro/src/core/render/params-and-props.ts index fc08c495e..2cde3379c 100644 --- a/packages/astro/src/core/render/params-and-props.ts +++ b/packages/astro/src/core/render/params-and-props.ts @@ -1,6 +1,6 @@ import type { ComponentInstance, Params, Props, RouteData } from '../../@types/astro'; 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 { RouteCache, callGetStaticPaths, findPathItemByKey } from './route-cache.js'; @@ -9,12 +9,12 @@ interface GetParamsAndPropsOptions { route?: RouteData | undefined; routeCache: RouteCache; pathname: string; - logging: LogOptions; + logger: Logger; ssr: boolean; } 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), // 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, route, routeCache, - logging, + logger, ssr, }); - const matchedStaticPath = findPathItemByKey(staticPaths, params, route); + const matchedStaticPath = findPathItemByKey(staticPaths, params, route, logger); if (!matchedStaticPath && (ssr ? route.prerender : true)) { throw new AstroError({ ...AstroErrorData.NoMatchingStaticPathFound, diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index 72fa4ddcf..4d6e4cca5 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -11,7 +11,7 @@ import { renderJSX } from '../../runtime/server/jsx.js'; import { chunkToString } from '../../runtime/server/render/index.js'; import { AstroCookies } from '../cookies/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 responseSentSymbol = Symbol.for('astro.responseSent'); @@ -25,7 +25,7 @@ export interface CreateResultArgs { * Value of Astro config's `output` option, true if "server" or "hybrid" */ ssr: boolean; - logging: LogOptions; + logger: Logger; params: Params; pathname: string; renderers: SSRLoadedRenderer[]; @@ -55,12 +55,12 @@ function getFunctionExpression(slot: any) { class Slots { #result: SSRResult; #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.#slots = slots; - this.#loggingOpts = logging; + this.#logger = logger; if (slots) { for (const key of Object.keys(slots)) { @@ -90,8 +90,7 @@ class Slots { const result = this.#result; if (!Array.isArray(args)) { - warn( - this.#loggingOpts, + this.#logger.warn( '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"]])` ); @@ -164,7 +163,7 @@ export function createResult(args: CreateResultArgs): SSRResult { props: Record, slots: Record | null ) { - const astroSlots = new Slots(result, slots, args.logging); + const astroSlots = new Slots(result, slots, args.logger); const Astro: AstroGlobal = { // @ts-expect-error diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index 804f09183..f607cf5d9 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -8,7 +8,7 @@ import type { RuntimeMode, } from '../../@types/astro'; 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 { validateDynamicRouteModule, validateGetStaticPathsResult } from '../routing/validation.js'; @@ -18,7 +18,7 @@ interface CallGetStaticPathsOptions { mod: ComponentInstance; route: RouteData; routeCache: RouteCache; - logging: LogOptions; + logger: Logger; ssr: boolean; } @@ -26,7 +26,7 @@ export async function callGetStaticPaths({ mod, route, routeCache, - logging, + logger, ssr, }: CallGetStaticPathsOptions): Promise { 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; keyedStaticPaths.keyed = new Map(); @@ -80,12 +80,12 @@ interface RouteCacheEntry { * responses during dev and only ever called once during build. */ export class RouteCache { - private logging: LogOptions; + private logger: Logger; private cache: Record = {}; private mode: RuntimeMode; - constructor(logging: LogOptions, mode: RuntimeMode = 'production') { - this.logging = logging; + constructor(logger: Logger, mode: RuntimeMode = 'production') { + this.logger = logger; this.mode = mode; } @@ -99,8 +99,7 @@ export class RouteCache { // Warn here so that an unexpected double-call of getStaticPaths() // isn't invisible and developer can track down the issue. if (this.mode === 'production' && this.cache[route.component]?.staticPaths) { - warn( - this.logging, + this.logger.warn( 'routeCache', `Internal Warning: route cache overwritten. (${route.component})` ); @@ -116,12 +115,13 @@ export class RouteCache { export function findPathItemByKey( staticPaths: GetStaticPathsResultKeyed, params: Params, - route: RouteData + route: RouteData, + logger: Logger ) { const paramsKey = stringifyParams(params, route); const matchedStaticPath = staticPaths.keyed.get(paramsKey); if (matchedStaticPath) { return matchedStaticPath; } - debug('findPathItemByKey', `Unexpected cache miss looking for ${paramsKey}`); + logger.debug('findPathItemByKey', `Unexpected cache miss looking for ${paramsKey}`); } diff --git a/packages/astro/src/core/request.ts b/packages/astro/src/core/request.ts index 36222c7b6..5c671a3fc 100644 --- a/packages/astro/src/core/request.ts +++ b/packages/astro/src/core/request.ts @@ -1,6 +1,5 @@ import type { IncomingHttpHeaders } from 'node:http'; -import type { LogOptions } from './logger/core'; -import { warn } from './logger/core.js'; +import type { Logger } from './logger/core'; type HeaderType = Headers | Record | IncomingHttpHeaders; type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData; @@ -11,7 +10,7 @@ export interface CreateRequestOptions { headers: HeaderType; method?: string; body?: RequestBody | undefined; - logging: LogOptions; + logger: Logger; ssr: boolean; locals?: object | undefined; } @@ -25,7 +24,7 @@ export function createRequest({ clientAddress, method = 'GET', body = undefined, - logging, + logger, ssr, locals, }: CreateRequestOptions): Request { @@ -43,7 +42,7 @@ export function createRequest({ Object.defineProperties(request, { params: { 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; }, }, @@ -56,8 +55,7 @@ export function createRequest({ Object.defineProperty(request, 'headers', { ...headersDesc, get() { - warn( - logging, + logger.warn( 'ssg', `Headers are not exposed in static (SSG) output mode. To enable headers: set \`output: "server"\` in your config file.` ); diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index 124d870d9..f08c2a585 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -6,7 +6,7 @@ import type { RouteData, RoutePart, } from '../../../@types/astro'; -import type { LogOptions } from '../../logger/core'; +import type { Logger } from '../../logger/core'; import { createRequire } from 'module'; import nodeFs from 'node:fs'; @@ -14,7 +14,6 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { getPrerenderDefault } from '../../../prerender/utils.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js'; -import { warn } from '../../logger/core.js'; import { removeLeadingForwardSlash, slash } from '../../path.js'; import { resolvePages } from '../../util.js'; import { getRouteGenerator } from './generator.js'; @@ -221,7 +220,7 @@ export interface CreateRouteManifestParams { /** Create manifest of all static routes */ export function createRouteManifest( { settings, cwd, fsMod }: CreateRouteManifestParams, - logging: LogOptions + logger: Logger ): ManifestData { const components: string[] = []; const routes: RouteData[] = []; @@ -261,7 +260,7 @@ export function createRouteManifest( if (!isDir && !validPageExtensions.has(ext) && !validEndpointExtensions.has(ext)) { if (!foundInvalidFileExtensions.has(ext)) { foundInvalidFileExtensions.add(ext); - warn(logging, 'astro', `Invalid file extension for Pages: ${ext}`); + logger.warn('astro', `Invalid file extension for Pages: ${ext}`); } return; @@ -359,7 +358,7 @@ export function createRouteManifest( } else if (settings.injectedRoutes.length === 0) { 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 diff --git a/packages/astro/src/core/routing/validation.ts b/packages/astro/src/core/routing/validation.ts index b5c29b16e..e9f03eef8 100644 --- a/packages/astro/src/core/routing/validation.ts +++ b/packages/astro/src/core/routing/validation.ts @@ -1,7 +1,6 @@ import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import type { LogOptions } from '../logger/core'; -import { warn } from '../logger/core.js'; +import type { Logger } from '../logger/core'; const VALID_PARAM_TYPES = ['string', 'number', 'undefined']; @@ -40,7 +39,7 @@ export function validateDynamicRouteModule( /** Throw error and log warnings for malformed getStaticPaths() response */ export function validateGetStaticPathsResult( result: GetStaticPathsResult, - logging: LogOptions, + logger: Logger, route: RouteData ) { 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 for (const [key, val] of Object.entries(pathObject.params)) { if (!(typeof val === 'undefined' || typeof val === 'string' || typeof val === 'number')) { - warn( - logging, + logger.warn( 'getStaticPaths', `invalid path param: ${key}. A string, number or undefined value was expected, but got \`${JSON.stringify( val @@ -88,8 +86,7 @@ export function validateGetStaticPathsResult( ); } if (typeof val === 'string' && val === '') { - warn( - logging, + logger.warn( 'getStaticPaths', `invalid path param: ${key}. \`undefined\` expected for an optional param, but got empty string.` ); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index e1d432465..3dea7c714 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -12,11 +12,11 @@ import { runHookConfigSetup } from '../../integrations/index.js'; import { setUpEnvTs } from '../../vite-plugin-inject-env-ts/index.js'; import { getTimeStat } from '../build/util.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 { createVite } from '../create-vite.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; @@ -28,7 +28,7 @@ export type SyncOptions = { }; export type SyncInternalOptions = SyncOptions & { - logging: LogOptions; + logger: Logger; }; /** @@ -41,7 +41,7 @@ export default async function sync( inlineConfig: AstroInlineConfig, options?: SyncOptions ): Promise { - const logging = createNodeLogging(inlineConfig); + const logger = createNodeLogger(inlineConfig); const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, 'sync'); telemetry.record(eventCliSession('sync', userConfig)); @@ -49,11 +49,11 @@ export default async function sync( const settings = await runHookConfigSetup({ settings: _settings, - logging: logging, + logger: logger, 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( settings: AstroSettings, - { logging, fs }: SyncInternalOptions + { logger, fs }: SyncInternalOptions ): Promise { const timerStart = performance.now(); // Needed to load content config @@ -84,7 +84,7 @@ export async function syncInternal( ssr: { external: [] }, 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 { const contentTypesGenerator = await createContentTypesGenerator({ contentConfigObserver: globalContentConfigObserver, - logging, + logger: logger, fs: fs ?? fsMod, settings, viteServer: tempViteServer, @@ -117,7 +117,7 @@ export async function syncInternal( switch (typesResult.reason) { case 'no-content-dir': default: - info(logging, 'content', 'No content directory found. Skipping type generation.'); + logger.info('content', 'No content directory found. Skipping type generation.'); return 0; } } @@ -137,8 +137,8 @@ export async function syncInternal( await tempViteServer.close(); } - info(logging, 'content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); - await setUpEnvTs({ settings, logging, fs: fs ?? fsMod }); + logger.info('content', `Types generated ${dim(getTimeStat(timerStart, performance.now()))}`); + await setUpEnvTs({ settings, logger, fs: fs ?? fsMod }); return 0; } diff --git a/packages/astro/src/integrations/astroFeaturesValidation.ts b/packages/astro/src/integrations/astroFeaturesValidation.ts index c494b35f4..eb388745d 100644 --- a/packages/astro/src/integrations/astroFeaturesValidation.ts +++ b/packages/astro/src/integrations/astroFeaturesValidation.ts @@ -4,7 +4,7 @@ import type { AstroFeatureMap, SupportsKind, } 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 DEPRECATED = 'deprecated'; @@ -40,7 +40,7 @@ export function validateSupportedFeatures( adapterName: string, featureMap: AstroFeatureMap = ALL_UNSUPPORTED, config: AstroConfig, - logging: LogOptions + logger: Logger ): ValidationResult { const { assets = UNSUPPORTED_ASSETS_FEATURE, @@ -53,7 +53,7 @@ export function validateSupportedFeatures( validationResult.staticOutput = validateSupportKind( staticOutput, adapterName, - logging, + logger, 'staticOutput', () => config?.output === 'static' ); @@ -61,7 +61,7 @@ export function validateSupportedFeatures( validationResult.hybridOutput = validateSupportKind( hybridOutput, adapterName, - logging, + logger, 'hybridOutput', () => config?.output === 'hybrid' ); @@ -69,11 +69,11 @@ export function validateSupportedFeatures( validationResult.serverOutput = validateSupportKind( serverOutput, adapterName, - logging, + logger, 'serverOutput', () => config?.output === 'server' ); - validationResult.assets = validateAssetsFeature(assets, adapterName, config, logging); + validationResult.assets = validateAssetsFeature(assets, adapterName, config, logger); return validationResult; } @@ -81,44 +81,39 @@ export function validateSupportedFeatures( function validateSupportKind( supportKind: SupportsKind, adapterName: string, - logging: LogOptions, + logger: Logger, featureName: string, hasCorrectConfig: () => boolean ): boolean { if (supportKind === STABLE) { return true; } else if (supportKind === DEPRECATED) { - featureIsDeprecated(adapterName, logging); + featureIsDeprecated(adapterName, logger); } else if (supportKind === EXPERIMENTAL) { - featureIsExperimental(adapterName, logging); + featureIsExperimental(adapterName, logger); } if (hasCorrectConfig() && supportKind === UNSUPPORTED) { - featureIsUnsupported(adapterName, logging, featureName); + featureIsUnsupported(adapterName, logger, featureName); return false; } else { return true; } } -function featureIsUnsupported(adapterName: string, logging: LogOptions, featureName: string) { - error( - logging, +function featureIsUnsupported(adapterName: string, logger: Logger, featureName: string) { + logger.error( `${adapterName}`, `The feature ${featureName} is not supported by the adapter ${adapterName}.` ); } -function featureIsExperimental(adapterName: string, logging: LogOptions) { - warn(logging, `${adapterName}`, 'The feature is experimental and subject to issues or changes.'); +function featureIsExperimental(adapterName: string, logger: Logger) { + logger.warn(`${adapterName}`, 'The feature is experimental and subject to issues or changes.'); } -function featureIsDeprecated(adapterName: string, logging: LogOptions) { - warn( - logging, - `${adapterName}`, - 'The feature is deprecated and will be moved in the next release.' - ); +function featureIsDeprecated(adapterName: string, logger: Logger) { + logger.warn(`${adapterName}`, 'The feature is deprecated and will be moved in the next release.'); } const SHARP_SERVICE = 'astro/assets/services/sharp'; @@ -128,7 +123,7 @@ function validateAssetsFeature( assets: AstroAssetsFeature, adapterName: string, config: AstroConfig, - logging: LogOptions + logger: Logger ): boolean { const { supportKind = UNSUPPORTED, @@ -136,8 +131,7 @@ function validateAssetsFeature( isSquooshCompatible = false, } = assets; if (config?.image?.service?.entrypoint === SHARP_SERVICE && !isSharpCompatible) { - error( - logging, + logger.error( 'astro', `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) { - error( - logging, + logger.error( 'astro', `The currently selected adapter \`${adapterName}\` is not compatible with the image service "Squoosh".` ); return false; } - return validateSupportKind(supportKind, adapterName, logging, 'assets', () => true); + return validateSupportKind(supportKind, adapterName, logger, 'assets', () => true); } diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 71c5a5e63..9b7770c1c 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -18,7 +18,7 @@ import type { SerializedSSRManifest } from '../core/app/types'; import type { PageBuildData } from '../core/build/types'; import { buildClientDirectiveEntrypoint } from '../core/client-directive/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 { validateSupportedFeatures } from './astroFeaturesValidation.js'; @@ -26,15 +26,15 @@ async function withTakingALongTimeMsg({ name, hookResult, timeoutMs = 3000, - logging, + logger, }: { name: string; hookResult: T | Promise; timeoutMs?: number; - logging: LogOptions; + logger: Logger; }): Promise { const timeout = setTimeout(() => { - info(logging, 'build', `Waiting for the ${bold(name)} integration...`); + logger.info('build', `Waiting for the ${bold(name)} integration...`); }, timeoutMs); const result = await hookResult; clearTimeout(timeout); @@ -44,25 +44,25 @@ async function withTakingALongTimeMsg({ // Used internally to store instances of loggers. const Loggers = new WeakMap(); -function getLogger(integration: AstroIntegration, logging: LogOptions) { +function getLogger(integration: AstroIntegration, logger: Logger) { if (Loggers.has(integration)) { // SAFETY: we check the existence in the if block return Loggers.get(integration)!; } - const logger = new AstroIntegrationLogger(logging, integration.name); - Loggers.set(integration, logger); - return logger; + const integrationLogger = logger.forkIntegrationLogger(integration.name); + Loggers.set(integration, integrationLogger); + return integrationLogger; } export async function runHookConfigSetup({ settings, command, - logging, + logger, isRestart = false, }: { settings: AstroSettings; command: 'dev' | 'build' | 'preview'; - logging: LogOptions; + logger: Logger; isRestart?: boolean; }): Promise { // 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']) { - const logger = getLogger(integration, logging); + const integrationLogger = getLogger(integration, logger); const hooks: HookParameters<'astro:config:setup'> = { config: updatedConfig, @@ -125,7 +125,7 @@ export async function runHookConfigSetup({ } addedClientDirectives.set(name, buildClientDirectiveEntrypoint(name, entrypoint)); }, - logger, + logger: integrationLogger, }; // --- @@ -164,7 +164,7 @@ export async function runHookConfigSetup({ await withTakingALongTimeMsg({ name: integration.name, hookResult: integration.hooks['astro:config:setup'](hooks), - logging, + logger, }); // Add custom client directives to settings, waiting for compiled code by esbuild @@ -180,13 +180,12 @@ export async function runHookConfigSetup({ export async function runHookConfigDone({ settings, - logging, + logger, }: { settings: AstroSettings; - logging: LogOptions; + logger: Logger; }) { for (const integration of settings.config.integrations) { - const logger = getLogger(integration, logging); if (integration?.hooks?.['astro:config:done']) { await withTakingALongTimeMsg({ name: integration.name, @@ -200,8 +199,7 @@ export async function runHookConfigDone({ } if (!adapter.supportedAstroFeatures) { // NOTE: throw an error in Astro 4.0 - warn( - logging, + logger.warn( '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.` ); @@ -210,20 +208,18 @@ export async function runHookConfigDone({ adapter.name, adapter.supportedAstroFeatures, settings.config, - logging + logger ); for (const [featureName, supported] of Object.entries(validationResult)) { if (!supported) { - error( - logging, + logger.error( 'astro', `The adapter ${adapter.name} doesn't support the feature ${featureName}. Your project won't be built. You should not use it.` ); } } if (!validationResult.assets) { - info( - logging, + logger.info( '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.` ); @@ -235,9 +231,9 @@ export async function runHookConfigDone({ } settings.adapter = adapter; }, - logger, + logger: getLogger(integration, logger), }), - logging, + logger, }); } } @@ -246,19 +242,21 @@ export async function runHookConfigDone({ export async function runHookServerSetup({ config, server, - logging, + logger, }: { config: AstroConfig; server: ViteDevServer; - logging: LogOptions; + logger: Logger; }) { for (const integration of config.integrations) { if (integration?.hooks?.['astro:server:setup']) { - const logger = getLogger(integration, logging); await withTakingALongTimeMsg({ name: integration.name, - hookResult: integration.hooks['astro:server:setup']({ server, logger }), - logging, + hookResult: integration.hooks['astro:server:setup']({ + server, + logger: getLogger(integration, logger), + }), + logger, }); } } @@ -267,20 +265,21 @@ export async function runHookServerSetup({ export async function runHookServerStart({ config, address, - logging, + logger, }: { config: AstroConfig; address: AddressInfo; - logging: LogOptions; + logger: Logger; }) { for (const integration of config.integrations) { - const logger = getLogger(integration, logging); - if (integration?.hooks?.['astro:server:start']) { await withTakingALongTimeMsg({ name: integration.name, - hookResult: integration.hooks['astro:server:start']({ address, logger }), - logging, + hookResult: integration.hooks['astro:server:start']({ + address, + logger: getLogger(integration, logger), + }), + logger, }); } } @@ -288,19 +287,19 @@ export async function runHookServerStart({ export async function runHookServerDone({ config, - logging, + logger, }: { config: AstroConfig; - logging: LogOptions; + logger: Logger; }) { for (const integration of config.integrations) { - const logger = getLogger(integration, logging); - if (integration?.hooks?.['astro:server:done']) { await withTakingALongTimeMsg({ name: integration.name, - hookResult: integration.hooks['astro:server:done']({ logger }), - logging, + hookResult: integration.hooks['astro:server:done']({ + logger: getLogger(integration, logger), + }), + logger, }); } } @@ -311,7 +310,7 @@ export async function runHookBuildStart({ logging, }: { config: AstroConfig; - logging: LogOptions; + logging: Logger; }) { for (const integration of config.integrations) { if (integration?.hooks?.['astro:build:start']) { @@ -320,7 +319,7 @@ export async function runHookBuildStart({ await withTakingALongTimeMsg({ name: integration.name, hookResult: integration.hooks['astro:build:start']({ logger }), - logging, + logger: logging, }); } } @@ -331,20 +330,18 @@ export async function runHookBuildSetup({ vite, pages, target, - logging, + logger, }: { config: AstroConfig; vite: InlineConfig; pages: Map; target: 'server' | 'client'; - logging: LogOptions; + logger: Logger; }): Promise { let updatedConfig = vite; for (const integration of config.integrations) { if (integration?.hooks?.['astro:build:setup']) { - const logger = getLogger(integration, logging); - await withTakingALongTimeMsg({ name: integration.name, hookResult: integration.hooks['astro:build:setup']({ @@ -354,9 +351,9 @@ export async function runHookBuildSetup({ updateConfig: (newConfig) => { updatedConfig = mergeConfig(updatedConfig, newConfig); }, - logger, + logger: getLogger(integration, logger), }), - logging, + logger, }); } } @@ -367,7 +364,7 @@ export async function runHookBuildSetup({ type RunHookBuildSsr = { config: AstroConfig; manifest: SerializedSSRManifest; - logging: LogOptions; + logger: Logger; entryPoints: Map; middlewareEntryPoint: URL | undefined; }; @@ -375,23 +372,21 @@ type RunHookBuildSsr = { export async function runHookBuildSsr({ config, manifest, - logging, + logger, entryPoints, middlewareEntryPoint, }: RunHookBuildSsr) { for (const integration of config.integrations) { if (integration?.hooks?.['astro:build:ssr']) { - const logger = getLogger(integration, logging); - await withTakingALongTimeMsg({ name: integration.name, hookResult: integration.hooks['astro:build:ssr']({ manifest, entryPoints, middlewareEntryPoint, - logger, + logger: getLogger(integration, logger), }), - logging, + logger, }); } } @@ -399,21 +394,22 @@ export async function runHookBuildSsr({ export async function runHookBuildGenerated({ config, - logging, + logger, }: { config: AstroConfig; - logging: LogOptions; + logger: Logger; }) { const dir = isServerLikeOutput(config) ? config.build.client : config.outDir; for (const integration of config.integrations) { - const logger = getLogger(integration, logging); - if (integration?.hooks?.['astro:build:generated']) { await withTakingALongTimeMsg({ name: integration.name, - hookResult: integration.hooks['astro:build:generated']({ dir, logger }), - logging, + hookResult: integration.hooks['astro:build:generated']({ + dir, + logger: getLogger(integration, logger), + }), + logger, }); } } @@ -423,7 +419,7 @@ type RunHookBuildDone = { config: AstroConfig; pages: string[]; routes: RouteData[]; - logging: LogOptions; + logging: Logger; }; export async function runHookBuildDone({ config, pages, routes, logging }: RunHookBuildDone) { @@ -442,7 +438,7 @@ export async function runHookBuildDone({ config, pages, routes, logging }: RunHo routes, logger, }), - logging, + logger: logging, }); } } diff --git a/packages/astro/src/runtime/server/endpoint.ts b/packages/astro/src/runtime/server/endpoint.ts index 91f19fd57..686e3795f 100644 --- a/packages/astro/src/runtime/server/endpoint.ts +++ b/packages/astro/src/runtime/server/endpoint.ts @@ -1,13 +1,12 @@ 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(); // TODO: remove in Astro 4.0 if (mod[lowerCaseMethod]) { - warn( - logging, + logger.warn( 'astro', `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, context: APIContext, ssr: boolean, - logging: LogOptions + logger: Logger ) { const { request } = context; 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 if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'GET' && chosenMethod !== 'get') { // eslint-disable-next-line no-console diff --git a/packages/astro/src/vite-plugin-astro-server/base.ts b/packages/astro/src/vite-plugin-astro-server/base.ts index f9e1c3fe4..bb6a8a009 100644 --- a/packages/astro/src/vite-plugin-astro-server/base.ts +++ b/packages/astro/src/vite-plugin-astro-server/base.ts @@ -2,14 +2,14 @@ import type * as vite from 'vite'; import type { AstroSettings } from '../@types/astro'; 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 { log404 } from './common.js'; import { writeHtmlResponse } from './response.js'; export function baseMiddleware( settings: AstroSettings, - logging: LogOptions + logger: Logger ): vite.Connect.NextHandleFunction { const { config } = settings; const site = config.site ? new URL(config.base, config.site) : undefined; @@ -28,13 +28,13 @@ export function baseMiddleware( } if (pathname === '/' || pathname === '/index.html') { - log404(logging, pathname); + log404(logger, pathname); const html = subpathNotUsedTemplate(devRoot, pathname); return writeHtmlResponse(res, 404, html); } if (req.headers.accept?.includes('text/html')) { - log404(logging, pathname); + log404(logger, pathname); const html = notFoundTemplate({ statusCode: 404, title: 'Not found', @@ -49,8 +49,7 @@ export function baseMiddleware( fs.stat(publicPath, (_err, stats) => { if (stats) { const expectedLocation = new URL('.' + url, devRootURL).pathname; - warn( - logging, + logger.warn( 'dev', `Requests for items in your public folder must also include your base. ${url} should be ${expectedLocation}. Omitting the base will break in production.` ); diff --git a/packages/astro/src/vite-plugin-astro-server/common.ts b/packages/astro/src/vite-plugin-astro-server/common.ts index 9739bebc5..9e331232c 100644 --- a/packages/astro/src/vite-plugin-astro-server/common.ts +++ b/packages/astro/src/vite-plugin-astro-server/common.ts @@ -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'; -export function log404(logging: LogOptions, pathname: string) { - info(logging, 'serve', msg.req({ url: pathname, statusCode: 404 })); +export function log404(logger: Logger, pathname: string) { + logger.info('serve', msg.req({ url: pathname, statusCode: 404 })); } diff --git a/packages/astro/src/vite-plugin-astro-server/devPipeline.ts b/packages/astro/src/vite-plugin-astro-server/devPipeline.ts index 6bb8e86eb..fbe9c0429 100644 --- a/packages/astro/src/vite-plugin-astro-server/devPipeline.ts +++ b/packages/astro/src/vite-plugin-astro-server/devPipeline.ts @@ -5,8 +5,7 @@ import type { SSRLoadedRenderer, SSRManifest, } from '../@types/astro'; -import type { LogOptions } from '../core/logger/core'; -import { Logger } from '../core/logger/core.js'; +import type { Logger } from '../core/logger/core'; import type { ModuleLoader } from '../core/module-loader'; import { Pipeline } from '../core/pipeline.js'; import type { Environment } from '../core/render'; @@ -22,18 +21,18 @@ export default class DevPipeline extends Pipeline { constructor({ manifest, - logging, + logger, settings, loader, }: { manifest: SSRManifest; - logging: LogOptions; + logger: Logger; settings: AstroSettings; loader: ModuleLoader; }) { - const env = DevPipeline.createDevelopmentEnvironment(manifest, settings, logging, loader); + const env = DevPipeline.createDevelopmentEnvironment(manifest, settings, logger, loader); super(env); - this.#devLogger = new Logger(logging); + this.#devLogger = logger; this.#settings = settings; this.#loader = loader; this.setEndpointHandler(this.#handleEndpointResult); @@ -69,21 +68,20 @@ export default class DevPipeline extends Pipeline { static createDevelopmentEnvironment( manifest: SSRManifest, settings: AstroSettings, - logging: LogOptions, + logger: Logger, loader: ModuleLoader ): Environment { const mode: RuntimeMode = 'development'; - return createEnvironment({ adapterName: manifest.adapterName, - logging, + logger, 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), + routeCache: new RouteCache(logger, mode), site: manifest.site, ssr: isServerLikeOutput(settings.config), streaming: true, diff --git a/packages/astro/src/vite-plugin-astro-server/environment.ts b/packages/astro/src/vite-plugin-astro-server/environment.ts deleted file mode 100644 index 010c1b96a..000000000 --- a/packages/astro/src/vite-plugin-astro-server/environment.ts +++ /dev/null @@ -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, - }); -} diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 374f31fec..26568715b 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -2,7 +2,7 @@ import type fs from 'node:fs'; import type * as vite from 'vite'; import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro'; 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 { createRouteManifest } from '../core/routing/index.js'; import { baseMiddleware } from './base.js'; @@ -12,13 +12,13 @@ import { handleRequest } from './request.js'; export interface AstroPluginOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; fs: typeof fs; } export default function createVitePluginAstroServer({ settings, - logging, + logger, fs: fsMod, }: AstroPluginOptions): vite.Plugin { return { @@ -26,15 +26,15 @@ export default function createVitePluginAstroServer({ configureServer(viteServer) { const loader = createViteLoader(viteServer); const manifest = createDevelopmentManifest(settings); - const pipeline = new DevPipeline({ logging, manifest, settings, loader }); - let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logging); + const pipeline = new DevPipeline({ logger, manifest, settings, loader }); + let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logger); const controller = createController({ loader }); /** rebuild the route cache + manifest, as needed. */ function rebuildManifest(needsManifestRebuild: boolean) { pipeline.clearRouteCache(); if (needsManifestRebuild) { - manifestData = createRouteManifest({ settings }, logging); + manifestData = createRouteManifest({ settings }, logger); } } // 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 viteServer.middlewares.stack.unshift({ route: '', - handle: baseMiddleware(settings, logging), + handle: baseMiddleware(settings, logger), }); // Note that this function has a name so other middleware can find it. viteServer.middlewares.use(async function astroDevHandler(request, response) { diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index d4f0118ee..af02da410 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -51,7 +51,7 @@ export async function matchRoute( pipeline: DevPipeline ): Promise { const env = pipeline.getEnvironment(); - const { routeCache, logging } = env; + const { routeCache, logger } = env; const matches = matchAllRoutes(pathname, manifestData); const preloadedMatches = await getSortedPreloadedMatches({ pipeline, @@ -68,7 +68,7 @@ export async function matchRoute( route: maybeRoute, routeCache, pathname: pathname, - logging, + logger, ssr: isServerLikeOutput(pipeline.getConfig()), }); return { @@ -106,7 +106,7 @@ export async function matchRoute( ); } - log404(logging, pathname); + log404(logger, pathname); const custom404 = getCustom404Route(manifestData); if (custom404) { @@ -156,7 +156,7 @@ export async function handleRoute({ const settings = pipeline.getSettings(); const config = pipeline.getConfig(); const moduleLoader = pipeline.getModuleLoader(); - const { logging } = env; + const { logger } = env; if (!matchedRoute) { return handle404Response(origin, incomingRequest, incomingResponse); } @@ -171,7 +171,7 @@ export async function handleRoute({ headers: buildingToSSR ? incomingRequest.headers : new Headers(), method: incomingRequest.method, body, - logging, + logger, ssr: buildingToSSR, clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined, locals: Reflect.get(incomingRequest, clientLocalsSymbol), // Allows adapters to pass in locals in dev mode. diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index b8704c81b..6c6b797ec 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -1,12 +1,12 @@ import { transformWithEsbuild, type ESBuildTransformResult } from 'vite'; import type { AstroConfig } from '../@types/astro'; 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'; interface CachedFullCompilation { compileProps: CompileProps; - logging: LogOptions; + logger: Logger; } interface FullCompileResult extends Omit { @@ -18,14 +18,14 @@ interface EnhanceCompilerErrorOptions { id: string; source: string; config: AstroConfig; - logging: LogOptions; + logger: Logger; } const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; export async function cachedFullCompilation({ compileProps, - logging, + logger, }: CachedFullCompilation): Promise { let transformResult: CompileResult; let esbuildResult: ESBuildTransformResult; @@ -52,7 +52,7 @@ export async function cachedFullCompilation({ id: compileProps.filename, source: compileProps.source, config: compileProps.astroConfig, - logging: logging, + logger: logger, }); throw err; } diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index f123dba3a..6502ae513 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -7,8 +7,7 @@ import { isCached, type CompileResult, } from '../core/compile/index.js'; -import type { LogOptions } from '../core/logger/core.js'; -import { info } from '../core/logger/core.js'; +import type { Logger } from '../core/logger/core.js'; import * as msg from '../core/messages.js'; import { isAstroScript } from './query.js'; @@ -20,14 +19,15 @@ const isPkgFile = (id: string | null) => { export interface HandleHotUpdateOptions { config: AstroConfig; - logging: LogOptions; + logger: Logger; + compile: () => ReturnType; source: string; } export async function handleHotUpdate( ctx: HmrContext, - { config, logging, compile, source }: HandleHotUpdateOptions + { config, logger, compile, source }: HandleHotUpdateOptions ) { let isStyleOnlyChange = false; 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 (isStyleOnlyChange) { - info(logging, 'astro', msg.hmr({ file, style: true })); + logger.info('astro', msg.hmr({ file, style: true })); // remove base file and hoisted scripts 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')); if (isSelfAccepting) { if (/astro\.config\.[cm][jt]s$/.test(file)) return mods; - info(logging, 'astro', msg.hmr({ file })); + logger.info('astro', msg.hmr({ file })); } else { - info(logging, 'astro', msg.reload({ file })); + logger.info('astro', msg.reload({ file })); } return mods; diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index c5523d712..371ae9657 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -1,7 +1,7 @@ import type { SourceDescription } from 'rollup'; import type * as vite from 'vite'; 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 { normalizePath } from 'vite'; @@ -20,11 +20,11 @@ export type { AstroPluginMetadata }; interface AstroPluginOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; } /** 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; let resolvedConfig: vite.ResolvedConfig; @@ -143,7 +143,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P source, }; - const transformResult = await cachedFullCompilation({ compileProps, logging }); + const transformResult = await cachedFullCompilation({ compileProps, logger }); for (const dep of transformResult.cssDeps) { this.addWatchFile(dep); @@ -182,7 +182,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P const compile = () => cachedCompilation(compileProps); return handleHotUpdate(context, { config, - logging, + logger, compile, source: compileProps.source, }); diff --git a/packages/astro/src/vite-plugin-inject-env-ts/index.ts b/packages/astro/src/vite-plugin-inject-env-ts/index.ts index a97ca134d..d884075ab 100644 --- a/packages/astro/src/vite-plugin-inject-env-ts/index.ts +++ b/packages/astro/src/vite-plugin-inject-env-ts/index.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'; import { normalizePath, type Plugin } from 'vite'; import type { AstroSettings } from '../@types/astro.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 }) { return new URL('env.d.ts', srcDir); @@ -13,11 +13,11 @@ export function getEnvTsPath({ srcDir }: { srcDir: URL }) { export function astroInjectEnvTsPlugin({ settings, - logging, + logger, fs, }: { settings: AstroSettings; - logging: LogOptions; + logger: Logger; fs: typeof fsMod; }): Plugin { return { @@ -26,18 +26,18 @@ export function astroInjectEnvTsPlugin({ // Ex. `.astro` types have been written enforce: 'post', async config() { - await setUpEnvTs({ settings, logging, fs }); + await setUpEnvTs({ settings, logger, fs }); }, }; } export async function setUpEnvTs({ settings, - logging, + logger, fs, }: { settings: AstroSettings; - logging: LogOptions; + logger: Logger; fs: typeof fsMod; }) { const envTsPath = getEnvTsPath(settings.config); @@ -57,7 +57,7 @@ export async function setUpEnvTs({ 'types="astro/client"' ); 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)) @@ -68,7 +68,7 @@ export async function setUpEnvTs({ if (!typesEnvContents.includes(expectedTypeReference)) { typesEnvContents = `${expectedTypeReference}\n${typesEnvContents}`; await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8'); - info(logging, 'content', `Added ${bold(envTsPathRelativetoRoot)} types`); + logger.info('content', `Added ${bold(envTsPathRelativetoRoot)} types`); } } else { // 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.writeFile(envTsPath, referenceDefs.join('\n'), 'utf-8'); - info(logging, 'astro', `Added ${bold(envTsPathRelativetoRoot)} types`); + logger.info('astro', `Added ${bold(envTsPathRelativetoRoot)} types`); } } diff --git a/packages/astro/src/vite-plugin-integrations-container/index.ts b/packages/astro/src/vite-plugin-integrations-container/index.ts index 6cc2da152..b18d2e5e9 100644 --- a/packages/astro/src/vite-plugin-integrations-container/index.ts +++ b/packages/astro/src/vite-plugin-integrations-container/index.ts @@ -1,7 +1,7 @@ import type { PluginContext } from 'rollup'; import type { Plugin as VitePlugin } from 'vite'; 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 { runHookServerSetup } from '../integrations/index.js'; @@ -9,16 +9,16 @@ import { runHookServerSetup } from '../integrations/index.js'; /** Connect Astro integrations into Vite, as needed. */ export default function astroIntegrationsContainerPlugin({ settings, - logging, + logger, }: { settings: AstroSettings; - logging: LogOptions; + logger: Logger; }): VitePlugin { return { name: 'astro:integration-container', async configureServer(server) { if (server.config.isProduction) return; - await runHookServerSetup({ config: settings.config, server, logging }); + await runHookServerSetup({ config: settings.config, server, logger }); }, async buildStart() { if (settings.injectedRoutes.length === settings.resolvedInjectedRoutes.length) return; diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index ae26bfb42..cc86d1fc1 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -11,15 +11,14 @@ import type { Plugin } from 'vite'; import { normalizePath } from 'vite'; import type { AstroSettings } from '../@types/astro'; import { AstroError, AstroErrorData, MarkdownError } from '../core/errors/index.js'; -import type { LogOptions } from '../core/logger/core.js'; -import { warn } from '../core/logger/core.js'; +import type { Logger } from '../core/logger/core.js'; import { isMarkdownFile, rootRelativePath } from '../core/util.js'; import type { PluginMetadata } from '../vite-plugin-astro/types.js'; import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js'; interface AstroPluginOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; } function safeMatter(source: string, id: string) { @@ -57,7 +56,7 @@ const astroErrorModulePath = normalizePath( 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 { enforce: 'pre', name: 'astro:markdown', @@ -101,8 +100,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu const { layout } = frontmatter; if (frontmatter.setup) { - warn( - logging, + logger.warn( '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.` ); diff --git a/packages/astro/src/vite-plugin-mdx/index.ts b/packages/astro/src/vite-plugin-mdx/index.ts index f2b068068..b640d6c80 100644 --- a/packages/astro/src/vite-plugin-mdx/index.ts +++ b/packages/astro/src/vite-plugin-mdx/index.ts @@ -1,7 +1,7 @@ import type { TransformResult } from 'rollup'; import { transformWithEsbuild, type Plugin, type ResolvedConfig } from 'vite'; 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 babel from '@babel/core'; @@ -73,7 +73,7 @@ async function transformJSX({ interface AstroPluginJSXOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; } // Format inspired by https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L54 diff --git a/packages/astro/src/vite-plugin-scanner/index.ts b/packages/astro/src/vite-plugin-scanner/index.ts index 106a2f08d..031ea56c6 100644 --- a/packages/astro/src/vite-plugin-scanner/index.ts +++ b/packages/astro/src/vite-plugin-scanner/index.ts @@ -1,25 +1,23 @@ import type { Plugin as VitePlugin } from 'vite'; 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 { extname } from 'node:path'; import { normalizePath } from 'vite'; -import { warn } from '../core/logger/core.js'; import { isEndpoint, isPage, rootRelativePath } from '../core/util.js'; import { getPrerenderDefault, isServerLikeOutput } from '../prerender/utils.js'; import { scan } from './scan.js'; export interface AstroPluginScannerOptions { settings: AstroSettings; - logging: LogOptions; + logger: Logger; } const KNOWN_FILE_EXTENSIONS = ['.astro', '.js', '.ts']; export default function astroScannerPlugin({ settings, - logging, + logger, }: AstroPluginScannerOptions): VitePlugin { return { name: 'astro:scanner', @@ -55,8 +53,7 @@ export default function astroScannerPlugin({ KNOWN_FILE_EXTENSIONS.includes(extname(filename)) ) { const reason = ` because \`output: "${settings.config.output}"\` is set`; - warn( - logging, + logger.warn( 'getStaticPaths', `The getStaticPaths() statement in ${bold( rootRelativePath(settings.config.root, fileURL, true) diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index 26fafe41a..c2f9b6982 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -6,6 +6,7 @@ import { removeDir } from '../dist/core/fs/index.js'; import testAdapter from './test-adapter.js'; import { testImageService } from './test-image-service.js'; import { loadFixture } from './test-utils.js'; +import { Logger } from '../dist/core/logger/core.js'; describe('astro:image', () => { /** @type {import('./test-utils').Fixture} */ @@ -27,7 +28,7 @@ describe('astro:image', () => { }); devServer = await fixture.startDevServer({ - logging: { + logger: new Logger({ level: 'error', dest: new Writable({ objectMode: true, @@ -36,7 +37,7 @@ describe('astro:image', () => { callback(); }, }), - }, + }), }); }); @@ -447,7 +448,7 @@ describe('astro:image', () => { }); devServer = await fixture.startDevServer({ - logging: { + logger: new Logger({ level: 'error', dest: new Writable({ objectMode: true, @@ -456,7 +457,7 @@ describe('astro:image', () => { callback(); }, }), - }, + }), }); }); diff --git a/packages/astro/test/static-build.test.js b/packages/astro/test/static-build.test.js index 77c24f398..54701fee1 100644 --- a/packages/astro/test/static-build.test.js +++ b/packages/astro/test/static-build.test.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { load as cheerioLoad } from 'cheerio'; import { loadFixture } from './test-utils.js'; +import { Logger } from '../dist/core/logger/core.js'; function addLeadingSlash(path) { return path.startsWith('/') ? path : '/' + path; @@ -22,22 +23,22 @@ describe('Static build', () => { let logs = []; before(async () => { - /** @type {import('../src/core/logger/core').LogOptions} */ - const logging = { + /** @type {import('../src/core/logger/core').Logger} */ + const logger = new Logger({ dest: { write(chunk) { logs.push(chunk); }, }, level: 'warn', - }; + }); fixture = await loadFixture({ root: './fixtures/static-build/', // test suite was authored when inlineStylesheets defaulted to never build: { inlineStylesheets: 'never' }, }); - await fixture.build({ logging }); + await fixture.build({ logger }); }); it('Builds out .astro pages', async () => { diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index a420dd6c9..0a7d57929 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { runHookBuildSetup } from '../../../dist/integrations/index.js'; import { validateSupportedFeatures } from '../../../dist/integrations/astroFeaturesValidation.js'; -import { defaultLogging } from '../test-utils.js'; +import { defaultLogger } from '../test-utils.js'; describe('Integration API', () => { it('runHookBuildSetup should work', async () => { @@ -23,7 +23,7 @@ describe('Integration API', () => { ], }, vite: {}, - logging: {}, + logger: defaultLogger, pages: new Map(), target: 'server', }); @@ -41,7 +41,7 @@ describe('Astro feature map', function () { { output: 'hybrid', }, - defaultLogging + defaultLogger ); expect(result['hybridOutput']).to.be.true; }); @@ -53,7 +53,7 @@ describe('Astro feature map', function () { { output: 'hybrid', }, - defaultLogging + defaultLogger ); expect(result['hybridOutput']).to.be.false; }); @@ -65,7 +65,7 @@ describe('Astro feature map', function () { { output: 'hybrid', }, - defaultLogging + defaultLogger ); expect(result['hybridOutput']).to.be.false; }); @@ -78,7 +78,7 @@ describe('Astro feature map', function () { { output: 'static', }, - defaultLogging + defaultLogger ); expect(result['staticOutput']).to.be.true; }); @@ -90,7 +90,7 @@ describe('Astro feature map', function () { { output: 'static', }, - defaultLogging + defaultLogger ); expect(result['staticOutput']).to.be.false; }); @@ -103,7 +103,7 @@ describe('Astro feature map', function () { { output: 'hybrid', }, - defaultLogging + defaultLogger ); expect(result['hybridOutput']).to.be.true; }); @@ -117,7 +117,7 @@ describe('Astro feature map', function () { { output: 'hybrid', }, - defaultLogging + defaultLogger ); expect(result['hybridOutput']).to.be.false; }); @@ -130,7 +130,7 @@ describe('Astro feature map', function () { { output: 'server', }, - defaultLogging + defaultLogger ); expect(result['serverOutput']).to.be.true; }); @@ -144,7 +144,7 @@ describe('Astro feature map', function () { { output: 'server', }, - defaultLogging + defaultLogger ); expect(result['serverOutput']).to.be.false; }); @@ -167,7 +167,7 @@ describe('Astro feature map', function () { }, }, }, - defaultLogging + defaultLogger ); expect(result['assets']).to.be.true; }); @@ -187,7 +187,7 @@ describe('Astro feature map', function () { }, }, }, - defaultLogging + defaultLogger ); expect(result['assets']).to.be.true; }); @@ -208,7 +208,7 @@ describe('Astro feature map', function () { }, }, }, - defaultLogging + defaultLogger ); expect(result['assets']).to.be.false; }); diff --git a/packages/astro/test/units/routing/manifest.test.js b/packages/astro/test/units/routing/manifest.test.js index cf3fb0bf1..a7014d853 100644 --- a/packages/astro/test/units/routing/manifest.test.js +++ b/packages/astro/test/units/routing/manifest.test.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { fileURLToPath } from 'node:url'; 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); @@ -77,7 +77,7 @@ describe('routing - createRouteManifest', () => { settings, fsMod: fs, }, - defaultLogging + defaultLogger ); expect(manifest.routes[0].route).to.equal('/foo'); diff --git a/packages/astro/test/units/routing/route-matching.test.js b/packages/astro/test/units/routing/route-matching.test.js index c0bf7d6e6..6f4724893 100644 --- a/packages/astro/test/units/routing/route-matching.test.js +++ b/packages/astro/test/units/routing/route-matching.test.js @@ -2,7 +2,7 @@ import { createBasicSettings, createFs, createRequestAndResponse, - defaultLogging, + defaultLogger, } from '../test-utils.js'; import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js'; import { fileURLToPath } from 'node:url'; @@ -140,19 +140,19 @@ describe('Route matching', () => { container = await createContainer({ fs, settings, - logging: defaultLogging, + logger: defaultLogger, }); const loader = createViteLoader(container.viteServer); const manifest = createDevelopmentManifest(container.settings); - pipeline = new DevPipeline({ manifest, logging: defaultLogging, settings, loader }); + pipeline = new DevPipeline({ manifest, logger: defaultLogger, settings, loader }); manifestData = createRouteManifest( { cwd: fileURLToPath(root), settings, fsMod: fs, }, - defaultLogging + defaultLogger ); }); diff --git a/packages/astro/test/units/shiki/shiki.test.js b/packages/astro/test/units/shiki/shiki.test.js index e5b78963f..d88f3c31e 100644 --- a/packages/astro/test/units/shiki/shiki.test.js +++ b/packages/astro/test/units/shiki/shiki.test.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { fileURLToPath } from 'node:url'; import { createContainer } from '../../../dist/core/dev/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); @@ -12,7 +12,7 @@ describe('', () => { let mod; before(async () => { const settings = await createBasicSettings({ root: fileURLToPath(root) }); - container = await createContainer({ settings, logging: defaultLogging }); + container = await createContainer({ settings, logger: defaultLogger }); const loader = createViteLoader(container.viteServer); mod = await loader.import('astro/components/Shiki.js'); }); diff --git a/packages/astro/test/units/test-utils.js b/packages/astro/test/units/test-utils.js index 80dff5ddb..f8d6dce24 100644 --- a/packages/astro/test/units/test-utils.js +++ b/packages/astro/test/units/test-utils.js @@ -12,12 +12,13 @@ import { resolveConfig } from '../../dist/core/config/index.js'; import { createBaseSettings } from '../../dist/core/config/settings.js'; import { createContainer } from '../../dist/core/dev/container.js'; import { unixify } from './correct-path.js'; +import { Logger } from '../../dist/core/logger/core.js'; -/** @type {import('../../src/core/logger/core').LogOptions} */ -export const defaultLogging = { +/** @type {import('../../src/core/logger/core').Logger} */ +export const defaultLogger = new Logger({ dest: nodeLogDestination, level: 'error', -}; +}); /** @type {import('../../src/core/logger/core').LogOptions} */ export const silentLogging = { @@ -187,7 +188,7 @@ export function createBasicEnvironment(options = {}) { clientDirectives: getDefaultClientDirectives(), resolve: options.resolve ?? ((s) => Promise.resolve(s)), routeCache: new RouteCache(options.logging, mode), - logging: options.logging ?? defaultLogging, + logger: options.logger ?? defaultLogger, ssr: options.ssr ?? true, streaming: options.streaming ?? true, }); @@ -223,7 +224,7 @@ export async function runInContainer(options = {}, callback) { fs: options?.fs ?? realFS, settings, inlineConfig: options.inlineConfig ?? {}, - logging: defaultLogging, + logger: defaultLogger, }); try { await callback(container); diff --git a/packages/astro/test/units/vite-plugin-astro-server/request.test.js b/packages/astro/test/units/vite-plugin-astro-server/request.test.js index 58ad404fd..d3472c56b 100644 --- a/packages/astro/test/units/vite-plugin-astro-server/request.test.js +++ b/packages/astro/test/units/vite-plugin-astro-server/request.test.js @@ -8,7 +8,7 @@ import { createBasicSettings, createFs, createRequestAndResponse, - defaultLogging, + defaultLogger, } from '../test-utils.js'; import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js'; import DevPipeline from '../../../dist/vite-plugin-astro-server/devPipeline.js'; @@ -21,7 +21,7 @@ async function createDevPipeline(overrides = {}) { return new DevPipeline({ manifest, settings, - logging: defaultLogging, + logging: defaultLogger, loader, }); } @@ -53,7 +53,7 @@ describe('vite-plugin-astro-server', () => { fsMod: fs, settings: pipeline.getSettings(), }, - defaultLogging + defaultLogger ); try {