# Deploy an Angular single-page app on Yeeted

A color contrast checker written as an **Angular 21** standalone component
with signals and zoneless change detection, deployed with **no Dockerfile**:
Yeeted detects Angular from `@angular/core` in `package.json`, runs `npm ci`
from the lockfile and `npm run build` (`ng build`), finds the built
`index.html` under `dist/contrast-angular/browser/`, and serves that folder
from nginx with a fallback to `index.html` for deep links.

The contrast math in `src/app/contrast.ts` is a typed copy of the module the
[Vue](contrast-vue.md), [Svelte](contrast-svelte.md) and
[Astro](contrast-astro.md) examples share, so a difference between
them is the framework and its build, not the app. The project is kept to the
Angular packages a build needs: no router, forms, animations or test runner.

Tests: `npm test` (node:test on the contrast math, run through Node's
TypeScript type stripping) · `./smoke.sh https://...` against a deployment.

## Run locally

Use Node 22.18 or newer (22.12 builds the app; `npm test` needs the built-in
TypeScript support). From `node/contrast-angular`:

```sh
npm ci
npm test
npm start
```

Open `http://localhost:4200`. `npm run build` writes the production files to
`dist/contrast-angular/browser/`, which is what the deployed image serves.
`angular.json` turns CLI analytics off, so a build never stops to ask.

## Deploy and verify

Follow the [deployment walkthrough](getting-started.md). Deploy this
folder, including `package-lock.json`, `angular.json`, `tsconfig.json` and
`yeeted.yaml`, with no database. Do not upload `node_modules/`, `.angular/` or
`dist/`; the build runs on Yeeted. The manifest routes to port 80, where nginx
listens. An Angular build takes noticeably longer than a Vite one; follow the
deployment status rather than resending it.

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

The script checks that the BUILT `index.html` is served (it loads a hashed
`main-*.js` that the source file does not reference), that the 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 and accepts `#rgb` and `#rrggbb`
colors. Server-side rendering (`@angular/ssr`) is a different deployment
shape and is not covered here.

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