diff --git a/.changeset/bright-eels-cross.md b/.changeset/bright-eels-cross.md new file mode 100644 index 000000000000..638a5d7c1965 --- /dev/null +++ b/.changeset/bright-eels-cross.md @@ -0,0 +1,23 @@ +--- +'astro': minor +--- + +Exposes extra APIs for scripting and testing. + +### Config helpers + +Two new helper functions exported from `astro/config`: + +- `mergeConfig()` allows users to merge partially defined Astro configurations on top of a base config while following the merge rules of `updateConfig()` available for integrations. +- `validateConfig()` allows users to validate that a given value is a valid Astro configuration and fills in default values as necessary. + +These helpers are particularly useful for integration authors and for developers writing scripts that need to manipulate Astro configurations programmatically. + +### Programmatic build + +The `build` API now receives a second optional `BuildOptions` argument where users can specify: + +- `devOutput` (default `false`): output a development-based build similar to code transformed in `astro dev`. +- `teardownCompiler` (default `true`): teardown the compiler WASM instance after build. + +These options provide more control when running Astro builds programmatically, especially for testing scenarios or custom build pipelines. diff --git a/.changeset/slimy-cougars-worry.md b/.changeset/slimy-cougars-worry.md new file mode 100644 index 000000000000..3182f83b7358 --- /dev/null +++ b/.changeset/slimy-cougars-worry.md @@ -0,0 +1,7 @@ +--- +'astro': patch +--- + +Fixes incorrect config update when calling `updateConfig` from `astro:build:setup` hook. + +The function previously called a custom update config function made for merging an Astro config. Now it calls the appropriate `mergeConfig()` utility exported by Vite that updates functional options correctly. diff --git a/packages/astro/src/config/entrypoint.ts b/packages/astro/src/config/entrypoint.ts index 4951792d63ae..35290abde4df 100644 --- a/packages/astro/src/config/entrypoint.ts +++ b/packages/astro/src/config/entrypoint.ts @@ -5,6 +5,8 @@ import type { ImageServiceConfig } from '../types/public/index.js'; export { defineConfig, getViteConfig } from './index.js'; export { envField } from '../env/config.js'; +export { mergeConfig } from '../core/config/merge.js'; +export { validateConfig } from '../core/config/validate.js'; /** * Return the configuration needed to use the Sharp-based image service diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index c3d91196acf0..61da8a782373 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -45,7 +45,9 @@ export interface BuildOptions { * Teardown the compiler WASM instance after build. This can improve performance when * building once, but may cause a performance hit if building multiple times in a row. * - * @internal only used for testing + * When building multiple projects in the same execution (e.g. during tests), disabling + * this option can greatly improve performance at the cost of some extra memory usage. + * * @default true */ teardownCompiler?: boolean; diff --git a/packages/astro/src/core/config/merge.ts b/packages/astro/src/core/config/merge.ts index c897c1441aa8..21ce9a9d60ee 100644 --- a/packages/astro/src/core/config/merge.ts +++ b/packages/astro/src/core/config/merge.ts @@ -1,5 +1,7 @@ import { mergeConfig as mergeViteConfig } from 'vite'; import { arraify, isObject, isURL } from '../util.js'; +import type { DeepPartial } from '../../type-utils.js'; +import type { AstroConfig, AstroInlineConfig } from '../../types/public/index.js'; function mergeConfigRecursively( defaults: Record, @@ -64,10 +66,9 @@ function mergeConfigRecursively( return merged; } -export function mergeConfig( - defaults: Record, - overrides: Record, - isRoot = true, -): Record { - return mergeConfigRecursively(defaults, overrides, isRoot ? '' : '.'); +export function mergeConfig( + defaults: C, + overrides: DeepPartial, +): C { + return mergeConfigRecursively(defaults, overrides, '') as C; } diff --git a/packages/astro/src/core/index.ts b/packages/astro/src/core/index.ts index 14a8c2f99af0..d51a3099f606 100644 --- a/packages/astro/src/core/index.ts +++ b/packages/astro/src/core/index.ts @@ -4,18 +4,10 @@ import type { AstroInlineConfig } from '../types/public/config.js'; import { default as _build } from './build/index.js'; import { default as _sync } from './sync/index.js'; +export { default as build } from './build/index.js'; export { default as dev } from './dev/index.js'; export { default as preview } from './preview/index.js'; -/** - * Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory. - * If SSR is enabled, this will generate the necessary server files to serve your site. - * - * @experimental The JavaScript API is experimental - */ -// Wrap `_build` to prevent exposing the second internal options parameter -export const build = (inlineConfig: AstroInlineConfig) => _build(inlineConfig); - /** * Generates TypeScript types for all Astro modules. This sets up a `src/env.d.ts` file for type inferencing, * and defines the `astro:content` module for the Content Collections API. diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 8d7d0fa3055b..6eecb0ac1ef7 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -3,6 +3,7 @@ import type { AddressInfo } from 'node:net'; import { fileURLToPath } from 'node:url'; import { bold } from 'kleur/colors'; import type { InlineConfig, ViteDevServer } from 'vite'; +import { mergeConfig as mergeViteConfig } from 'vite'; import astroIntegrationActionsRouteHandler from '../actions/integration.js'; import { isActionsFilePresent } from '../actions/utils.js'; import { CONTENT_LAYER_TYPE } from '../content/consts.js'; @@ -196,7 +197,7 @@ export async function runHookConfigSetup({ updatedSettings.scripts.push({ stage, content }); }, updateConfig: (newConfig) => { - updatedConfig = mergeConfig(updatedConfig, newConfig) as AstroConfig; + updatedConfig = mergeConfig(updatedConfig, newConfig); return { ...updatedConfig }; }, injectRoute: (injectRoute) => { @@ -235,8 +236,7 @@ export async function runHookConfigSetup({ } logger.debug( 'middleware', - `The integration ${integration.name} has added middleware that runs ${ - order === 'pre' ? 'before' : 'after' + `The integration ${integration.name} has added middleware that runs ${order === 'pre' ? 'before' : 'after' } any application middleware you define.`, ); updatedSettings.middlewares[order].push( @@ -510,7 +510,7 @@ export async function runHookBuildSetup({ pages, target, updateConfig: (newConfig) => { - updatedConfig = mergeConfig(updatedConfig, newConfig); + updatedConfig = mergeViteConfig(updatedConfig, newConfig); return { ...updatedConfig }; }, logger: getLogger(integration, logger), @@ -654,7 +654,7 @@ export async function runHookRouteSetup({ logger.debug( 'router', `The ${route.component} route's prerender option has been changed multiple times by integrations:\n` + - prerenderChangeLogs.map((log) => `- ${log.integrationName}: ${log.value}`).join('\n'), + prerenderChangeLogs.map((log) => `- ${log.integrationName}: ${log.value}`).join('\n'), ); } }