SPLT CI/CD Pipeline — Vue 3 SPA on Cloudflare Workers

splt-frontend · solidprofessorhub · updated 2026-03-13
Pull Requestopened / synchronize / reopened
Path filters: *.js *.vue *.ts *.css package.json package-lock.json
wrangler.toml index.html vite.config.js vitest.config.js tailwind.config.js
postcss.config.js tsconfig.json uno.config.* .nvmrc .npmrc
.eslintignore .prettierrc sonar-project.properties .github/**
PR Checks — ci_cd.ymlconcurrency: cancel-in-progress per PR
env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
parallel
Lint · 3 min timeout
Checkout
Validate branch name (org shared action)
🔨npx oxlint@1.6.0 --format=github
No npm install — oxlint is standalone

Test with Coverage · 15 min timeout
Checkout
Setup Node.js (.nvmrc + native npm cache)
Setup NPM auth (GH Packages + FontAwesome)
🔨npm ci --legacy-peer-deps
🔨npm run test:coverage (Vitest)
Post coverage table → GitHub Step Summary
🚀Upload coverage/ artifact (1-day retention)

SonarCloud Analysis · 10 min timeout
needs: [test]
Checkout — full history fetch-depth: 0
Download coverage artifact from test job
🛡SonarCloud Scan (v6, uses uploaded coverage)
Required checks (org ruleset "Vue"): Lint, Test with Coverage, SonarCloud Analysis — all three exact names must pass for merge
Pull Requestopened / synchronize / reopened (parallel with PR Checks)
CF Deploy — PR Preview Pathreusable workflow: cf-workers-deploy.yml
deploy · 15 min timeout
Checkout
Install Doppler CLI
Auto-detect Doppler config → "preview"
Setup Node.js + NPM auth
🔨npm install --legacy-peer-deps
Sanitize branch name
Compute preview origin URL
Conditional: only runs if preview_origin_env_var is set. Outputs https://pr-{branch}-live.solidprofessor.com
🔨doppler run -- npm run generate
Auth override: if preview_origin_env_var set, injects VITE_APP_SP_URL={origin} at build time
🚀wrangler versions upload --preview-alias {branch}
Register KV: worker-preview:{alias} (7d TTL)
🚀Attach custom domain via CF API
pr-{branch}-live.solidprofessor.com → preview-router Worker
Register KV: custom-domain:{hostname} (7d TTL)
🛡Smoke test .workers.dev URL (3 retries)
Compute preview URL outputs

needs: deploy
preview-comment · caller workflow
🚀Post sticky PR comment with preview URL
pr-{branch}-live.solidprofessor.com/training
marocchino/sticky-pull-request-comment — reusable workflow comment suppressed
Push to mainmerge commit
All three use the same reusable workflow with different inputs
CF Deploy — Push to Main3 parallel reusable workflow calls
parallel
deploy — splt-frontend (prod)
Doppler config: prod (auto-detected)
🔨doppler run -- npm run generate
🚀wrangler deploy --name splt-frontend
skip_main_custom_domain: true
Prod domain (live.solidprofessor.com) managed by Terraform, not KV

deploy-preprod — splt-frontend-preprod
Doppler config override: preprod
🔨doppler run -- npm run generate
🚀wrangler deploy --name splt-frontend-preprod
Serves: preprod-live.solidprofessor.com
(TF-managed custom domain)

deploy-preview — splt-frontend-preview
Doppler config override: preview
🔨doppler run -- npm run generate
🚀wrangler deploy --name splt-frontend-preview
Serves: staging-live.solidprofessor.com
(TF-managed custom domain — permanent preview env, not PR-specific)
PR Closedmerged or closed
Cleanup — PR Closedreusable workflow
cleanup job
parallel with cleanup-comment
Sanitize branch name
Remove KV: worker-preview:{alias}
Remove KV: custom-domain:{hostname}
Detach custom domain via CF API
Worker version persists on Cloudflare — only routing removed. Versions are immutable and garbage-collected by CF.
preview-cleanup-commentcaller workflow (parallel with cleanup)
🚀Update sticky PR comment → "Cleaned Up"
Legend
setup / config
🔨 build / install
🚀 deploy / publish
cleanup
🛡 scan / verify