You'll need Node 24.x and yarn. Use nvm (macOS/Linux) or nvm-windows to switch Node versions between projects.
corepack enable
All commands should be run from this directory (web/).
Installs all dependencies for all packages in the monorepo.
All of the following commands use Turbo to orchestrate tasks across the monorepo. Create a .env file in apps/wps-web/ using apps/wps-web/.env.example as a sample before running.
Runs the app in development mode. The page will reload on edits and lint errors will appear in the console.
Launches the Vitest test runner across all packages, including unit tests and React Testing Library component tests.
Launches the Cypress test runner in interactive watch mode for end-to-end and integration tests.
Builds the app for production to apps/wps-web/build.
- Create
.envinapps/wps-web/usingapps/wps-web/.env.exampleas a sample - Run
docker compose buildand thendocker compose up - Open http://localhost:3000
apps/
wps-web/ # Main React app (@wps/wps-web)
packages/
api/ # API client functions (@wps/api)
types/ # Shared type declarations (@wps/types)
ui/ # Shared React components (@wps/ui)
utils/ # Shared utilities (@wps/utils)
tsconfig/ # Shared TypeScript configs (@wps/tsconfig)
Each package declares its own dependencies explicitly in its package.json. This matters because multiple apps consume these packages — a new app that omits a dependency that happens to be hoisted by another package will fail in non-obvious ways.
- Runtime imports →
dependencies import typeonly →devDependencies- Workspace packages used only for types →
devDependencies(e.g.@wps/types)
The workspace uses nodeLinker: node-modules (configured in .yarnrc.yml), which hoists all packages into a shared node_modules. Any package can resolve any other package at build time regardless of what's declared.
Switching to nodeLinker: pnp (Yarn Plug'n'Play) would enforce strict boundaries — packages can only import what they explicitly declare, and build errors surface immediately. PnP also reduces disk usage and speeds up installs by storing packages as zips rather than extracted file trees. This hasn't been adopted yet due to migration risk (Vite and other tooling require PnP compatibility verification).