Static Sites
Build and deploy a static frontend using an ssg workspace or the lower-level frontend package CLI.
See also: CSS Playbook for the minimal, convention-first styling approach used by the SSG starter.
Supported Paths
- Top-level Bun CLI: scaffold an
ssgworkspace, or override a publish run withwebstir publish --workspace <path> --frontend-mode ssg. - Lower-level package CLI: run
webstir-frontend publish --workspace <path> --mode ssgwhen you are working directly with the frontend package.
Recommended Flow
webstir init ssg site
cd site
bun install
webstir publish --workspace "$PWD"What happens:
- The frontend provider writes optimized assets to
dist/frontend/**. - SSG publish creates static-friendly aliases:
dist/frontend/pages/<page>/index.htmldist/frontend/<page>/index.htmldist/frontend/index.htmlwhenpages/home/index.htmlexists
- Publish injects the same optimized HTML/CSS/JS output used by the
ssgdemo workspaces.
Advanced Package-Level Flow
If you are testing the frontend package directly:
bunx webstir-frontend publish --workspace "$PWD" --mode ssgUse this path when you need package-level control without going through the top-level orchestrator.
If you are using the top-level CLI against a non-ssg workspace, the equivalent override is webstir publish --workspace "$PWD" --frontend-mode ssg.
Static Paths from Module Metadata
You can describe SSG views in package.json under webstir.moduleManifest.views. SSG publish uses these hints to create additional index.html aliases and, when a backend view loader exists, generate per-page view-data.json.
Example:
{
"webstir": {
"mode": "ssg",
"moduleManifest": {
"views": [
{ "name": "HomeView", "path": "/" },
{ "name": "AboutView", "path": "/about" }
]
}
}
}Notes:
routesmetadata is for backend APIs, not SSG page generation.- In
ssgworkspaces, omittedrenderModevalues default tossg. staticPathsis optional for simple views and useful when you want extra aliases such as/about/team.
GitHub Pages
webstir publish --workspace "$PWD"
mkdir -p out
cp -R dist/frontend/* out/Then publish out/ with your preferred Pages workflow.
S3 + CloudFront
Scaffold the deploy script, edge function, and workflow:
webstir enable s3-cloudfront --workspace "$PWD"
S3_BUCKET=your-bucket-name CLOUDFRONT_DISTRIBUTION_ID=E123EXAMPLE bun run deployThe script publishes, syncs dist/frontend/** to the bucket with long-lived caching for fingerprinted bundles and revalidation for documents, and invalidates the distribution. See Enable Features for what it writes.
Directory URLs need an edge rewrite
Publish output is directory-based (/about/ is about/index.html). CloudFront's DefaultRootObject only covers /. When the origin is the S3 REST endpoint (the default when you pick a bucket in the CloudFront console, and the only option with Origin Access Control), every other page returns 404, because the REST endpoint serves exact object keys and never maps a directory to its index file.
Attach the generated utils/cloudfront-rewrite-directory-index.js as a CloudFront Function on the distribution's default behavior, viewer-request event. It rewrites /about/ and /about to /about/index.html and leaves file requests alone. Only the S3 website endpoint resolves directory indexes on its own, and that endpoint is HTTP-only and cannot use Origin Access Control.
Error pages
Add a 404 page to the workspace and point the distribution's custom error responses for 403 and 404 at /404/index.html. The 404 page is excluded from the sitemap automatically.