diff --git a/.changeset/four-eggs-compare.md b/.changeset/four-eggs-compare.md new file mode 100644 index 0000000000..b89e39294e --- /dev/null +++ b/.changeset/four-eggs-compare.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Adds a new "astro:build:generated" hook that runs after SSG builds finish but **before** build artifacts are cleaned up. This is a very specific use case, "astro:build:done" is probably what you're looking for. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 817467a30b..59f8470ce2 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1159,6 +1159,7 @@ export interface AstroIntegration { target: 'client' | 'server'; updateConfig: (newConfig: ViteConfigWithSSR) => void; }) => void | Promise; + 'astro:build:generated'?: (options: { dir: URL }) => void | Promise; 'astro:build:done'?: (options: { pages: { pathname: string }[]; dir: URL; diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index f686592949..8083a47ad2 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -19,6 +19,7 @@ import { removeTrailingForwardSlash, } from '../../core/path.js'; import type { RenderOptions } from '../../core/render/core'; +import { runHookBuildGenerated } from '../../integrations/index.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { call as callEndpoint } from '../endpoint/index.js'; import { debug, info } from '../logger/core.js'; @@ -111,6 +112,9 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn for (const pageData of eachPageData(internals)) { await generatePage(opts, internals, pageData, ssrEntry, builtPaths); } + + await runHookBuildGenerated({ config: opts.astroConfig, buildConfig: opts.buildConfig, logging: opts.logging }); + info(opts.logging, null, dim(`Completed in ${getTimeStat(timer, performance.now())}.\n`)); } diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 68d2a23aef..2b51ae3825 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -263,6 +263,28 @@ export async function runHookBuildSsr({ } } +export async function runHookBuildGenerated({ + config, + buildConfig, + logging, +}: { + config: AstroConfig; + buildConfig: BuildConfig; + logging: LogOptions; +}) { + const dir = config.output === 'server' ? buildConfig.client : config.outDir; + + for (const integration of config.integrations) { + if (integration?.hooks?.['astro:build:generated']) { + await withTakingALongTimeMsg({ + name: integration.name, + hookResult: integration.hooks['astro:build:generated']({ dir }), + logging, + }); + } + } +} + export async function runHookBuildDone({ config, buildConfig, diff --git a/packages/astro/test/static-build-dir.test.js b/packages/astro/test/static-build-dir.test.js index d09756af29..d6a8c90c39 100644 --- a/packages/astro/test/static-build-dir.test.js +++ b/packages/astro/test/static-build-dir.test.js @@ -4,6 +4,8 @@ import { loadFixture } from './test-utils.js'; describe('Static build: dir takes the URL path to the output directory', () => { /** @type {URL} */ let checkDir; + /** @type {URL} */ + let checkGeneratedDir; before(async () => { const fixture = await loadFixture({ root: './fixtures/static-build-dir/', @@ -11,6 +13,9 @@ describe('Static build: dir takes the URL path to the output directory', () => { { name: '@astrojs/dir', hooks: { + 'astro:build:generated': ({ dir }) => { + checkGeneratedDir = dir; + }, 'astro:build:done': ({ dir }) => { checkDir = dir; }, @@ -25,5 +30,6 @@ describe('Static build: dir takes the URL path to the output directory', () => { expect(removeTrailingSlash(checkDir.toString())).to.be.equal( removeTrailingSlash(new URL('./fixtures/static-build-dir/dist', import.meta.url).toString()) ); + expect(checkDir.toString()).to.be.equal(checkGeneratedDir.toString()); }); });