5.8 KiB
First-time deployment
Everything needed to take this repo from a fresh clone to a live deploy of
mnswpr.com. Once it's set up you won't need this again —
day to day, pnpm release is the whole story.
Two services are involved: Netlify hosts the site, Firebase (Firestore) stores the leaderboard. Both are driven entirely from the CLI; nothing here requires a web dashboard except one Netlify setting noted below.
For the conceptual split between infra config (committed, declarative) and infra tools (pinned devDependencies), see AGENTS.md → "Infra".
0. Prerequisites
pnpm i # installs firebase-tools and netlify-cli as pinned devDependencies
Both CLIs are invoked through pnpm exec, so you never need a global install.
1. Netlify
Log in and link the repo
pnpm exec netlify login
pnpm exec netlify link # binds this directory to the site; writes .netlify/ (gitignored)
If you know the site ID you can skip the prompts:
pnpm exec netlify link --id <site-id>
Losing .netlify/ is harmless — it's local state. Re-run netlify link.
Set the base directory
The site's base directory must be the repo root. This is the one setting that isn't in a config file — it lives on the site itself (Site configuration → Build & deploy → Base directory) and must be empty.
If it points at a subdirectory that doesn't exist, git-triggered builds fail before they start.
Set the environment variables
This is the step most likely to be missed, because it only affects one of the two deploy paths:
pnpm run deploy:sitebuilds locally and uploadsdist/. It reads your local, gitignored.env.production— Netlify's env vars are never consulted.pnpm releaseforce-pushes thereleasebranch, and Netlify builds it from git. That build runs on Netlify's machines with no access to any local file, so it needs the variables set on the site.
A site that deploys fine via deploy:site can still ship a broken build from
git if these are missing — the Firebase config comes out undefined and the
leaderboard fails for every visitor.
The eight values are the same ones committed in .env.development: prod and
dev are the same Firebase project (see firebase/.firebaserc), separated
only by collection namespace. So you can set them straight from that file:
grep -E '^VITE_FIREBASE_' .env.development | while IFS='=' read -r k v; do
pnpm exec netlify env:set "$k" "$v"
done
That covers:
VITE_FIREBASE_API_KEY VITE_FIREBASE_STORAGE_BUCKET
VITE_FIREBASE_AUTH_DOMAIN VITE_FIREBASE_MESSAGING_SENDER_ID
VITE_FIREBASE_DATABASE_URL VITE_FIREBASE_APP_ID
VITE_FIREBASE_PROJECT_ID VITE_FIREBASE_MEASUREMENT_ID
Two variables are deliberately not in that list:
VITE_LB_NAMESPACEis already set tomwinnetlify.toml, so it ships with the repo. (src/main.jsdefaults tomw-testwhen it's missing, so a misconfigured build writes to the test board, never production.)VITE_FIRESTORE_EMULATORmust stay absent or empty in production.src/main.jstreats1/true/yesas "connect to a local emulator", so if it leaks into the site's environment the live leaderboard silently tries to reach127.0.0.1:8080and fails for everyone. It belongs only in.env.development.
Verify what's actually set:
pnpm exec netlify env:list
These are not secrets. Firebase Web API keys are public by design — they identify the project, they don't authorize anything. Access is governed by
firebase/firestore.rules. They're kept out of git as prod hygiene, not because exposure is dangerous; the dev values are committed for this reason.
2. Firebase
Log in
pnpm exec firebase login
Deploy the security rules
Do this before the first real release. firebase/firestore.rules is the
source of truth for who can read and write the leaderboard, but it only takes
effect once deployed — a project can be running rules set by hand in the console
long ago, which won't match the repo.
pnpm run deploy:db # firebase --config firebase/firebase.json deploy --only firestore
That deploys rules and indexes. Note that prod and dev are the same
Firebase project, so a rules deploy affects both environments at once.
If the rules are stale, leaderboard writes fail with permission-denied even though the site loads fine — worth confirming after the first deploy by finishing a game and checking the score appears.
3. Deploy
Two paths, both supported:
pnpm run deploy:site # build locally, upload dist/ via the Netlify CLI
or the full release, which is what tags a version and triggers the git build:
pnpm release # lint + test, then bumpp, then sync the release branch
pnpm release runs scripts/release.js, which force-pushes main to the
release branch on the gh remote. That push is the deploy — Netlify
watches that branch. It refuses to run from a branch other than main or with a
dirty working tree.
Verifying a first deploy
pnpm exec netlify env:listshows all eightVITE_FIREBASE_*and noVITE_FIRESTORE_EMULATOR.- The site loads and the version in the heading matches
package.json. - Finish a game — your score appears on the board. This is the real end-to-end check: it exercises the env vars, the rules, and the namespace together.
- The leaderboard shows the
mwnamespace, notmw-test.
Related
firebase-leaderboards.md— data model, rules, environments, deployment detailsfirestore-emulator.md— running the leaderboard locallyleaderboard-env-migration.md— history of the env-var/namespace migration