#Static Deployment
The static runtime declaration generates a client-only bundle with no server code. This is for single-page applications (SPAs) that do not need server-side logic at runtime.
#Build
alepha build --runtime=static
static anywhere in build.runtime makes the whole build static, whatever else the list names. The build process:
- Builds the client. No server bundle is built: the build analyzes the app in-process instead, to learn its pages.
- Prerenders every
static: truepage, every$route({ static: true })and every$sitemapnot set tostatic: false, as an SSR build does. - Writes
index.html. A/page prerendered in step 2 keeps its HTML; otherwise the$pageat/(one declaringpath: "/"or leavingpathout, and with no children) is rendered and stripped to an empty<div id="root"></div>, and an app with none fails here. - Writes
404.htmland200.html, SPA shells ofindex.html, and aCNAMEfile for Surge. Each is written only if yourpublic/did not already provide it. - Removes everything but
public/and the manifest. - Writes
_headersand a brotli.brcopy of each compressible file.
--prebuilt is refused: a static build needs the live app to render its pages.
#Output Structure
dist/
public/
index.html # Prerendered `/` page, or the SPA shell
200.html # SPA fallback
404.html # Not-found fallback
CNAME # Surge domain
_headers # Cache and security headers, for hosts that read it
entry.*.js, chunk.*.js, asset.* # JS, CSS, images, at the root
*.br # Brotli copies, for hosts that serve them
manifest.json # What the build declared
#Deploy
The output in dist/public/ is plain HTML, CSS and JS: deploy it to any static host. With Surge (which the generated CNAME file targets):
alepha build --runtime=static
npx surge dist/public
Cloudflare Pages, Netlify, or GitHub Pages work just as well: point them at dist/public/. Cloudflare Pages and Netlify read the _headers file as is.
#Configure Domain
Set a custom Surge domain in alepha.config.ts:
1import { defineConfig } from "alepha/cli/config"; 2 3export default defineConfig({ 4 build: { 5 runtime: ["static"], 6 static: { 7 domain: "myapp.surge.sh", 8 }, 9 },10});
If no domain is specified, Alepha generates a deterministic domain from your package.json name: {name}-{hash}.surge.sh.
#Shipping a Client Built by Something Else
The steps above assume Alepha rendered the site: its own Vite client build, or a $page at /. A site built by anything else - a hand-written index.html through plain Vite, a static export from another tool - has no page for the build to render, and filling dist/public/ yourself does not help either, because the build cleans dist/ before any task runs.
Point build.static.source at the directory your own build fills instead:
1import { defineConfig } from "alepha/cli/config"; 2 3export default defineConfig({ 4 build: { 5 runtime: ["static"], 6 static: { 7 source: "dist-client", 8 }, 9 },10});
vite build --outDir dist-client --emptyOutDir
alepha build --runtime=static
The directory is copied into dist/public/ before the fallbacks are derived, so your index.html ships as written and 200.html/404.html are stripped-down shells of it. Two rules:
- It must live outside
dist/. A source inside it is refused by name - the clean step deletes it before it can be read. - It must contain an
index.html. Otherwise a static host has nothing to answer/with, and the build says so rather than failing later on a path you never wrote.
A server entry is still required, because the build boots the workspace to analyze it. Nothing of it ships - the static build keeps only the client directory and the manifest - so a bare run(Alepha.create()) is enough for a site with no server of its own.
#Other Hosting Providers
The dist/public/ directory is a standard static site. Deploy it to any static hosting:
- GitHub Pages: copy
dist/public/to thegh-pagesbranch - Netlify: set build output to
dist/public - Cloudflare Pages: set build output to
dist/public
The 200.html file serves as the SPA fallback for hosting providers that support it (Surge, Netlify). Configure your hosting provider's rewrite rules to serve 200.html for all unmatched routes.
#Sitemap
Add the $sitemap primitive to a router. It is prerendered to
dist/public/sitemap.xml alongside the static build:
1import { $sitemap } from "alepha/react/sitemap";2 3class AppRouter {4 // hostname defaults to PUBLIC_URL, then "" (relative URLs)5 sitemap = $sitemap({ hostname: "https://myapp.com" });6}
The sitemap lists every leaf $page with no parameter, static or not, and the
static.entries of a page with parameters, excluding wildcard paths and /404. See
Sitemap.