frontend · starter · 3d
Static page deploy
Take a static HTML/CSS page from a file on disk to a public URL with a deploy you can re-run — your first real delivery, no build step required.
Deliverable
A static site deployed to a public URL via a repeatable deploy (Cloudflare Pages / Netlify / GitHub Pages), with cache headers, a 404 page, and Lighthouse CWV in the green.
Milestones
0/4 · 0%- 01Prepare and preview locally
Prepare a minimal static site folder: index.html, a linked style.css, one image with explicit width/height, and a 404.html. Serve it locally with a static server (e.g. npx serve or python -m http.server) — not by opening file:// — so relative links, MIME types, and 404 handling behave like they will in production. Open it at localhost and verify there is no console error, the image has reserved space (no layout shift when it loads), and navigating to a non-existent path shows your 404.html when served. This is the artifact you will deploy; if it works locally via a server, it will work remotely.
Definition of done- A folder with index.html + style.css + image (explicit dimensions) + 404.html is served locally via a static server and loads with no console errors.
- Visiting a non-existent path serves 404.html (200 vs 404 distinction is correct per host) and the image does not cause CLS.
Self-review
Show local serve with no console errors and 404 handling. A reviewer checks explicit image dimensions and that file:// was not used for preview.
- 02Deploy to a public URL
Deploy the folder to a real host — Cloudflare Pages (wrangler pages deploy), Netlify (drag-and-drop or CLI), or GitHub Pages — and get a public https:// URL. The deploy must be repeatable: a single command or a git push re-deploys without manual dashboard clicks that you can't reproduce. Verify the URL is reachable from another device (not just your localhost) and that the same folder you previewed locally is what got deployed (no extra build step silently transforming it). Save the URL — it's the deliverable.
Definition of done- The site is live at a public https:// URL via a repeatable deploy (CLI command or git push) — verified from a second device or incognito.
- Re-running the same deploy command updates the live site without manual dashboard steps.
Self-review
Show the public URL and the repeatable deploy command (not just a dashboard screenshot). A reviewer checks the URL is https and the deploy is reproducible.
- 03Cache headers and 404 polish
Set the right cache behaviour and make the 404 page useful. Static assets with hashed filenames (if any) can be cached for a year (immutable), but index.html must never be cached long — otherwise visitors keep seeing the old version after you deploy a fix. On most static hosts this is automatic (hashed assets → long cache, html → no-cache), but verify with curl -I: check Cache-Control on index.html vs an asset. Polish the 404 page so it links back to home and explains what happened — a blank 404 is a dead end. Verify both: curl the asset and index.html and compare headers.
Definition of done- curl -I on index.html shows no-cache / short cache; on a hashed asset (or the image) shows long immutable cache — headers are verified and documented.
- The 404 page is styled, links back to home, and returns 404 status (not 200) on a missing path.
Self-review
Show curl -I headers for index.html vs asset and the 404 page returning 404. A reviewer checks Cache-Control values are appropriate per file type.
- 04Lighthouse and CWV
Measure the deployed site with Lighthouse (mobile) and fix any red. Record LCP (<2.5s), CLS (<0.1), and the accessibility checks: contrast ≥4.5:1, alt text, and keyboard focus visible. Common first-deploy failures: an unsized hero image causes CLS, a web font without font-display: swap blocks LCP, a missing alt or low contrast fails a11y. Fix them in the source, re-deploy with the same repeatable command, and show the scores go green. The lesson is that deploy is not the finish line — measure is.
Definition of done- Lighthouse mobile on the public URL shows LCP < 2.5s, CLS < 0.1, and no critical a11y failures — before/after scores are recorded if a fix was needed.
- Re-deploy after a fix uses the same repeatable command and the new scores are green.
Self-review
Show the public Lighthouse report (LCP/CLS/a11y) before and after fixes if any. A reviewer checks the URL is the deployed one and the CWV targets are met.
Starter
fallowlone/skein-projects
projects/static-page-deploy
- README.md
- artifact/index.html
- artifact/style.css
- src/page.ts
- test/page.test.ts
npx degit fallowlone/skein-projects/projects/static-page-deploy static-page-deploy Implement the stubs, then run the tests until they pass: bun test
Fork the repo and push your work — the grade workflow runs the suite plus static checks on your own runners.
Rubric
| Junior | Mid | Senior | |
|---|---|---|---|
| Repeatable deploy | The site is deployed but only via manual dashboard clicks that can't be re-run from the terminal. | A single CLI command or git push re-deploys the same folder; the public URL is https and reachable from another device. | The deploy is CI-ready (could run on a push) and the artifact is the same folder that was previewed locally — no hidden build step changes it. |
| Caching & 404 correctness | The site is live but cache headers are not checked and the 404 page is blank or returns 200. | index.html is no-cache, assets are long-cache (or the difference is documented), and the 404 returns 404 with a home link. | Can explain why hashing filenames enables immutable caching and why a long cache on index.html would break deploys. |
| CWV & a11y | The site loads but LCP/CLS/a11y have not been measured. | Lighthouse shows LCP < 2.5s, CLS < 0.1, no critical a11y issues, and any red was fixed and re-deployed. | Can name which resource set each CWV (hero image for LCP, dimensions for CLS) and what would break the budget under a future change. |
Reference walkthrough (spoiler)
Why no-cache on index.html: the HTML file is the entry point that references hashed assets. If the HTML itself is cached long, a deploy that changes the HTML and the asset hashes leaves visitors on the old HTML pointing at old hashes — they never see the fix until the HTML cache expires.
Why file:// is not a preview: the file protocol has different origin, CORS, and MIME-type rules than http. A site that works via file:// can still break when served — relative links, 404 handling, and module imports behave differently. Always preview via a static server.
Make it senior
- Add a custom domain with https and a redirect from the apex to www (or vice versa) so the site has a memorable URL.
- Add a _headers or _redirects file to set explicit Cache-Control and security headers (X-Content-Type-Options, Referrer-Policy).