Docs
Developer Guide
Single source of truth for setting up the monorepo, understanding its structure, and doing day-to-day development work.
For the branching strategy and PR process see WORKFLOW.md. For performing releases (local + NPM) see RELEASE_GUIDE.md.
#Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Node.js | โฅ 18.18 | nodejs.org |
| Rush | latest | npm install -g @microsoft/rush |
| Docker | any recent | Required only for local registry testing |
Do not install pnpm globally. Rush downloads and manages pnpm internally at the exact
version pinned in rush.json. Running pnpm install directly will produce incorrect results
and break the lockfile.
#First-time setup
# 1. Clone
git clone https://github.com/yoltra/yoltra.git
cd yoltra
# 2. Install all workspace dependencies (Rush manages pnpm)
rush install
# 3. Build the entire monorepo (graph-aware, incremental)
rush buildRush reads the project graph from rush.json, installs all packages into the shared
common/temp/ store, and links them using pnpm workspaces.
#Repository structure
yoltra/
โโโ packages/
โ โโโ core/ @yoltra/core โ state container library
โ โโโ react/ @yoltra/react โ React bindings
โ
โโโ tools/
โ โโโ eslint-config-base/ @yoltra/eslint-config-base โ shared ESLint (Node + browser TS)
โ โโโ eslint-config-react/ @yoltra/eslint-config-react โ shared ESLint (React + TS)
โ โโโ registry/ Verdaccio local registry (Docker)
โ
โโโ examples/
โ โโโ v0/
โ โโโ yoltra-in-react/ Yoltra vs Redux Toolkit comparison app
โ โโโ yoltra-in-nextjs/ Next.js integration example
โ โโโ yoltra-kinetic-logo/ SVG animation โ fine-grained subscription demo
โ
โโโ common/
โ โโโ config/rush/ Rush config files (committed โ never edit lockfile by hand)
โ โโโ scripts/ Shared helpers (copy-license.cjs, etc.)
โ
โโโ docs/
โโโ en/ English documentation (this folder)
โโโ es/ Spanish translations#Everyday commands
#Monorepo-wide
rush install # Install / sync all dependencies (after cloning or pulling)
rush update # Regenerate lockfile (run after editing any package.json)
rush build # Incremental build โ uses cache, skips unchanged packages
rush rebuild # Force full rebuild โ bypasses cache, rebuilds everything
rush test # Run Vitest across all packages
rush lint # Run ESLint across all packages
rush typecheck # Run tsc --noEmit across all packages#Focused builds
Use --to and --from to narrow the build to a subset of the dependency graph:
rush build --to @yoltra/core # Build core and its transitive deps
rush build --to @yoltra/react # Build react (and core first)
rush build --from @yoltra/core # Build core and every downstream dependent
rush build --to @yoltra/react --verbose # Same, with detailed output#Per-package commands (rushx)
rushx runs an npm script in the current package. Change to the package directory first:
cd packages/core
rushx build # Build just this package
rushx test # Run tests with coverage
rushx lint # Check for lint errors
rushx lint:fix # Auto-fix lint issues
rushx typecheck # TypeScript type checking
cd packages/react
rushx build
rushx test
rushx docs # Generate TypeDoc API docs#Build cache
Rush's local build cache is enabled via common/config/rush/build-cache.json.
Each library package declares its cacheable output in rush-project.json:
{
"operationSettings": [{ "operationName": "build", "outputFolderNames": ["dist"] }]
}Key rules:
rush buildโ reads and writes the cache; unchanged packages finish instantly.rush rebuildโ always skips the cache; use this when you suspect a stale output.- Cache lives in
common/temp/build-cache/(gitignored, local only).
#ESLint architecture
Lint configuration is extracted into two shareable packages under tools/:
| Package | Target packages | Includes |
|---|---|---|
@yoltra/eslint-config-base | @yoltra/core | ESLint recommended, typescript-eslint recommended, browser + Node globals |
@yoltra/eslint-config-react | @yoltra/react | Extends base + react-hooks + react-refresh |
Each library package has a thin eslint.config.mjs that just re-exports the shared config:
// packages/core/eslint.config.mjs
import baseConfig from "@yoltra/eslint-config-base";
export default baseConfig;// packages/react/eslint.config.mjs
import reactConfig from "@yoltra/eslint-config-react";
export default reactConfig;To add a rule globally โ edit the config package in tools/. No need to touch each
library's eslint.config.mjs. To override a rule for one package โ extend the array in that
package's eslint.config.mjs.
#Conventional commits + DCO
Every commit must:
-
Follow Conventional Commits:
ts<type>(<scope>): <short description> [optional body] Signed-off-by: Your Name <you@example.com> -
Carry a DCO sign-off (
git commit -sappends it automatically).
Allowed <type> values: feat, fix, perf, refactor, docs, test, build, chore,
revert.
#Testing & coverage
- Runner: Vitest
- UI helpers:
@testing-library/react(for@yoltra/react) - Minimum coverage thresholds (lines / branches / functions / statements): 95%
# All packages
rush test
# Single package
cd packages/core && rushx testSnapshot tests are only allowed for stable, deterministic output.
#Change files (required for every publishable PR)
Any PR that modifies @yoltra/core, @yoltra/react, or another published package must
include a Rush change file. (There is no CI yet โ verify it locally with the command below; wiring
rush change --verify into CI is the recommended enforcement, see the
Release Guide.)
# Interactive prompt โ select the packages you changed and the bump type
rush change
# Verify a change file exists
rush change -vChange files are committed to common/changes/ alongside the code change. When a release is
prepared they are consumed by rush version --bump to update package.json versions and
generate CHANGELOG.md entries.
While the project is < 1.0.0: use minor for breaking changes and patch for fixes.
#Adding a new publishable package
- Create the folder under
packages/ortools/. - Add a
package.jsonwith"publishConfig": { "access": "public" }. - Add a minimal
rush-project.json(declareoutputFolderNamesif the package builds). - Register the package in
rush.jsonunder"projects". - Run
rush updateto regenerate the lockfile. - If it ships in sync with the product suite, set
"versionPolicyName": "yoltra"(the lockstep policy โ see the Release Guide); otherwise leave it unset for independent versioning.
#Updating dependencies
- Edit the relevant
package.json. - Run
rush updateto recalculate and rewrite the lockfile. - Commit both the
package.jsonchange and the updatedcommon/config/rush/pnpm-lock.yaml.
Never touch common/config/rush/pnpm-lock.yaml by hand.
#Troubleshooting
| Symptom | Fix |
|---|---|
| Missing change file (rush change -v) | rush change, commit the file in common/changes/. |
rush install peer dep errors | strictPeerDependencies: false is already set; try rush install --purge. |
| Commit rejected | Ensure Conventional Commits format + DCO sign-off (git commit -s). |
| Stale build output | rush rebuild bypasses cache and forces a full recompile. |
| Verdaccio: "version already exists" | Bump version (rush change + rush version --bump) or wipe with docker compose down -v. |
rushx not found | npm install -g @microsoft/rush |
| Wrong pnpm version in lockfile | Never run pnpm install directly; always use rush install / rush update. |