Skip to content

Commit

Permalink
feat(astro): Exposes extra APIs for script and testing (#12052)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt Kane <[email protected]>
Co-authored-by: Sarah Rainsberger <[email protected]>
Co-authored-by: Emanuele Stoppa <[email protected]>


Co-authored-by: matthewp <[email protected]>
Co-authored-by: sarah11918 <[email protected]>
Co-authored-by: ematipico <[email protected]>
Co-authored-by: bluwy <[email protected]>
Co-authored-by: ascorbic <[email protected]>
Co-authored-by: florian-lefebvre <[email protected]>
  • Loading branch information
7 people authored Feb 26, 2025
1 parent eb47231 commit 5be12b2
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 21 deletions.
23 changes: 23 additions & 0 deletions .changeset/bright-eels-cross.md
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 7 additions & 0 deletions .changeset/slimy-cougars-worry.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 2 additions & 0 deletions packages/astro/src/config/entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion packages/astro/src/core/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 7 additions & 6 deletions packages/astro/src/core/config/merge.ts
Original file line number Diff line number Diff line change
@@ -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<string, any>,
Expand Down Expand Up @@ -64,10 +66,9 @@ function mergeConfigRecursively(
return merged;
}

export function mergeConfig(
defaults: Record<string, any>,
overrides: Record<string, any>,
isRoot = true,
): Record<string, any> {
return mergeConfigRecursively(defaults, overrides, isRoot ? '' : '.');
export function mergeConfig<C extends AstroConfig | AstroInlineConfig>(
defaults: C,
overrides: DeepPartial<C>,
): C {
return mergeConfigRecursively(defaults, overrides, '') as C;
}
10 changes: 1 addition & 9 deletions packages/astro/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 5 additions & 5 deletions packages/astro/src/integrations/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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'),
);
}
}
Expand Down

0 comments on commit 5be12b2

Please sign in to comment.