VibecoderMcSwaggins CodeRabbit commited on
Commit
c0bb818
·
unverified ·
1 Parent(s): 66404dc

feat(deploy): HuggingFace Static Space for frontend (#34)

Browse files

## Changes
- Add frontend/.env.production with backend API URL
- Update frontend/README.md with HF Spaces YAML metadata
- Add path-based CI filtering (dorny/paths-filter)
- Fix frontend-build conditional to handle skipped jobs
- Update spec 36 to document Vite 7 tsconfig pattern

## CI Optimization
- Backend jobs only run on src/, tests/, pyproject.toml changes
- Frontend jobs only run on frontend/** changes
- Push to main runs full CI (safety gate)

Co-authored-by: CodeRabbit <coderabbit@users.noreply.github.com>

.github/workflows/ci.yml CHANGED
@@ -7,6 +7,11 @@ on:
7
  branches: [main]
8
  workflow_dispatch:
9
  inputs:
 
 
 
 
 
10
  run_integration:
11
  description: 'Run integration tests (requires HuggingFace download)'
12
  required: false
@@ -14,7 +19,35 @@ on:
14
  type: boolean
15
 
16
  jobs:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  lint:
 
 
18
  runs-on: ubuntu-latest
19
  steps:
20
  - uses: actions/checkout@v4
@@ -35,6 +68,8 @@ jobs:
35
  run: uv run ruff format --check .
36
 
37
  typecheck:
 
 
38
  runs-on: ubuntu-latest
39
  steps:
40
  - uses: actions/checkout@v4
@@ -52,6 +87,8 @@ jobs:
52
  run: uv run mypy src/
53
 
54
  test:
 
 
55
  runs-on: ubuntu-latest
56
  steps:
57
  - uses: actions/checkout@v4
@@ -107,8 +144,10 @@ jobs:
107
  env:
108
  HF_HOME: /tmp/hf_cache
109
 
110
- # Frontend Jobs
111
  frontend-lint:
 
 
112
  runs-on: ubuntu-latest
113
  defaults:
114
  run:
@@ -126,6 +165,8 @@ jobs:
126
  - run: npm run lint
127
 
128
  frontend-typecheck:
 
 
129
  runs-on: ubuntu-latest
130
  defaults:
131
  run:
@@ -143,6 +184,8 @@ jobs:
143
  - run: npx tsc --noEmit
144
 
145
  frontend-test:
 
 
146
  runs-on: ubuntu-latest
147
  defaults:
148
  run:
@@ -167,6 +210,8 @@ jobs:
167
  token: ${{ secrets.CODECOV_TOKEN }}
168
 
169
  frontend-e2e:
 
 
170
  runs-on: ubuntu-latest
171
  defaults:
172
  run:
@@ -193,8 +238,16 @@ jobs:
193
  retention-days: 7
194
 
195
  frontend-build:
 
 
 
 
 
 
 
 
 
196
  runs-on: ubuntu-latest
197
- needs: [frontend-lint, frontend-typecheck, frontend-test]
198
  defaults:
199
  run:
200
  working-directory: frontend
 
7
  branches: [main]
8
  workflow_dispatch:
9
  inputs:
10
+ run_all:
11
+ description: 'Run all jobs regardless of path filters'
12
+ required: false
13
+ default: false
14
+ type: boolean
15
  run_integration:
16
  description: 'Run integration tests (requires HuggingFace download)'
17
  required: false
 
19
  type: boolean
20
 
21
  jobs:
22
+ # Detect which paths changed to conditionally run jobs
23
+ changes:
24
+ runs-on: ubuntu-latest
25
+ outputs:
26
+ backend: ${{ steps.filter.outputs.backend }}
27
+ frontend: ${{ steps.filter.outputs.frontend }}
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - uses: dorny/paths-filter@v3
32
+ id: filter
33
+ with:
34
+ filters: |
35
+ backend:
36
+ - 'src/**'
37
+ - 'tests/**'
38
+ - 'pyproject.toml'
39
+ - 'requirements.txt'
40
+ - 'Dockerfile'
41
+ - '.github/workflows/ci.yml'
42
+ frontend:
43
+ - 'frontend/**'
44
+ - '.github/workflows/ci.yml'
45
+
46
+ # Backend Jobs - run on backend changes, main push, or manual override
47
+ # Design: Push to main always runs full CI (safety gate), PRs use path filtering (efficiency)
48
  lint:
49
+ needs: changes
50
+ if: needs.changes.outputs.backend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
51
  runs-on: ubuntu-latest
52
  steps:
53
  - uses: actions/checkout@v4
 
68
  run: uv run ruff format --check .
69
 
70
  typecheck:
71
+ needs: changes
72
+ if: needs.changes.outputs.backend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
73
  runs-on: ubuntu-latest
74
  steps:
75
  - uses: actions/checkout@v4
 
87
  run: uv run mypy src/
88
 
89
  test:
90
+ needs: changes
91
+ if: needs.changes.outputs.backend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
92
  runs-on: ubuntu-latest
93
  steps:
94
  - uses: actions/checkout@v4
 
144
  env:
145
  HF_HOME: /tmp/hf_cache
146
 
147
+ # Frontend Jobs - run on frontend changes, main push, or manual override
148
  frontend-lint:
149
+ needs: changes
150
+ if: needs.changes.outputs.frontend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
151
  runs-on: ubuntu-latest
152
  defaults:
153
  run:
 
165
  - run: npm run lint
166
 
167
  frontend-typecheck:
168
+ needs: changes
169
+ if: needs.changes.outputs.frontend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
170
  runs-on: ubuntu-latest
171
  defaults:
172
  run:
 
184
  - run: npx tsc --noEmit
185
 
186
  frontend-test:
187
+ needs: changes
188
+ if: needs.changes.outputs.frontend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
189
  runs-on: ubuntu-latest
190
  defaults:
191
  run:
 
210
  token: ${{ secrets.CODECOV_TOKEN }}
211
 
212
  frontend-e2e:
213
+ needs: changes
214
+ if: needs.changes.outputs.frontend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)
215
  runs-on: ubuntu-latest
216
  defaults:
217
  run:
 
238
  retention-days: 7
239
 
240
  frontend-build:
241
+ needs: [changes, frontend-lint, frontend-typecheck, frontend-test]
242
+ # Build if: (1) frontend changed OR push to main OR manual run_all, AND (2) no prerequisite failures
243
+ # Note: Uses != 'failure' instead of == 'success' to handle skipped jobs gracefully
244
+ if: |
245
+ always() &&
246
+ (needs.changes.outputs.frontend == 'true' || github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.run_all)) &&
247
+ needs.frontend-lint.result != 'failure' &&
248
+ needs.frontend-typecheck.result != 'failure' &&
249
+ needs.frontend-test.result != 'failure'
250
  runs-on: ubuntu-latest
 
251
  defaults:
252
  run:
253
  working-directory: frontend
docs/specs/frontend/36-frontend-without-gradio-hf-spaces.md CHANGED
@@ -207,28 +207,48 @@ export default defineConfig({
207
  })
208
  ```
209
 
210
- ### tsconfig.json
211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  ```json
213
  {
214
  "compilerOptions": {
215
- "target": "ES2020",
 
216
  "useDefineForClassFields": true,
217
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
218
  "module": "ESNext",
 
219
  "skipLibCheck": true,
220
  "moduleResolution": "bundler",
221
  "allowImportingTsExtensions": true,
222
- "isolatedModules": true,
223
  "moduleDetection": "force",
224
  "noEmit": true,
225
  "jsx": "react-jsx",
226
  "strict": true,
227
  "noUnusedLocals": true,
228
  "noUnusedParameters": true,
229
- "noFallthroughCasesInSwitch": true
 
 
230
  },
231
- "include": ["src"]
 
232
  }
233
  ```
234
 
@@ -710,7 +730,7 @@ colorTo: purple
710
  sdk: static
711
  app_file: dist/index.html
712
  app_build_command: npm run build
713
- # CRITICAL: Vite 6 requires Node.js >= 20. HF Spaces defaults to Node 18.
714
  # Without this, the build will fail or produce warnings.
715
  nodejs_version: "20"
716
  pinned: false
 
207
  })
208
  ```
209
 
210
+ ### TypeScript Configuration (Vite 7 Project References Pattern)
211
 
212
+ Vite 7 uses a project references pattern for better separation of app, test, and build configs:
213
+
214
+ **tsconfig.json** (root - references only):
215
+ ```json
216
+ {
217
+ "files": [],
218
+ "references": [
219
+ { "path": "./tsconfig.app.json" },
220
+ { "path": "./tsconfig.node.json" },
221
+ { "path": "./tsconfig.test.json" }
222
+ ]
223
+ }
224
+ ```
225
+
226
+ **tsconfig.app.json** (application code):
227
  ```json
228
  {
229
  "compilerOptions": {
230
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
231
+ "target": "ES2022",
232
  "useDefineForClassFields": true,
233
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
234
  "module": "ESNext",
235
+ "types": ["vite/client"],
236
  "skipLibCheck": true,
237
  "moduleResolution": "bundler",
238
  "allowImportingTsExtensions": true,
239
+ "verbatimModuleSyntax": true,
240
  "moduleDetection": "force",
241
  "noEmit": true,
242
  "jsx": "react-jsx",
243
  "strict": true,
244
  "noUnusedLocals": true,
245
  "noUnusedParameters": true,
246
+ "erasableSyntaxOnly": true,
247
+ "noFallthroughCasesInSwitch": true,
248
+ "noUncheckedSideEffectImports": true
249
  },
250
+ "include": ["src"],
251
+ "exclude": ["src/test", "src/mocks", "src/**/*.test.tsx", "src/**/*.test.ts"]
252
  }
