Skip to content

Commit 6cbcde5

Browse files
authored
feat: frontend scaffold (Vite + React 19.2 + TS strict, eslint flat + prettier + vitest) (#21) (#58)
1 parent 1c09345 commit 6cbcde5

29 files changed

Lines changed: 6969 additions & 1 deletion

.github/branch-protection/develop.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
"Coverage",
99
"Architecture (import-linter)",
1010
"Pre-commit",
11+
"Frontend Build",
12+
"Frontend Quality",
1113
"Branch-protection contexts sync",
1214
"Commit-type sync",
1315
"Lint PR title (conventional commits)",
1416
"Secret scan (gitleaks)",
1517
"Python deps (pip-audit)",
18+
"Frontend deps (npm audit)",
1619
"Container image scan (trivy)"
1720
]
1821
},

.github/branch-protection/main.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
"Coverage",
99
"Architecture (import-linter)",
1010
"Pre-commit",
11+
"Frontend Build",
12+
"Frontend Quality",
1113
"Branch-protection contexts sync",
1214
"Commit-type sync",
1315
"Lint PR title (conventional commits)",
1416
"Secret scan (gitleaks)",
1517
"Python deps (pip-audit)",
18+
"Frontend deps (npm audit)",
1619
"Container image scan (trivy)"
1720
]
1821
},

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,37 @@ jobs:
9191
- run: uv sync --frozen --extra dev
9292
- run: uv run pre-commit run --all-files --show-diff-on-failure
9393

94+
frontend-build:
95+
name: Frontend Build
96+
runs-on: ubuntu-latest
97+
steps:
98+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
99+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
100+
with:
101+
node-version: "24"
102+
cache: npm
103+
cache-dependency-path: frontend/package-lock.json
104+
- run: cd frontend && npm ci && npm run build
105+
106+
frontend-quality:
107+
name: Frontend Quality
108+
runs-on: ubuntu-latest
109+
# Lint + format + tsc + vitest. Mirrors the strict posture the backend
110+
# enjoys (ruff + mypy + pytest); the Frontend Build job above validates
111+
# the bundler output, this one validates source quality.
112+
steps:
113+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
114+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
115+
with:
116+
node-version: "24"
117+
cache: npm
118+
cache-dependency-path: frontend/package-lock.json
119+
- run: cd frontend && npm ci
120+
- run: cd frontend && npm run lint
121+
- run: cd frontend && npm run format:check
122+
- run: cd frontend && npm run check
123+
- run: cd frontend && npm run test
124+
94125
branch-protection-sync:
95126
name: Branch-protection contexts sync
96127
runs-on: ubuntu-latest

.github/workflows/security.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,20 @@ jobs:
6767
--vulnerability-service osv \
6868
$IGNORES
6969
70-
# Frontend deps (npm audit) — added by ticket #21 alongside frontend/.
70+
npm-audit:
71+
name: Frontend deps (npm audit)
72+
runs-on: ubuntu-latest
73+
steps:
74+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
75+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
76+
with:
77+
node-version: "24"
78+
cache: npm
79+
cache-dependency-path: frontend/package-lock.json
80+
- run: cd frontend && npm ci
81+
# --audit-level=high — fail only on high/critical; moderate/low noted
82+
# but not blocking.
83+
- run: cd frontend && npm audit --audit-level=high
7184

7285
trivy-image:
7386
name: Container image scan (trivy)

frontend/.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules/
2+
dist/
3+
build/
4+
coverage/
5+
.vite/
6+
*.log
7+
.git/
8+
.env
9+
.env.*

frontend/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

frontend/.prettierignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
dist/
2+
build/
3+
node_modules/
4+
coverage/
5+
*.min.js
6+
*.min.css
7+
package-lock.json
8+
.vite/

frontend/.prettierrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true,
4+
"trailingComma": "es5",
5+
"printWidth": 100,
6+
"tabWidth": 2,
7+
"arrowParens": "always",
8+
"endOfLine": "lf"
9+
}

frontend/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Frontend dev container — Vite dev server on :5173.
2+
#
3+
# docker-compose.yml mounts the host's frontend/ over /app and a separate
4+
# anonymous volume over /app/node_modules so platform-native deps survive.
5+
# The node_modules baked into this image is the production-resolved set the
6+
# CI image scan inspects; the bind-mount overrides it at runtime.
7+
#
8+
# For a real deployment, add a multi-stage build that runs `npm run build`
9+
# and copies dist/ onto an nginx:alpine; for the template's local-dev focus
10+
# the dev server is sufficient.
11+
12+
FROM node:24-slim
13+
14+
WORKDIR /app
15+
16+
COPY package.json package-lock.json* ./
17+
RUN npm ci || npm install
18+
19+
COPY . .
20+
21+
EXPOSE 5173
22+
23+
# --host 0.0.0.0 so the dev server is reachable from outside the container.
24+
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]

frontend/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
9+
10+
## React Compiler
11+
12+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13+
14+
## Expanding the ESLint configuration
15+
16+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17+
18+
```js
19+
export default defineConfig([
20+
globalIgnores(['dist']),
21+
{
22+
files: ['**/*.{ts,tsx}'],
23+
extends: [
24+
// Other configs...
25+
26+
// Remove tseslint.configs.recommended and replace with this
27+
tseslint.configs.recommendedTypeChecked,
28+
// Alternatively, use this for stricter rules
29+
tseslint.configs.strictTypeChecked,
30+
// Optionally, add this for stylistic rules
31+
tseslint.configs.stylisticTypeChecked,
32+
33+
// Other configs...
34+
],
35+
languageOptions: {
36+
parserOptions: {
37+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
38+
tsconfigRootDir: import.meta.dirname,
39+
},
40+
// other options...
41+
},
42+
},
43+
])
44+
```
45+
46+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47+
48+
```js
49+
// eslint.config.js
50+
import reactX from 'eslint-plugin-react-x'
51+
import reactDom from 'eslint-plugin-react-dom'
52+
53+
export default defineConfig([
54+
globalIgnores(['dist']),
55+
{
56+
files: ['**/*.{ts,tsx}'],
57+
extends: [
58+
// Other configs...
59+
// Enable lint rules for React
60+
reactX.configs['recommended-typescript'],
61+
// Enable lint rules for React DOM
62+
reactDom.configs.recommended,
63+
],
64+
languageOptions: {
65+
parserOptions: {
66+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
67+
tsconfigRootDir: import.meta.dirname,
68+
},
69+
// other options...
70+
},
71+
},
72+
])
73+
```

0 commit comments

Comments
 (0)