1import {
2 frameworkSite,
3 staticConfigFromAssets,
4 type FrameworkSiteProps,
5} from "./FrameworkSite.ts";
6
7/** The framework-integration package that drives the Astro build. */
8export const ASTRO_FRAMEWORK_SPECIFIER =
9 "@alchemy.run/frontend-frameworks/astro";
10
11/** The Node container deploy target for the Astro build. */
12export const ASTRO_NODE_TARGET_SPECIFIER =
13 "@alchemy.run/frontend-frameworks/astro/node";
14
15export interface AstroProps extends FrameworkSiteProps {
16 /**
17 * Serializable Astro config merged OVER the project's own
18 * `astro.config.*` (which loads natively). `adapter` is owned by the Node
19 * deploy target and may not be set here.
20 */
21 astro?: {
22 /** The full URL the site deploys to (`Astro.site`). */
23 site?: string;
24 /** Base path the site deploys under. */
25 base?: string;
26 /**
27 * Astro output target. `"server"` renders pages on demand; individual
28 * pages opt into prerendering with `export const prerender = true`.
29 * `"static"` prerenders every page at build time and deploys
30 * assets-only (no SSR server).
31 * @default "server"
32 */
33 output?: "server" | "static";
34 /** Source directory, relative to `rootDir`. @default "./src" */
35 srcDir?: string;
36 /** Public (static passthrough) directory. @default "./public" */
37 publicDir?: string;
38 /** Build output directory. @default "./dist" */
39 outDir?: string;
40 /** Trailing-slash handling for routes. */
41 trailingSlash?: "always" | "never" | "ignore";
42 };
43}
44
45/**
46 * Deploy an [Astro](https://astro.build) application to Cloud Run: a service
47 * running the Node adapter's serve entry (static files first, then the
48 * framework handler) on Cloud Run's `PORT` (8080).
49 *
50 * Pages render on demand by default (`output: "server"`). With
51 * `astro: { output: "static" }` every page is prerendered and the deploy
52 * is assets-only.
53 *
54 *
55 * ### Creating Astro Sites
56 * **Example:** Basic Astro App
57 * ```typescript
58 * const site = yield* GCP.Website.Astro("Web", {
59 * rootDir: "./app",
60 * });
61 * ```
62 *
63 * **Example:** Warm Instance with More Memory
64 * ```typescript
65 * const site = yield* GCP.Website.Astro("Web", {
66 * rootDir: "./app",
67 * scaling: { minInstanceCount: 1 },
68 * resources: { limits: { cpu: "1", memory: "1Gi" } },
69 * });
70 * ```
71 *
72 * ### Static Sites
73 * **Example:** Fully Static Astro Site
74 * ```typescript
75 * const site = yield* GCP.Website.Astro("Docs", {
76 * rootDir: "./docs",
77 * astro: { output: "static" },
78 * assets: { notFoundHandling: "404-page" },
79 * });
80 * ```
81 *
82 * @resource
83 * @product Website
84 */
85export const Astro = (id: string, props: AstroProps = {}) => {
86 const output = props.astro?.output ?? "server";
87 return frameworkSite(id, props, {
88 name: "Astro",
89 framework: ASTRO_FRAMEWORK_SPECIFIER,
90 target: ASTRO_NODE_TARGET_SPECIFIER,
91 options: { astro: { ...props.astro, output } },
92 static:
93 output === "static" ? staticConfigFromAssets(props.assets) : undefined,
94 });
95};