253
  ```
254
 
 
730
  sdk: static
731
  app_file: dist/index.html
732
  app_build_command: npm run build
733
+ # CRITICAL: Vite 7 requires Node.js >= 20. HF Spaces defaults to Node 18.
734
  # Without this, the build will fail or produce warnings.
735
  nodejs_version: "20"
736
  pinned: false
frontend/.env.production ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Production environment - HuggingFace Spaces deployment
2
+ # Backend API running on Docker Space with T4 GPU
3
+ VITE_API_URL=https://vibecodermcswaggins-stroke-deepisles-demo.hf.space
frontend/README.md CHANGED
@@ -6,8 +6,7 @@ colorTo: purple
6
  sdk: static
7
  app_file: dist/index.html
8
  app_build_command: npm run build
9
- # CRITICAL: Vite 6 requires Node.js >= 20. HF Spaces defaults to Node 18.
10
- # Without this, the build will fail or produce warnings.
11
  nodejs_version: "20"
12
  pinned: false
13
  ---
@@ -61,5 +60,20 @@ npm run build # Production build
61
  Set `VITE_API_URL` to point to your backend:
62
 
63
  ```bash
 
64
  VITE_API_URL=http://localhost:7860 npm run dev
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  ```
 
6
  sdk: static
7
  app_file: dist/index.html
8
  app_build_command: npm run build
9
+ # CRITICAL: Vite 7 requires Node.js >= 20. HF Spaces defaults to Node 18.
 
10
  nodejs_version: "20"
11
  pinned: false
12
  ---
 
60
  Set `VITE_API_URL` to point to your backend:
61
 
62
  ```bash
63
+ # Local development (default)
64
  VITE_API_URL=http://localhost:7860 npm run dev
65
+
66
+ # Production is configured in .env.production
67
+ # Points to: https://vibecodermcswaggins-stroke-deepisles-demo.hf.space
68
+ ```
69
+
70
+ ## Deployment
71
+
72
+ This frontend deploys as a **HuggingFace Static Space**. The backend API runs on a separate Docker Space with GPU.
73
+
74
+ ```bash
75
+ # Build for production (uses .env.production)
76
+ npm run build
77
+
78
+ # The dist/ folder is deployed to HF Static Space
79
  ```