Repository: withastro/astro
File: packages/astro/src/core/build/static-build.ts (TypeScript)

Code before:
					outDir: fileURLToPath(getServerOutputDirectory(settings)),
				}
			}
		}
	};

	const updatedViteBuildConfig = await runHookBuildSetup({
		config: settings.config,
		pages: internals.pagesByKeys,
		vite: viteBuildConfig,
		target: 'server',
		logger: opts.logger,
	});

	const builder = await vite.createBuilder(updatedViteBuildConfig);

	// Build ssr environment for server output
	const ssrOutput = settings.buildOutput === 'static' ? [] : await builder.build(builder.environments.ssr);

	// Build prerender environment for static generation
	const prerenderOutput = await builder.build(builder.environments.prerender);

	// Extract prerender entry filename and store in internals
	extractPrerenderEntryFileName(internals, prerenderOutput);

	// Build client environment
	// We must discover client inputs after SSR build because hydration/client-only directives
	// are only detected during SSR. We mutate the config here since the builder was already created
	// and this is the only way to update the input after instantiation.
	internals.clientInput = getClientInput(internals, settings);
	builder.environments.client.config.build.rollupOptions.input = Array.from(internals.clientInput);
	const clientOutput = internals.clientInput.size === 0 ? [] : await builder.build(builder.environments.client);

	return { ssrOutput, prerenderOutput, clientOutput };
}

type MutateChunk = (chunk: vite.Rollup.OutputChunk, targets: string[], newCode: string) => void;

/**
 * Extracts the prerender entry filename from the build output
 * and stores it in internals for later retrieval in generatePages.
 */
function extractPrerenderEntryFileName(
	internals: BuildInternals,
	prerenderOutput: vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[],
) {
	const outputs = Array.isArray(prerenderOutput) ? prerenderOutput : [prerenderOutput];

	for (const output of outputs) {
		for (const chunk of output.output) {
			if (chunk.type !== 'asset' && 'fileName' in chunk) {

Review comment (refactor):
Can we use a more functional approach? Let the function return the needed value, and then we assign it. Two issues with the current approach:
- We don't know if we found what we needed
- If no value is extracted, we don't handle it

Here's the proposal:

```js
const maybePrerenderFile = extractPrerenderEntryFileName( prerenderOutput);
if (maybePrerenderFile) {
	internals.prerenderEntryFileName = maybePrerenderFile;
} else {
	// handle this case gracefully
}
```

Code after:
			ssr: {
				build: {
					outDir: fileURLToPath(getServerOutputDirectory(settings)),
				}
			}
		}
	};

	const updatedViteBuildConfig = await runHookBuildSetup({
		config: settings.config,
		pages: internals.pagesByKeys,
		vite: viteBuildConfig,
		target: 'server',
		logger: opts.logger,
	});

	const builder = await vite.createBuilder(updatedViteBuildConfig);

	// Build ssr environment for server output
	const ssrOutput = settings.buildOutput === 'static' ? [] : await builder.build(builder.environments.ssr);

	// Build prerender environment for static generation
	const prerenderOutput = await builder.build(builder.environments.prerender);

	// Extract prerender entry filename and store in internals
	extractPrerenderEntryFileName(internals, prerenderOutput);

	// Build client environment
	// We must discover client inputs after SSR build because hydration/client-only directives
	// are only detected during SSR. We mutate the config here since the builder was already created
	// and this is the only way to update the input after instantiation.
	internals.clientInput = getClientInput(internals, settings);
	builder.environments.client.config.build.rollupOptions.input = Array.from(internals.clientInput);
	const clientOutput = internals.clientInput.size === 0 ? [] : await builder.build(builder.environments.client);

	return { ssrOutput, prerenderOutput, clientOutput };
}

type MutateChunk = (chunk: vite.Rollup.OutputChunk, targets: string[], newCode: string) => void;

/**
 * Finds and returns the prerender entry filename from the build output.
 * Throws an error if no prerender entry file is found.
 */
function getPrerenderEntryFileName(
	prerenderOutput: vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[] | vite.Rollup.RollupWatcher,
): string {
	const outputs = viteBuildReturnToRollupOutputs(prerenderOutput as any);

	for (const output of outputs) {
		for (const chunk of output.output) {