1import * as Namespace from "../../Namespace.ts";
2import { makeFrameworkSite, type FrameworkSiteProps } from "./FrameworkSite.ts";
3
4/** The framework-integration package that drives the React Router build. */
5export const REACT_ROUTER_FRAMEWORK_SPECIFIER =
6 "@alchemy.run/frontend-frameworks/react-router";
7
8/** The Node container deploy target for the React Router build. */
9export const REACT_ROUTER_NODE_TARGET_SPECIFIER =
10 "@alchemy.run/frontend-frameworks/react-router/node";
11
12export interface ReactRouterProps extends FrameworkSiteProps {}
13
14/**
15 * Deploy a [React Router](https://reactrouter.com) v7 app (framework mode)
16 * to Railway: the SSR server plus client assets on one `Railway.Service`.
17 *
18 * The build runs through
19 * `@alchemy.run/frontend-frameworks/react-router` with the
20 * `@alchemy.run/frontend-frameworks/react-router/node` deploy target — both
21 * must be installed in your project, alongside `@react-router/dev`,
22 * `react-router`, and `vite`.
23 *
24 * Your `vite.config.ts` needs no adapter wiring. React Router's server
25 * build is a `ServerBuild` manifest rather than a request handler, so the
26 * integration wraps the manifest with `createRequestHandler` and packages
27 * the resulting fetch handler as a Node HTTP server on port 3000.
28 *
29 * React Server Components (React Router's `unstable` RSC plugin) and
30 * multi-environment builds are not supported yet — the build fails with an
31 * actionable error when more than one server entry is emitted.
32 *
33 * During `alchemy dev` the site is React Router's own Vite dev server and
34 * no cloud resources are created. `Alchemy.remote()` opts back into the
35 * live Service path.
36 *
37 * ### Creating React Router Sites
38 * **Example:** Basic React Router App
39 * ```typescript
40 * const site = yield* Railway.Website.ReactRouter("Web", {
41 * rootDir: "./app",
42 * });
43 * ```
44 *
45 * **Example:** Custom Domain
46 * ```typescript
47 * const site = yield* Railway.Website.ReactRouter("Web", {
48 * rootDir: "./app",
49 * domain: "app.example.com",
50 * });
51 * ```
52 *
53 * ### Server Configuration
54 * **Example:** Process Environment
55 * ```typescript
56 * const site = yield* Railway.Website.ReactRouter("Web", {
57 * rootDir: "./app",
58 * env: {
59 * GREETING: "Hello from React Router on Railway!",
60 * },
61 * });
62 * ```
63 *
64 * **Example:** Read An Environment Variable From A Loader
65 * ```typescript
66 * // app/routes/home.tsx
67 * export function loader() {
68 * return { apiBase: process.env.API_BASE ?? "unset" };
69 * }
70 * ```
71 *
72 * @resource
73 * @product Website
74 */
75export const ReactRouter = (id: string, props: ReactRouterProps = {}) =>
76 makeFrameworkSite(id, props, {
77 name: "ReactRouter",
78 framework: REACT_ROUTER_FRAMEWORK_SPECIFIER,
79 target: REACT_ROUTER_NODE_TARGET_SPECIFIER,
80 }).pipe(Namespace.push(id));