feat(web): Vite + TanStack Router + Tamagui app #19

Merged
admin-mrrm merged 2 commits from feat/apps-web into main 2026-04-15 21:39:55 +02:00
Owner

Summary

  • Adds apps/web — first user-facing surface, wires together every package shipped on this branch so far
  • Vite 6 + @vitejs/plugin-react + @tamagui/vite-plugin (Tamagui static style extraction enabled in prod)
  • TanStack Router with typed routes: /, /lists, /lists/$listId, /auth/callback. Auth-protected routes use beforeLoad to redirect to Keycloak when no session exists.
  • TanStack Query v5 with one shared QueryClient (sane defaults: staleTime: 30s, refetchOnWindowFocus: false)
  • @mrrmlab/auth wired via WebStorageTokenStore(sessionStorage) — tokens die with the tab, refresh-token rotation handles silent re-login
  • OIDC is optional in dev: when VITE_KC_ISSUER is empty, the app skips login entirely and the backend's dev-user passthrough handles auth. Mirrors the api server's own KC_ISSUER behavior.
  • /lists and /lists/$listId drop the screens from @mrrmlab/feature-shopping-list straight in — feature parity with mobile (#12) comes for free

Bundled refactor: auth + api-client → source-only

  • Both packages were CJS-built (legacy of the shared-types pattern) but only consumed by bundlers. Dropped the dist build, point main at ./src/index.ts. Matches ui and feature-shopping-list.
  • This was forced by Vite/Rollup failing to detect named exports on tsc's CJS re-export-heavy index.js outputs — first auth, then api-client would have hit the same wall.
  • shared-types stays CJS-built because Nest still depends on it. Vite handles its CJS dist via build.commonjsOptions.include widened to cover the workspace package.

Verification

  • pnpm -r typecheck — 8 packages clean
  • pnpm --filter @mrrmlab/web build — produces a 763 kB JS / 3.8 kB CSS bundle
  • pnpm --filter @mrrmlab/api build — Nest backend still builds (shared-types CJS path unaffected)
  • End-to-end browser smoke test against a running backend (tracked in #11 follow-up if needed)

Test plan

  • pnpm --filter @mrrmlab/web dev and click through /, /lists, item add/toggle/delete
  • With Keycloak unset in .env.local, verify the dev-user passthrough flow works end-to-end against the running api
  • With Keycloak set, verify /auth/callback round-trips correctly and returnTo is honored

Closes #11

## Summary - Adds `apps/web` — first user-facing surface, wires together every package shipped on this branch so far - **Vite 6** + `@vitejs/plugin-react` + `@tamagui/vite-plugin` (Tamagui static style extraction enabled in prod) - **TanStack Router** with typed routes: `/`, `/lists`, `/lists/$listId`, `/auth/callback`. Auth-protected routes use `beforeLoad` to redirect to Keycloak when no session exists. - **TanStack Query v5** with one shared `QueryClient` (sane defaults: `staleTime: 30s`, `refetchOnWindowFocus: false`) - **`@mrrmlab/auth`** wired via `WebStorageTokenStore(sessionStorage)` — tokens die with the tab, refresh-token rotation handles silent re-login - **OIDC is optional in dev**: when `VITE_KC_ISSUER` is empty, the app skips login entirely and the backend's dev-user passthrough handles auth. Mirrors the api server's own `KC_ISSUER` behavior. - `/lists` and `/lists/$listId` drop the screens from `@mrrmlab/feature-shopping-list` straight in — feature parity with mobile (#12) comes for free ## Bundled refactor: auth + api-client → source-only - Both packages were CJS-built (legacy of the shared-types pattern) but only consumed by bundlers. Dropped the dist build, point `main` at `./src/index.ts`. Matches `ui` and `feature-shopping-list`. - This was forced by Vite/Rollup failing to detect named exports on tsc's CJS re-export-heavy `index.js` outputs — first auth, then api-client would have hit the same wall. - `shared-types` stays CJS-built because Nest still depends on it. Vite handles its CJS dist via `build.commonjsOptions.include` widened to cover the workspace package. ## Verification - [x] `pnpm -r typecheck` — 8 packages clean - [x] `pnpm --filter @mrrmlab/web build` — produces a 763 kB JS / 3.8 kB CSS bundle - [x] `pnpm --filter @mrrmlab/api build` — Nest backend still builds (shared-types CJS path unaffected) - [ ] End-to-end browser smoke test against a running backend (tracked in #11 follow-up if needed) ## Test plan - [ ] `pnpm --filter @mrrmlab/web dev` and click through `/`, `/lists`, item add/toggle/delete - [ ] With Keycloak unset in `.env.local`, verify the dev-user passthrough flow works end-to-end against the running api - [ ] With Keycloak set, verify `/auth/callback` round-trips correctly and `returnTo` is honored Closes #11
Both packages are consumed only by bundlers (web, mobile, feature-shopping-list),
never by NestJS — the CJS dist setup was carrying weight it didn't need.
Vite/Rollup also struggles to detect named exports on tsc's CJS output of
re-export-heavy index files, which broke the apps/web build.

Source-only matches the pattern already used by ui and feature-shopping-list:
main → ./src/index.ts, no build step, host bundlers compile TS directly.
shared-types stays CJS-built because Nest still depends on it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds apps/web — the first user-facing surface for mrrmlab. Wires
everything previously shipped on this branch into a working web app:

  - Vite 6 + @vitejs/plugin-react + @tamagui/vite-plugin (with static
    style extraction enabled in prod)
  - TanStack Router with typed routes: /, /lists, /lists/$listId,
    /auth/callback. Auth-protected routes use beforeLoad to redirect
    to Keycloak when no session exists.
  - TanStack Query v5 with a single shared QueryClient
  - @mrrmlab/auth wired via sessionStorage token store; OIDC config is
    optional in dev — when VITE_KC_ISSUER is unset, the app skips login
    entirely and the backend's dev-user passthrough handles it.
  - @mrrmlab/api-client built with a getToken callback that pulls from
    the AuthClient
  - Drops @mrrmlab/feature-shopping-list's screens straight into the
    /lists and /lists/$listId routes — feature parity comes for free.

Vite build needs commonjsOptions.include widened so Rollup processes
@mrrmlab/shared-types' CJS dist (which has to stay CJS for NestJS).

Closes #11

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
admin-mrrm/mrrmlabapp!19
No description provided.