Skip to content

Commit fe0ff18

Browse files
committed
chore(frontend): migrate to pnpm and add lint tooling
1 parent 981b24c commit fe0ff18

17 files changed

Lines changed: 5319 additions & 5834 deletions

.devcontainer/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ RUN apk add --no-cache \
1616
yaml-dev \
1717
tzdata
1818

19+
RUN if ! command -v corepack >/dev/null 2>&1; then npm install -g corepack; fi \
20+
&& corepack enable \
21+
&& corepack prepare "pnpm@latest" --activate
22+
1923
ARG USER=vscode
2024
ARG UID=1000
2125
ARG GID=1000

.devcontainer/devcontainer.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
"vscode": {
99
"extensions": [
1010
"rebornix.ruby",
11-
"esbenp.prettier-vscode"
11+
"esbenp.prettier-vscode",
12+
"dbaeumer.vscode-eslint"
1213
],
1314
"settings": {
1415
"editor.formatOnSave": true,
1516
"editor.defaultFormatter": "esbenp.prettier-vscode",
17+
"editor.codeActionsOnSave": {
18+
"source.fixAll.eslint": "explicit"
19+
},
20+
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
1621
"prettier.configPath": "./frontend/prettier.config.js",
1722
"ruby.format": "rubocop",
1823
"ruby.lint": { "rubocop": true },

.github/workflows/ci.yml

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,20 @@ jobs:
5454
with:
5555
bundler-cache: true
5656

57+
- name: Setup pnpm
58+
uses: pnpm/action-setup@v4
59+
with:
60+
cache: true
61+
cache_dependency_path: frontend/pnpm-lock.yaml
62+
package_json_file: frontend/package.json
63+
5764
- name: Setup Node.js for OpenAPI lint tooling
5865
uses: actions/setup-node@v6
5966
with:
6067
node-version-file: ".tool-versions"
61-
cache: npm
62-
cache-dependency-path: frontend/package-lock.json
6368

6469
- name: Install frontend dependencies for OpenAPI client verification
65-
run: npm ci
70+
run: pnpm install --frozen-lockfile
6671
working-directory: frontend
6772

6873
- name: Verify generated OpenAPI spec and client are up to date
@@ -79,33 +84,41 @@ jobs:
7984
steps:
8085
- uses: actions/checkout@v6
8186

87+
- name: Setup pnpm
88+
uses: pnpm/action-setup@v4
89+
with:
90+
cache: true
91+
cache_dependency_path: frontend/pnpm-lock.yaml
92+
package_json_file: frontend/package.json
93+
8294
- name: Setup Node.js
8395
uses: actions/setup-node@v6
8496
with:
8597
node-version-file: ".tool-versions"
86-
cache: npm
87-
cache-dependency-path: frontend/package-lock.json
8898

8999
- name: Install dependencies
90-
run: npm ci
100+
run: pnpm install --frozen-lockfile
91101

92102
- name: Typecheck frontend
93-
run: npm run typecheck
103+
run: pnpm run typecheck
104+
105+
- name: Lint CSS with Stylelint
106+
run: pnpm exec stylelint "**/*.css"
94107

95108
- name: Check formatting
96-
run: npm run format:check
109+
run: pnpm run format:check
97110

98111
- name: Audit dependencies
99-
run: npm audit --audit-level=moderate
112+
run: pnpm audit --audit-level=moderate
100113

101114
- name: Run frontend tests
102-
run: npm run test:ci
115+
run: pnpm run test:ci
103116

104117
- name: Install Playwright Chromium
105-
run: npx playwright install --with-deps chromium
118+
run: pnpm exec playwright install --with-deps chromium
106119

107120
- name: Run frontend smoke test
108-
run: npm run test:e2e
121+
run: pnpm run test:e2e
109122

110123
docker-build-smoke-image:
111124
needs:
@@ -175,19 +188,24 @@ jobs:
175188
- name: Checkout code
176189
uses: actions/checkout@v6
177190

191+
- name: Setup pnpm
192+
uses: pnpm/action-setup@v4
193+
with:
194+
cache: true
195+
cache_dependency_path: frontend/pnpm-lock.yaml
196+
package_json_file: frontend/package.json
197+
178198
- name: Setup Node.js for Docker build
179199
uses: actions/setup-node@v6
180200
with:
181201
node-version-file: ".tool-versions"
182-
cache: npm
183-
cache-dependency-path: frontend/package-lock.json
184202

185203
- name: Install frontend dependencies
186-
run: npm ci
204+
run: pnpm install --frozen-lockfile
187205
working-directory: frontend
188206

189207
- name: Build frontend static assets
190-
run: npm run build
208+
run: pnpm run build
191209
working-directory: frontend
192210

193211
- name: Set up QEMU

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ ARG NODE_BASE_IMAGE=node:22-alpine@sha256:8094c002d08262dba12645a3b4a15cd6cd627d
55
FROM ${NODE_BASE_IMAGE} AS frontend-builder
66

77
WORKDIR /app/frontend
8-
COPY frontend/package*.json ./
9-
RUN npm ci
8+
COPY frontend/package.json frontend/pnpm-lock.yaml ./
9+
RUN corepack enable && pnpm install --frozen-lockfile
1010
COPY frontend/ ./
11-
RUN npm run build
11+
RUN pnpm run build
1212

1313
# Stage 2: Ruby Build
1414
FROM ${RUBY_BASE_IMAGE} AS builder

Makefile

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ setup: ## Full development setup
1818
fi
1919
@mkdir -p tmp/rack-cache-body tmp/rack-cache-meta
2020
@echo "Setting up frontend..."
21-
@cd frontend && npm install
21+
@cd frontend && CI=1 pnpm install --frozen-lockfile
2222
@echo "Setup complete!"
2323

2424
dev: ## Start development server with live reload
@@ -29,26 +29,26 @@ dev-ruby: ## Start Ruby server only
2929
@bin/dev-ruby
3030

3131
dev-frontend: ## Start frontend dev server only
32-
@cd frontend && npm run dev
32+
@cd frontend && pnpm run dev
3333

3434
test: ## Run all tests (Ruby + Frontend)
3535
bundle exec rspec
36-
@cd frontend && npm run test:ci
36+
@cd frontend && pnpm run test:ci
3737

3838
test-ruby: ## Run Ruby tests only
3939
bundle exec rspec
4040

4141
test-frontend: ## Run frontend tests only
42-
@cd frontend && npm run test:ci
42+
@cd frontend && pnpm run test:ci
4343

4444
test-frontend-unit: ## Run frontend unit tests only
45-
@cd frontend && npm run test:unit
45+
@cd frontend && pnpm run test:unit
4646

4747
test-frontend-contract: ## Run frontend contract tests only
48-
@cd frontend && npm run test:contract
48+
@cd frontend && pnpm run test:contract
4949

5050
test-frontend-e2e: ## Run frontend Playwright smoke tests
51-
@cd frontend && npm run test:e2e
51+
@cd frontend && pnpm run test:e2e
5252

5353
check-frontend: ## Run frontend typecheck, format, and test checks
5454
$(MAKE) lint-js
@@ -67,11 +67,15 @@ lint-ruby: ## Run Ruby linter (RuboCop) - errors when issues found
6767
bundle exec rake yard:verify_public_docs
6868
@echo "Ruby linting complete!"
6969

70-
lint-js: ## Run JavaScript/Frontend linter (Prettier) - errors when issues found
70+
lint-js: ## Run JavaScript/Frontend linting (TypeScript + ESLint + Stylelint + Prettier) - errors when issues found
7171
@echo "Running TypeScript typecheck..."
72-
@cd frontend && npm run typecheck
72+
@cd frontend && pnpm run typecheck
73+
@echo "Running ESLint..."
74+
@cd frontend && pnpm run lint
75+
@echo "Running Stylelint..."
76+
@cd frontend && pnpm exec stylelint "../public/shared-ui.css" "**/*.css"
7377
@echo "Running Prettier format check..."
74-
@cd frontend && npm run format:check
78+
@cd frontend && pnpm run format:check
7579
@echo "JavaScript linting complete!"
7680

7781
lintfix: lintfix-ruby lintfix-js ## Auto-fix all linting issues (Ruby + Frontend)
@@ -83,8 +87,10 @@ lintfix-ruby: ## Auto-fix Ruby linting issues
8387
@echo "Ruby lintfix complete!"
8488

8589
lintfix-js: ## Auto-fix JavaScript/Frontend linting issues
90+
@echo "Running ESLint auto-fix..."
91+
@cd frontend && pnpm run lint:fix
8692
@echo "Running Prettier formatting..."
87-
@cd frontend && npm run format
93+
@cd frontend && pnpm run format
8894
@echo "JavaScript lintfix complete!"
8995

9096
quick-check: ## Fast local checks (Ruby lint/docs + frontend format/typecheck)
@@ -110,10 +116,10 @@ openapi-verify: ## Regenerate OpenAPI and fail if public/openapi.yaml or fronten
110116
$(MAKE) openapi-client-verify
111117

112118
openapi-client: ## Generate frontend OpenAPI client/types from public/openapi.yaml
113-
@cd frontend && npm run openapi:generate
119+
@cd frontend && pnpm run openapi:generate
114120

115121
openapi-client-verify: ## Generate frontend OpenAPI client and fail if generated files are stale
116-
@cd frontend && npm run openapi:verify
122+
@cd frontend && pnpm run openapi:verify
117123

118124
openapi-lint: openapi-lint-redocly openapi-lint-spectral ## Lint public/openapi.yaml with Redocly and Spectral
119125

@@ -132,5 +138,5 @@ clean: ## Clean temporary files
132138

133139
frontend-setup: ## Setup frontend dependencies
134140
@echo "Setting up frontend dependencies..."
135-
@cd frontend && npm install
141+
@cd frontend && CI=1 pnpm install --frozen-lockfile
136142
@echo "Frontend setup complete!"

bin/dev

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ cleanup() {
2828

2929
# Kill frontend dev server and its children
3030
if [ ! -z "$FRONTEND_PID" ]; then
31-
# Kill the npm process and its children
31+
# Kill the frontend package-manager process and its children
3232
pkill -P $FRONTEND_PID 2>/dev/null || true
3333
kill $FRONTEND_PID 2>/dev/null || true
3434
wait $FRONTEND_PID 2>/dev/null || true
@@ -79,7 +79,7 @@ fi
7979

8080
# Start frontend dev server
8181
cd frontend
82-
npm run dev &
82+
pnpm run dev &
8383
FRONTEND_PID=$!
8484

8585
# Verify frontend server started

bin/dev-with-frontend

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ echo "Starting frontend dev server with API proxy..."
4949
cd frontend
5050

5151
# Start frontend dev server (it will proxy API calls to Ruby server)
52-
npm run dev &
52+
pnpm run dev &
5353
FRONTEND_PID=$!
5454

5555
# Wait a moment for the frontend server to start

frontend/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist/
3+
.astro

frontend/.prettierignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Frontend package files
2-
package-lock.json
2+
pnpm-lock.yaml
33
yarn.lock
44

55
# Generated and transient frontend output

frontend/eslint.config.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import js from '@eslint/js';
2+
import globals from 'globals';
3+
import reactHooks from 'eslint-plugin-react-hooks';
4+
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
5+
import tseslint from 'typescript-eslint';
6+
7+
export default tseslint.config(
8+
{
9+
ignores: ['.astro/**', 'dist/**', 'node_modules/**', 'src/api/generated/**', 'test-results/**'],
10+
},
11+
{
12+
files: ['src/**/*.{js,jsx,ts,tsx}', 'e2e/**/*.ts', './*.{js,ts}'],
13+
extends: [
14+
js.configs.recommended,
15+
...tseslint.configs.recommended,
16+
eslintPluginUnicorn.configs.recommended,
17+
],
18+
languageOptions: {
19+
ecmaVersion: 'latest',
20+
sourceType: 'module',
21+
globals: {
22+
...globals.browser,
23+
...globals.node,
24+
...globals.vitest,
25+
},
26+
},
27+
plugins: {
28+
'react-hooks': reactHooks,
29+
},
30+
rules: {
31+
'react-hooks/rules-of-hooks': 'error',
32+
'react-hooks/exhaustive-deps': 'off',
33+
'@typescript-eslint/no-explicit-any': 'off',
34+
'unicorn/filename-case': 'off',
35+
'unicorn/better-regex': 'warn',
36+
},
37+
}
38+
);

0 commit comments

Comments
 (0)