Files
crewli/dev-docs/FRONTEND-TOOLING.md
bert.hausmans 637d77b327 docs(plan-3): close out Plan 3 — BACKLOG entries, RFC status, primitives registry, tooling conventions
- BACKLOG: add 3 spawned follow-ups (EnergyDots NaN, DraggableBlock pointercancel, AD-3 Menubar a11y)
- RFC-WS-GUI-REDESIGN-CREWLI-STARTER: mark Plan 3 complete with commit refs + DoD ledger
- PRIMEVUE_COMPONENTS: v2 primitives registry (8 components), statusSeverity SoT, Menubar-wrap pattern
- ARCH-TESTING: mount-helper type convention (Plan 3 codified, Plan 4 carry-over)
- FRONTEND-TOOLING: scoped lint invocation note (DoD #13 root cause)
- AppDialog.stories.ts: rename title to 'Shared/AppDialog' for sibling consistency
2026-05-19 01:41:19 +02:00

4.2 KiB

Frontend tooling

Type-safety and quality tooling for the Vue 3 + TypeScript SPAs.

ts-reset

Installed in both apps/portal/ and apps/app/ as a dev-dependency. Imported via src/reset.d.ts:

import '@total-typescript/ts-reset'

Both SPAs' tsconfig.json include ./src/**/*, so the .d.ts is picked up automatically — no explicit include edit needed.

What it changes

ts-reset patches TypeScript's loosest default types:

  • Array.filter(Boolean) returns non-nullable Array<T> instead of Array<T | null | undefined | false | 0 | "">
  • JSON.parse returns unknown instead of any
  • fetch().then(r => r.json()) returns unknown instead of any
  • Array.includes() accepts narrower types
  • Map.get() returns T | undefined more strictly
  • See https://github.com/total-typescript/ts-reset for the full list

Why this matters

The default TypeScript types for these built-ins lose information that real code relies on. ts-reset fixes the types to match runtime behavior, surfacing bugs that were previously hidden.

Adoption state

apps/app — 0 pre-install tsc errors in own code; install surfaced 2 errors in src/stores/useImpersonationStore.ts (both from JSON.parse on sessionStorage content). Both fixed inline via as ImpersonationState assertions that make the existing trust-in- sessionStorage explicit. A backlog entry (TECH-TS-IMPERSONATION) tracks proper runtime validation of the stored shape.

apps/portal — 22 pre-existing tsc errors in own code (mostly tiptap editor components — unrelated to ts-reset). ts-reset added 0 new errors in portal's own code. 4 additional errors surfaced in tiptap's third-party .ts sources under node_modules (tiptap ships uncompiled TypeScript and some of its internal JSON.parse call sites fall under ts-reset's tightening). Not our code; left as-is.

Neither SPA achieves tsc --noEmit clean today — that's a pre- existing state unrelated to this work package. Build + vitest are the actual CI-relevant gates and both remain green.

Bypassing

@ts-expect-error with comment justification at the call site — never blanket-disable ts-reset. If a specific reset is genuinely wrong for the project, document it; the upstream issue is the backstop.

ESLint

Scoped lint invocation

pnpm lint -- <path> is vacuous: pnpm's -- passthrough forwards trailing args as workspace/script filters, not as ESLint targets, so errors in the intended files are never surfaced. In Plan 3 this made per-task lint report "clean" while real errors existed — the root cause of the GUI-redesign DoD #13 miss (fixed in 0b19e785).

Correct scoped invocation — call the project's ESLint binary directly with the paths:

pnpm exec eslint <paths>

For per-task gates, pair a file-scoped run with a directory-scoped run so project-level rule misconfigs surface too:

pnpm exec eslint apps/app/src/components-v2/shared/Foo.vue
pnpm exec eslint apps/app/src/components-v2/shared

Vitest

Runs against apps/portal/ and apps/app/. apps/app/ has a Vitest test suite (402 tests as of May 2026); run with pnpm test from apps/app/.

Storybook

Storybook 10.x is installed in apps/app/ as a component development and documentation tool.

Scripts (run from apps/app/):

  • pnpm storybook — dev server on http://localhost:6006
  • pnpm build-storybook — static build to storybook-static/

Config files:

  • apps/app/.storybook/main.ts — framework, stories glob, addons, viteFinal aliases
  • apps/app/.storybook/preview.ts — PrimeVue (via installPrimeVue plugin), Tailwind

Stories location: co-located with components (ComponentName.stories.ts next to ComponentName.vue). Exception: smoke-test stories live in src/stories/.

Addons (explicit, no addon-essentials):

  • @storybook/addon-docs — autodocs, prop tables
  • @storybook/addon-a11y — axe-core accessibility checks per story

Scope boundary: Storybook = isolated render, autodocs, a11y. Interaction testing (click, form submit, emit) stays in Playwright CT. Do NOT install @storybook/addon-interactions.

Not in Storybook: page-level views, components with direct useAuthStore / useOrganisationStore calls (these need to be decoupled to props first).