# Deploy a Vue single-page app on Yeeted

A color contrast checker written as a **Vue 3 + Vite** single-page app, with
**no Dockerfile**: Yeeted detects Vue from `package.json`, runs `npm ci` from
the lockfile and `npm run build`, and serves `dist/` from nginx with a
fallback to `index.html`, so deep links load the app instead of a 404.

The contrast math is the WCAG 2 formula in `src/contrast.js`, a plain module
with no Vue imports. The same module backs the [Svelte](contrast-svelte.md) and
[Astro](contrast-astro.md) examples, and the
[Angular](contrast-angular.md) one carries a typed copy, so any
difference between them is the framework and its build, not the app.

Tests: `npm test` (node:test on the contrast math) · `./smoke.sh https://...`
against a deployment.

## Run locally

Use Node 22.12 or newer. From `node/contrast-vue`:

```sh
npm ci
npm test
npm run dev
```

Open the URL Vite prints. `npm run build` writes the production files to
`dist/`, which is what the deployed image serves.

## Deploy and verify

Follow the [deployment walkthrough](getting-started.md). Deploy this
folder, including `package-lock.json` and `yeeted.yaml`, with no database.
Do not upload `node_modules/` or `dist/`; the build runs on Yeeted. The
manifest routes to port 80, where nginx listens.

```sh
sh smoke.sh "$PREVIEW_URL"
```

The script checks that the BUILT `index.html` is served (it references
`/assets/`, which the source file does not), that the JavaScript bundle holds
the contrast logic, and that a deep link such as `/check/navy-on-white` falls
back to the app.

## What the app does not do

Everything runs in the browser; there is no API and nothing is stored. The
calculator implements the WCAG 2 ratio only, not APCA or any other contrast
model, and it accepts `#rgb` and `#rrggbb` colors only.

[All examples](index.md) · [Deploy an example](getting-started.md)
