feat: add Cloudflare Pages deployment support

next.config.mjs now detects CF_PAGES=1 (auto-injected by Cloudflare during
build) and switches basePath from /loto to "" — assets resolve at the
project root on loto.pages.dev. GH Pages keeps /loto unchanged.

New workflow .github/workflows/deploy-cloudflare-pages.yml mirrors the GH
Pages flow but publishes via cloudflare/wrangler-action@v3. Requires repo
secrets CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID; project name "loto"
is hardcoded — adjust --project-name= in the workflow if your CF Pages
project uses a different name.

Dashboard-based deploys also work without code changes thanks to the
CF_PAGES detection. See docs/deployment-guide.md for both paths.
This commit is contained in:
tiennm99 committed 2026-04-26 20:12:51 +07:00
1 parent e2dab7dd4e
commit 0916f7706f
3 files changed
+80 -14

No files matched your search

@@ -0,0 +1,36 @@
name: Deploy to Cloudflare Pages
on:
push:
branches: [master]
workflow_dispatch:
permissions:
contents: read
deployments: write
concurrency:
group: cf-pages
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
env:
# Force root basePath: CF Pages serves the site at the project root
# (loto.pages.dev), unlike GH Pages which prefixes with /loto.
NEXT_BASE_PATH: ""
- name: Publish to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy out --project-name=loto --branch=${{ github.ref_name }}
+38 -13
View File
@@ -1,26 +1,51 @@
# Deployment Guide
## Production Deployment (GitHub Pages)
## Production Deployment
### Automatic Deploy
The app auto-deploys from the `master` branch via `.github/workflows/deploy.yml`.
### GitHub Pages (default)
**Workflow**:
1. Push to `master`
2. GitHub Actions runs `npm run build`
3. Static export written to `out/` directory
4. Pages deployed to `https://{user}.github.io/loto`
Auto-deploys from `master` via `.github/workflows/deploy.yml`. Static export is
written to `out/`, then uploaded as a Pages artifact. Reachable at
`https://{user}.github.io/loto`.
**Note**: basePath is set to `/loto` in production (`next.config.mjs:23`).
basePath is set to `/loto` because GH Pages serves the project under that path
prefix. See `next.config.mjs`.
### Cloudflare Pages
Two ways to wire it up:
**Option A — Dashboard:**
1. dash.cloudflare.com → Workers & Pages → Create → Pages → Connect to Git → pick the repo
2. Build settings:
- Framework preset: `Next.js (Static HTML Export)`
- Build command: `npm run build`
- Build output directory: `out`
- Production branch: `master`
3. No env vars needed — `next.config.mjs` detects `CF_PAGES=1` (auto-injected by
Cloudflare) and switches basePath to root automatically.
**Option B — GitHub Actions (`.github/workflows/deploy-cloudflare-pages.yml`):**
Add two repo secrets:
- `CLOUDFLARE_API_TOKEN` — dash → My Profile → API Tokens → Create with the
`Pages — Edit` template
- `CLOUDFLARE_ACCOUNT_ID` — visible in the dash sidebar
Then push to `master` and the workflow uses `cloudflare/wrangler-action@v3` to
publish `out/` to a Pages project named `loto`. The workflow sets
`NEXT_BASE_PATH=""` explicitly so the build produces root-relative asset paths.
The two providers can run in parallel — they don't conflict. Disable whichever
you stop wanting by deleting its workflow file.
### Manual Deploy
### Manual Deploy (if needed)
```bash
npm run build
# out/ directory ready for upload
# out/ directory ready for upload to any static host
```
Then deploy `out/` folder to GitHub Pages or any static host.
## Development Environment
### Local Dev
+6 -1
View File
@@ -1,5 +1,8 @@
const isProd = process.env.NODE_ENV === "production";
const isCodeserver = process.env.NEXT_DEV_PROFILE === "codeserver";
// Cloudflare Pages injects CF_PAGES=1 during its build; avoid the GH Pages
// /loto basePath there since CF serves the site at the root.
const isCfPages = process.env.CF_PAGES === "1";
// In dev under code-server's reverse proxy, basePath/assetPrefix must match
// the proxy URL so links, assets, and the HMR socket all resolve.
@@ -20,7 +23,9 @@ function codeserverConfig() {
const cs = isCodeserver ? codeserverConfig() : null;
// NEXT_BASE_PATH wins so custom-domain / fork deploys don't have to edit code.
const basePath =
process.env.NEXT_BASE_PATH ?? cs?.basePath ?? (isProd ? "/loto" : "");
process.env.NEXT_BASE_PATH ??
cs?.basePath ??
(isCfPages ? "" : isProd ? "/loto" : "");
const nextConfig = {
output: "export",