Skip to content

Commit d394bb3

Browse files
Rewrite frontend in sveltekit (#140)
* Scaffold SvelteKit frontend v2 and add smoke test * Configure SvelteKit v2 for GitHub Pages deployment * Add new frontend badge * Refine frontend v2 production UX and starter snippets * Deploy frontend at codecanvas subdomain * Address frontend review comments
1 parent 5d3f92f commit d394bb3

24 files changed

Lines changed: 2654 additions & 1 deletion

.github/workflows/ci.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,22 @@ jobs:
3030
run: docker login --username "$DOCKERHUB_USERNAME" --password "$DOCKERHUB_TOKEN"
3131
- name: Runs golang tests, lints and web tests
3232
run: earthly --ci +run-ci
33+
34+
frontend-v2:
35+
runs-on: ubuntu-latest
36+
defaults:
37+
run:
38+
working-directory: web-frontend-v2
39+
steps:
40+
- uses: actions/checkout@v4
41+
- uses: actions/setup-node@v4
42+
with:
43+
node-version: 22
44+
cache: npm
45+
cache-dependency-path: web-frontend-v2/package-lock.json
46+
- name: Install frontend v2 dependencies
47+
run: npm ci
48+
- name: Typecheck frontend v2
49+
run: npm run check
50+
- name: Build frontend v2 with GitHub Pages settings
51+
run: npm run build:pages
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Deploy Web Frontend v2 to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "web-frontend-v2/**"
8+
- ".github/workflows/deploy-web-frontend-v2-pages.yml"
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
pages: write
14+
id-token: write
15+
16+
concurrency:
17+
group: "pages"
18+
cancel-in-progress: true
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
defaults:
24+
run:
25+
working-directory: web-frontend-v2
26+
env:
27+
PUBLIC_API_BASE_URL: https://runner.fly.dev
28+
PUBLIC_HIDE_API_TARGET_SELECTOR: "true"
29+
steps:
30+
- uses: actions/checkout@v4
31+
- uses: actions/setup-node@v4
32+
with:
33+
node-version: 22
34+
cache: npm
35+
cache-dependency-path: web-frontend-v2/package-lock.json
36+
- name: Setup Pages
37+
uses: actions/configure-pages@v5
38+
- name: Install dependencies
39+
run: npm ci
40+
- name: Build static site
41+
run: npm run build
42+
- name: Upload artifact
43+
uses: actions/upload-pages-artifact@v3
44+
with:
45+
path: web-frontend-v2/build
46+
47+
deploy:
48+
environment:
49+
name: github-pages
50+
url: ${{ steps.deployment.outputs.page_url }}
51+
runs-on: ubuntu-latest
52+
needs: build
53+
steps:
54+
- name: Deploy to GitHub Pages
55+
id: deployment
56+
uses: actions/deploy-pages@v4
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Frontend Rewrite Spec (SvelteKit)
2+
3+
Created: 2026-02-15T03:59:21Z (UTC)
4+
Branch: `feat/frontend-rewrite-sveltekit`
5+
6+
## Summary
7+
Rewrite `web-frontend/` from the current webpack + vanilla JS setup to `SvelteKit`.
8+
9+
This keeps the frontend lightweight while giving us modern routing, component structure, build tooling, and deploy adapters without committing to a heavy framework runtime.
10+
11+
## Framework Decision
12+
13+
### Candidates
14+
- `SvelteKit`
15+
- `Astro`
16+
- `SolidStart`
17+
18+
### Decision
19+
Choose `SvelteKit`.
20+
21+
### Why SvelteKit for this repo
22+
- Best fit for an app-style, interactive UI (editor + run action + output panes), not a content site.
23+
- Lightweight component model and low runtime overhead.
24+
- Official adapter model is straightforward for static or Node deployment targets.
25+
- Very strong DX for small teams: fast iteration, easy state flow, clear file-based routing.
26+
27+
### Why not Astro as primary
28+
- Astro is excellent for content-first sites with islands, but this project is a single interactive app surface where most UI is hydrated and stateful.
29+
- Using Astro here would add conceptual overhead without clear payoff.
30+
31+
### Why not SolidStart as primary
32+
- SolidStart is a valid option and performant, but SvelteKit has broader ecosystem/docs familiarity for handoff and maintenance in this codebase.
33+
34+
## Goals
35+
- Replace legacy webpack frontend with a modern framework architecture.
36+
- Preserve existing API behavior:
37+
- `GET /api/v1/languages`
38+
- `POST /api/v1/run`
39+
- Keep UX familiar while improving maintainability and testability.
40+
- Keep bundle size and dependencies modest.
41+
42+
## Non-goals
43+
- Backend API redesign.
44+
- Authentication/authorization changes.
45+
- Feature expansion beyond current runner UX in phase 1.
46+
47+
## Proposed Architecture
48+
- Framework: `SvelteKit`.
49+
- Build toolchain: default SvelteKit tooling.
50+
- Routing:
51+
- `/` main runner page.
52+
- Core UI modules:
53+
- `LanguageSelect`
54+
- `ThemeSelect`
55+
- `CodeEditor`
56+
- `RunButton`
57+
- `OutputPanel` (`stdout`, `stderr`, `error`)
58+
- API client:
59+
- Single module for `getLanguages()` and `runCode()`.
60+
- `PUBLIC_API_BASE_URL` env support for local/dev/prod.
61+
- Runtime selector for quickly switching between local and production backends during development.
62+
- State:
63+
- Minimal Svelte stores for language/theme/source/output/loading.
64+
65+
## Migration Plan
66+
67+
### Phase 0: Scaffolding
68+
- Create a new SvelteKit app in `web-frontend/` (or `web-frontend-v2/` if parallel migration is preferred).
69+
- Add base page layout and shared styles.
70+
- Add environment configuration for API base URL.
71+
72+
### Phase 1: API Integration
73+
- Implement `GET /api/v1/languages` fetch and populate language select.
74+
- Implement `POST /api/v1/run` with request/response typing.
75+
- Add loading, error, and timeout UX states.
76+
77+
### Phase 2: Editor + UX Parity
78+
- Integrate code editor component (CodeMirror wrapper).
79+
- Add theme selection and default starter snippets by language.
80+
- Preserve stdout/stderr/error rendering behavior.
81+
82+
### Phase 3: Hardening + Tests
83+
- Add unit tests for API client and component behavior.
84+
- Add one end-to-end smoke test for "select language -> run code -> see output".
85+
- Validate production build and static assets.
86+
87+
## Acceptance Criteria
88+
- Frontend starts locally and can run code against local API server.
89+
- Frontend can also be run locally against the production backend used by GitHub Pages.
90+
- Language list loads from server at runtime.
91+
- Running sample `bash` and `python3` code returns output correctly when runtime binaries are available.
92+
- No regression in core workflow vs current frontend.
93+
- CI includes frontend build + at least basic tests.
94+
95+
## Local Dev Workflow (Target)
96+
- Start API server: `go run ./server/main.go`
97+
- Start frontend dev server in `web-frontend`: `npm install && npm run dev`
98+
- Configure API URL via `.env` (`PUBLIC_API_BASE_URL=http://localhost:10100`) when you want to force the local backend.
99+
- Leave `PUBLIC_API_BASE_URL` unset to exercise the production backend locally before a GitHub Pages deploy.
100+
101+
## Risks
102+
- Runtime language availability differences (for example `python3` in sandbox rootfs).
103+
- Migration friction if we replace `web-frontend` in place instead of parallel folder rollout.
104+
- Existing styling/editor behavior parity may require incremental tuning.
105+
106+
## Rollout Recommendation
107+
- Build in `web-frontend-v2/` first for low-risk validation.
108+
- Switch deployment/build wiring after parity is confirmed.
109+
- Remove legacy webpack frontend after cutover.

readme.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
[![codecov](https://codecov.io/gh/camerondurham/runner/branch/main/graph/badge.svg)](https://codecov.io/gh/camerondurham/runner)
44
[![Go Version](https://img.shields.io/github/go-mod/go-version/camerondurham/runner)](https://img.shields.io/github/go-mod/go-version/camerondurham/runner)
5+
[![Frontend v2 (GitHub Pages)](https://img.shields.io/badge/frontend%20v2-live-2ea44f?logo=github)](https://codecanvas.u64.cam/)
56

67
Previously named "runner"
78

9+
Live frontend: <https://codecanvas.u64.cam/>
10+
811
## Demo
912

1013
![gif demo showing python3 nodejs and c++ running code](assets/animation_opt.gif)
@@ -85,7 +88,8 @@ Server-->>Client: return server transformed response
8588

8689
These components live in the following paths:
8790

88-
- browser front-end: [`web-frontend`](https://github.com/camerondurham/runner/tree/main/web-frontend) (thank you to @arekouzounian for this!)
91+
- browser front-end (legacy webpack app): [`web-frontend`](https://github.com/camerondurham/runner/tree/main/web-frontend) (thank you to @arekouzounian for this!)
92+
- browser front-end v2 (SvelteKit pilot): [`web-frontend-v2`](https://github.com/camerondurham/runner/tree/main/web-frontend-v2)
8993
- command-line interface: [`cli/runner/`](https://github.com/camerondurham/runner/tree/main/cli/runner) (another thank you to @arekouzounian for this!)
9094
- API Server: [`api/`](https://github.com/camerondurham/runner/tree/main/api) (thank you to @filipgraniczny for the help!)
9195
- CodeRunner: [`engine/coderunner`](https://github.com/camerondurham/runner/tree/main/engine/coderunner) (thank you to @siwei-li for the help!)

web-frontend-v2/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Optional local API override for frontend development.
2+
# Leave this unset to verify the frontend against the production backend.
3+
PUBLIC_API_BASE_URL=http://localhost:10100

web-frontend-v2/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
node_modules
2+
3+
# Output
4+
.output
5+
.vercel
6+
.netlify
7+
.wrangler
8+
/.svelte-kit
9+
/build
10+
11+
# OS
12+
.DS_Store
13+
Thumbs.db
14+
15+
# Env
16+
.env
17+
.env.*
18+
!.env.example
19+
!.env.test
20+
21+
# Vite
22+
vite.config.js.timestamp-*
23+
vite.config.ts.timestamp-*
24+
25+
# Playwright
26+
test-results
27+
playwright-report

web-frontend-v2/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
engine-strict=true

web-frontend-v2/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Web Frontend v2 (SvelteKit)
2+
3+
SvelteKit-based rewrite of the CodeCanvas frontend.
4+
5+
## Local Development
6+
7+
By default, the frontend now targets the production backend (`https://runner.fly.dev`) so you can verify a local UI change against the same endpoint the GitHub Pages build will use.
8+
9+
1. Start the frontend against the production API:
10+
11+
```sh
12+
cd web-frontend-v2
13+
npm run dev
14+
```
15+
16+
2. If you want to test against a local API server instead, either start the dev server with the local preset:
17+
18+
```sh
19+
npm run dev:local-api
20+
```
21+
22+
or create a local override:
23+
24+
```sh
25+
cp .env.example .env
26+
```
27+
28+
3. To run the backend locally, start the API server from repo root:
29+
30+
```sh
31+
go run ./server/main.go
32+
```
33+
34+
App URL is shown by Vite (usually `http://localhost:5173`).
35+
36+
In local development, you can switch between `Production` and `Local` backends in the app header without restarting the frontend.
37+
38+
## GitHub Pages Parity Check
39+
40+
To verify the exact deployment-style configuration locally, build for the custom-domain Pages site with the production API endpoint, then preview it locally:
41+
42+
```sh
43+
npm run preview:pages
44+
```
45+
46+
This serves the static site with:
47+
- base path: `/`
48+
- API backend: `https://runner.fly.dev`
49+
- backend selector hidden, matching the deployed GitHub Pages app
50+
51+
## API Contract
52+
53+
- `GET /api/v1/languages`
54+
- `POST /api/v1/run`
55+
56+
## Quality Checks
57+
58+
```sh
59+
npm run check
60+
npm run build
61+
npm run build:pages
62+
```
63+
64+
## Smoke Test
65+
66+
Runs an end-to-end UI smoke test with Playwright. It starts both the API server and frontend dev server automatically.
67+
68+
```sh
69+
npm run test:smoke
70+
```
71+
72+
On NixOS, use the Chromium wrapper from `nixpkgs`:
73+
74+
```sh
75+
npm run test:smoke:nix
76+
```
77+
78+
## GitHub Pages Deployment
79+
80+
Concrete deployment target:
81+
- URL: `https://codecanvas.u64.cam/`
82+
- API backend URL used in Pages build: `https://runner.fly.dev`
83+
- Workflow: `.github/workflows/deploy-web-frontend-v2-pages.yml`
84+
85+
The workflow triggers on push to `main` when `web-frontend-v2/**` changes, and can also be run manually.
86+
In the CodeCanvas repository's GitHub Pages settings, set the repository custom domain to `codecanvas.u64.cam` and use a DNS `CNAME` record from `codecanvas.u64.cam` to `camerondurham.github.io`.

0 commit comments

Comments
 (0)