From b0cc93996169fe8a52a7b1119ce2180ae6101e70 Mon Sep 17 00:00:00 2001
From: Tony Sullivan <tony.f.sullivan@outlook.com>
Date: Wed, 21 Sep 2022 17:13:36 +0000
Subject: [PATCH] Adds a new "astro:build:generated" hook for SSG builds
 (#4775)

* Revert "Revert "Adds a new "astro:build:generated" hook for SSG builds (#4772)" (#4774)"

This reverts commit 13a4b0d48813a4aa42f3a4ccd54ff7d37c8008a6.

* fix: updating for latest merge with main
---
 .changeset/four-eggs-compare.md              |  5 +++++
 packages/astro/src/@types/astro.ts           |  1 +
 packages/astro/src/core/build/generate.ts    |  7 +++++++
 packages/astro/src/integrations/index.ts     | 22 ++++++++++++++++++++
 packages/astro/test/static-build-dir.test.js |  6 ++++++
 5 files changed, 41 insertions(+)
 create mode 100644 .changeset/four-eggs-compare.md

diff --git a/.changeset/four-eggs-compare.md b/.changeset/four-eggs-compare.md
new file mode 100644
index 000000000..b89e39294
--- /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 835be849a..6a392f840 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -1160,6 +1160,7 @@ export interface AstroIntegration {
 			target: 'client' | 'server';
 			updateConfig: (newConfig: ViteConfigWithSSR) => void;
 		}) => void | Promise<void>;
+		'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;
 		'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 a73d48945..97df739a0 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -20,6 +20,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';
@@ -113,6 +114,12 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
 		await generatePage(opts, internals, pageData, ssrEntry, builtPaths);
 	}
 
+	await runHookBuildGenerated({
+		config: opts.settings.config,
+		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 99aae5f77..1089e9be6 100644
--- a/packages/astro/src/integrations/index.ts
+++ b/packages/astro/src/integrations/index.ts
@@ -267,6 +267,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 d09756af2..d6a8c90c3 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());
 	});
 });