fix(deploy): configure pnpm allowBuilds and add Cloudflare deployment setup

This commit is contained in:
2026-08-10 22:37:41 +08:00
parent ddfec7258f
commit 88039d9ebe
8 changed files with 1029 additions and 49 deletions
+72
View File
@@ -0,0 +1,72 @@
name: CI
# Gitea Actions mirror of .github/workflows/ci.yml.
# Typecheck / test / build on every push & PR; deploy the SPA to Cloudflare
# Workers (static assets) on pushes to main.
#
# Required Gitea config (Repo → Settings → Actions → Secrets / Variables):
# Variable VITE_API_BASE_URL — Laravel API base URL baked into the build
# Secret CLOUDFLARE_API_TOKEN — token with "Edit Cloudflare Workers" scope
# Secret CLOUDFLARE_ACCOUNT_ID — Cloudflare account id
#
# Requires an act_runner registered with the `ubuntu-latest` label, using an
# image that has git + node bootstrapping (e.g. catthehacker/ubuntu:act-22.04).
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ gitea.ref }}
cancel-in-progress: true
jobs:
check:
name: Typecheck, test & build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run generate-routes
- run: pnpm run typecheck
- run: pnpm test
- run: pnpm run build
env:
VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL }}
deploy:
name: Deploy to Cloudflare Workers
needs: check
if: gitea.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run generate-routes
# cf:build runs `vite build` then copies the TanStack Start SPA shell
# (_shell.html) to index.html so Cloudflare's single-page-application
# fallback (wrangler.jsonc) returns it for every client route.
- name: Build SPA
run: pnpm run cf:build
env:
VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL }}
- name: Deploy
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+68
View File
@@ -0,0 +1,68 @@
name: CI
# Typecheck / test / build on every push & PR; deploy the SPA to Cloudflare
# Workers (static assets) on pushes to main.
#
# Required GitHub config (Settings → Secrets and variables → Actions):
# Variable VITE_API_BASE_URL — Laravel API base URL baked into the build
# Secret CLOUDFLARE_API_TOKEN — token with "Edit Cloudflare Workers" scope
# Secret CLOUDFLARE_ACCOUNT_ID — Cloudflare account id
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
name: Typecheck, test & build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run generate-routes
- run: pnpm run typecheck
- run: pnpm test
- run: pnpm run build
env:
VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL }}
deploy:
name: Deploy to Cloudflare Workers
needs: check
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm run generate-routes
# cf:build runs `vite build` then copies the TanStack Start SPA shell
# (_shell.html) to index.html so Cloudflare's single-page-application
# fallback (wrangler.jsonc) returns it for every client route.
- name: Build SPA
run: pnpm run cf:build
env:
VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL }}
- name: Deploy
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+2
View File
@@ -11,3 +11,5 @@ dist-ssr
.vinxi
__unconfig*
todos.json
*.profraw
+35
View File
@@ -31,6 +31,41 @@ ddev exec php artisan tinker storage/app/e2e-admin-seed.php
| `pnpm test` | vitest (API client envelope/refresh/error tests) |
| `pnpm gen:api` | regenerate `src/api/types.gen.ts` from the backend's scribe-admin OpenAPI spec (`../gig-platform/public/api-docs/admin/openapi.yaml`; run `ddev exec php artisan scribe:generate --config scribe-admin` there first) |
## Deploy
The app is a client-rendered SPA served as static assets by a Cloudflare Worker
(`wrangler.jsonc`, `not_found_handling: single-page-application`). The build
emits `_shell.html`, which is copied to `index.html` so Cloudflare's SPA
fallback returns it for every client route.
**Manual deploy** (needs `wrangler login` or `CLOUDFLARE_API_TOKEN` /
`CLOUDFLARE_ACCOUNT_ID` in your env):
```bash
pnpm cf:deploy # vite build → copy shell to index.html → wrangler deploy
```
**CI/CD** — every push & PR runs typecheck + test + build; pushes to `main`
build and deploy to Cloudflare. Two mirrored pipelines are provided:
| Platform | Workflow |
| --- | --- |
| GitHub Actions | `.github/workflows/ci.yml` |
| Gitea Actions | `.gitea/workflows/ci.yml` |
Configure these on the repo before the first deploy:
| Type | Name | Value |
| --- | --- | --- |
| Variable | `VITE_API_BASE_URL` | backend API origin baked into the build |
| Secret | `CLOUDFLARE_API_TOKEN` | token with "Edit Cloudflare Workers" scope |
| Secret | `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account id |
- GitHub: *Settings → Secrets and variables → Actions*.
- Gitea: *Repo → Settings → Actions → Secrets / Variables*. Actions must be
enabled and an `act_runner` registered with the `ubuntu-latest` label (use an
image such as `catthehacker/ubuntu:act-22.04`).
## Architecture notes
- **Auth**: Bearer tokens in localStorage (zustand persist). `src/api/client.ts`
+5 -8
View File
@@ -12,7 +12,9 @@
"preview": "vite preview",
"test": "vitest run",
"gen:api": "node scripts/gen-api.mjs",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"cf:build": "vite build && node -e \"require('fs').copyFileSync('.output/public/_shell.html','.output/public/index.html')\"",
"cf:deploy": "pnpm cf:build && wrangler deploy"
},
"dependencies": {
"@hookform/resolvers": "^5.4.0",
@@ -58,12 +60,7 @@
"openapi-typescript": "^7.13.0",
"typescript": "^6.0.2",
"vite": "^8.0.0",
"vitest": "^4.1.5"
},
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"lightningcss"
]
"vitest": "^4.1.5",
"wrangler": "^4.111.0"
}
}
+824 -41
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
allowBuilds:
esbuild: true
lightningcss: true
sharp: true
workerd: true
+17
View File
@@ -0,0 +1,17 @@
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "gig-admin",
"compatibility_date": "2026-07-15",
// Assets-only Worker: gig-admin is a client-rendered SPA (see vite.config.ts
// `spa: { enabled: true }`), so there is no server to run Cloudflare just
// serves the static build and falls back to the SPA shell for client routes.
// `pnpm cf:build` copies the TanStack Start shell to index.html, which
// `single-page-application` handling serves for any non-asset request.
"assets": {
"directory": ".output/public",
"not_found_handling": "single-page-application"
},
"observability": {
"enabled": true
}
}