Skip to content

Commit f87f8f0

Browse files
larsekhansenclaude
andauthored
Migrate frontend from Deno to Node/pnpm (#190)
* Migrate frontend from Deno to Node/npm Removes the dual-package-manager friction that bit us repeatedly: Trivy scans the npm lockfile while builds ran on Deno, so security bumps via Dependabot and local builds drifted apart. Single lockfile now (package-lock.json), tooling ecosystem expects npm anyway. - Dockerfile: denoland/deno:2.6.5 -> node:22-alpine (multi-stage, builder + runtime, npm ci with --omit=dev at runtime) - CI: setup-deno -> setup-node@v5 with built-in npm cache - package.json: add scripts (dev/build/preview/start/test:e2e*) - Delete deno.json + deno.lock Astro adapter (@astrojs/node) was already in deps. No source changes needed (no Deno.* APIs in src/). Verified locally: npm ci, npm run build, node dist/server/entry.mjs serves HTTP 200. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Switch frontend from npm to pnpm Aligns with the pnpm stub already present in the repo. Single package, not part of a workspace (root pnpm-workspace.yaml deleted since it never matched apps/*; can be added back if we ever extract shared packages). Changes: - apps/frontend: pnpm-lock.yaml replaces package-lock.json - Dockerfile: corepack enable + pnpm install --frozen-lockfile - CI: pnpm/action-setup + setup-node cache=pnpm - Root scripts (frontend:dev/build): pnpm instead of deno task - Docs (README, azure-deployment): commands updated - .gitignore: drop /deno.lock (Deno path retired) - dependabot.yml: comment updated; npm ecosystem reads pnpm-lock too - playwright.config.cjs webServer: pnpm run dev CMS folder unchanged. No Deno or stale npm artefacts left. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 203afa9 commit f87f8f0

15 files changed

Lines changed: 4407 additions & 9639 deletions

.github/dependabot.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
version: 2
22
updates:
3-
# Frontend (Astro/React/Deno-runtime npm deps)
3+
# Frontend (Astro/React on Node, managed with pnpm — Dependabot's npm
4+
# ecosystem reads pnpm-lock.yaml too).
45
- package-ecosystem: "npm"
56
directory: "/apps/frontend"
67
schedule:

.github/workflows/ci.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,28 @@ on:
88

99
jobs:
1010
frontend-build:
11-
name: Frontend (Astro/Deno) build
11+
name: Frontend (Astro/Node) build
1212
runs-on: ubuntu-latest
1313
steps:
1414
- uses: actions/checkout@v6
1515

16-
- uses: denoland/setup-deno@v2
16+
- uses: pnpm/action-setup@v4
1717
with:
18-
deno-version: v2.x
18+
version: 10
19+
20+
- uses: actions/setup-node@v5
21+
with:
22+
node-version: '22'
23+
cache: 'pnpm'
24+
cache-dependency-path: apps/frontend/pnpm-lock.yaml
1925

2026
- name: Install
2127
working-directory: apps/frontend
22-
run: deno task install
28+
run: pnpm install --frozen-lockfile
2329

2430
- name: Build
2531
working-directory: apps/frontend
26-
run: deno task build
32+
run: pnpm run build
2733

2834
cms-build:
2935
name: CMS (Umbraco/.NET) build

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ apps/cms/data/
3232
apps/cms/.strapi/
3333
apps/cms/.strapi-updater.json
3434

35-
# Deno (root-level lockfile is a stray artifact)
36-
/deno.lock
3735

3836
# Logs
3937
*.log

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ On first CMS run, the SQLite database is created, `ContentTypeComposer` creates
8383
all content types, and `ContentSeeder` populates demo content. Admin user is
8484
created via unattended install env vars.
8585

86-
**Terminal 2 — Frontend (Astro/Deno):**
86+
**Terminal 2 — Frontend (Astro/Node + pnpm):**
8787
```bash
8888
cd apps/frontend
89-
deno task dev
89+
pnpm install
90+
pnpm run dev
9091
```
9192
- Frontend: http://localhost:4321
9293

@@ -99,7 +100,7 @@ The frontend uses **hybrid rendering**:
99100

100101
In development, the Astro dev server re-fetches from Umbraco on each page load, so CMS changes appear on refresh.
101102

102-
In production, run `deno task build` to rebuild with latest content. Consider webhook-triggered rebuilds when CMS content changes.
103+
In production, run `pnpm run build` to rebuild with latest content. Consider webhook-triggered rebuilds when CMS content changes.
103104

104105
## Content Types
105106

@@ -175,13 +176,13 @@ The preview flow: Umbraco → Razor template redirect → `/api/preview?secret=.
175176
cd apps/frontend
176177

177178
# Run all tests (starts dev server automatically)
178-
deno task test:e2e
179+
pnpm run test:e2e
179180

180181
# Update visual regression snapshots
181-
deno task test:e2e:update
182+
pnpm run test:e2e:update
182183

183184
# Run tests with UI
184-
deno task test:e2e:ui
185+
pnpm run test:e2e:ui
185186
```
186187

187188
81 tests across 6 browser configurations (Chrome, Firefox, Safari, Chrome Dark, Mobile Chrome, Mobile Safari).

apps/frontend/Dockerfile

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1-
FROM denoland/deno:2.6.5
1+
# Multi-stage build: install + build with pnpm, run the standalone server on Node.
2+
# The Astro Node adapter outputs dist/server/entry.mjs which is a self-contained
3+
# HTTP server — no Astro CLI needed at runtime.
24

5+
FROM node:22-alpine AS builder
36
WORKDIR /app
47

5-
# Copy dependency files first for layer caching
6-
COPY deno.json deno.lock package.json ./
8+
# Enable corepack so pnpm is available (Node 22+ ships with corepack).
9+
RUN corepack enable
710

8-
# Install dependencies
9-
RUN deno install --allow-scripts=npm:sharp
11+
COPY package.json pnpm-lock.yaml ./
12+
RUN pnpm install --frozen-lockfile
1013

11-
# Copy source code
1214
COPY . .
15+
RUN pnpm run build
1316

14-
# Build the Astro site
15-
RUN deno task build
17+
# ─── Runtime stage ──────────────────────────────────────────────────────────
18+
FROM node:22-alpine
19+
WORKDIR /app
20+
21+
RUN corepack enable
22+
23+
# Production deps only at runtime; @astrojs/node bundles what it needs
24+
COPY package.json pnpm-lock.yaml ./
25+
RUN pnpm install --frozen-lockfile --prod && pnpm store prune
26+
27+
COPY --from=builder /app/dist ./dist
1628

17-
# The Node adapter outputs a standalone server at dist/server/entry.mjs
1829
ENV HOST=0.0.0.0
1930
ENV PORT=4321
31+
ENV NODE_ENV=production
2032
EXPOSE 4321
2133

22-
CMD ["deno", "-A", "dist/server/entry.mjs"]
34+
CMD ["node", "dist/server/entry.mjs"]

apps/frontend/deno.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)