diff --git a/skills/rushstack-best-practices/CHANGELOG.md b/skills/rushstack-best-practices/CHANGELOG.md new file mode 100644 index 0000000000..61c4ee219b --- /dev/null +++ b/skills/rushstack-best-practices/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log - Rush Stack Skills + +This log was last generated on Tue, 11 Feb 2026 00:00:00 GMT and should not be manually modified. + +## 1.0.0 +Tue, 11 Feb 2026 00:00:00 GMT + +### Minor changes + +- Initial release of Rush Stack skills collection +- `rushstack-best-practices` skill providing guidance for: + - Configuring Rush in a monorepo + - Common configuration patterns + - Package management best practices + - Build and toolchain recommendations + diff --git a/skills/rushstack-best-practices/SKILL.md b/skills/rushstack-best-practices/SKILL.md new file mode 100644 index 0000000000..33a8b3a2fb --- /dev/null +++ b/skills/rushstack-best-practices/SKILL.md @@ -0,0 +1,248 @@ +--- +name: rushstack-best-practices +description: Provides best practices and guidance for working with Rush monorepos. Use when the user is working in a Rush-based repository, asks about Rush commands (install, update, build, rebuild), needs help with project selection, dependency management, build caching, subspace configuration, or troubleshooting Rush-specific issues. +license: MIT +metadata: + author: rushstack + version: "1.0.0" +--- + +# Rushstack Best Practices + +This skill provides essential best practices for working with Rush monorepos. Following these guidelines ensures efficient dependency management, optimal build performance, and proper command usage. + +## Important Guidelines + +**When encountering unclear issues or questions:** + +1. **Never make assumptions** - If unsure about Rush behavior, configuration, or commands +2. **Search official resources first** - Check documentation and existing issues before guessing +3. **Provide accurate information** - Base responses on verified sources, not assumptions +4. **Ask for clarification** - When the problem description is ambiguous or incomplete + +## Core Principles + +1. **Always use Rush commands** - Avoid npm/pnpm/yarn directly in a Rush monorepo +2. **Use rushx for single projects** - Like npm run, but Rush-aware +3. **rush install vs update** - install for CI, update after changes +4. **rush build vs rebuild** - build for incremental, rebuild for clean +5. **Projects at 2 levels** - Standard: apps/, libraries/, tools/ +6. **Selection flags reduce scope** - Use --to, --from, --impacted-by +7. **Build cache is automatic** - Configure output folders to enable +8. **Subspace for large repos** - Isolate dependencies when needed + +## Project Selection Best Practices + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. Use these selection flags to improve efficiency: + +### --to +Select specified project and all its dependencies. +- Build specific project and its dependencies +- Ensure complete dependency chain build +```bash +rush build --to @my-company/my-project +rush build --to my-project # If project name is unique +rush build --to . # Use current directory's project +``` + +### --to-except +Select all dependencies of specified project, but not the project itself. +- Update project dependencies without processing project itself +- Pre-build dependencies +```bash +rush build --to-except @my-company/my-project +``` + +### --from +Select specified project and all its downstream dependencies. +- Validate changes' impact on downstream projects +- Build all projects affected by specific project +```bash +rush build --from @my-company/my-library +``` + +### --impacted-by +Select projects that might be affected by specified project changes, excluding dependencies. +- Quick test of project change impacts +- Use when dependency status is already correct +```bash +rush build --impacted-by @my-company/my-library +``` + +### --impacted-by-except +Similar to `--impacted-by`, but excludes specified project itself. +- Project itself has been manually built +- Only need to test downstream impacts +```bash +rush build --impacted-by-except @my-company/my-library +``` + +### --only +Only select specified project, completely ignore dependency relationships. +- Dependency status is known to be correct +- Combine with other selection parameters +```bash +rush build --only @my-company/my-project +rush build --impacted-by projectA --only projectB +``` + +## Command Usage Guidelines + +### Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. **`rush` command** - Execute operations affecting the entire repository or multiple projects + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing + +2. **`rushx` command** - Execute specific scripts for a single project + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector for toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: Running project-specific build scripts, tests, dev servers + +3. **`rush-pnpm` command** - Replace direct use of pnpm in Rush repository + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +### Install vs Update + +| Command | Behavior | When to Use | +|---------|----------|-------------| +| `rush update` | Updates shrinkwrap, installs new dependencies | After cloning, after git pull, after modifying package.json | +| `rush install` | Read-only install from existing shrinkwrap | CI/CD pipelines, ensuring version consistency | + +### Build vs Rebuild + +| Command | Behavior | When to Use | +|---------|----------|-------------| +| `rush build` | Incremental build, only changed projects | Daily development, quick validation | +| `rush rebuild` | Clean build all projects | Complete rebuild needed, investigating issues | + +## Dependency Management + +### Package Manager Selection +Choose in `rush.json`: +```json +{ + "pnpmVersion": "8.x.x" // Preferred - efficient, strict + // "npmVersion": "8.x.x" // Alternative + // "yarnVersion": "1.x.x" // Alternative +} +``` + +### Version Constraints +Configure in `common/config/subspaces//common-versions.json`: +```json +{ + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + "implicitlyPreferredVersions": true, + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } +} +``` + +### Adding/Removing Dependencies +Always use Rush commands, not npm/pnpm directly: +```bash +rush add -p lodash --dev # Add dev dependency +rush add -p react --exact # Add exact version +rush remove -p lodash # Remove dependency +``` + +## Build Cache Configuration + +Configure in `/config/rush-project.json`: +```json +{ + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["lib", "dist"], + "disableBuildCacheForOperation": false, + "dependsOnEnvVars": ["MY_ENV_VAR"] + } + ] +} +``` + +**Cache Behavior:** +- Cache stored in `common/temp/build-cache` +- Invalidated by: source changes, dependency changes, env vars, command params +- Parallel builds supported via `enableParallelism` + +## Troubleshooting + +### Dependency Issues +- Avoid `npm`, `pnpm`, `yarn` - use Rush commands +- Run `rush purge` to clean environment +- Run `rush update --recheck` to force dependency check + +### Build Issues +- Use `rush rebuild` to skip cache +- Check `rushx build` output for specific errors +- Use `--verbose` for detailed logs + +### Performance Issues +- Use selection flags (`--to`, `--from`, etc.) to reduce scope +- Enable build cache in rush-project.json +- Consider subspace for very large monorepos + +## Subspace for Large Monorepos + +**What is Subspace:** +- Allows multiple PNPM lock files in one Rush monorepo +- Enables independent dependency management per team/project group +- Reduces risk from dependency updates +- Improves install/update performance + +**When to Use:** +- Large monorepos (50+ projects) +- Multiple teams with different dependency needs +- Conflicting version requirements +- Need for faster dependency operations + +## Official Resources + +### Documentation & References + +**Official Websites:** +- [RushStack.io](https://rushstack.io/) - Main documentation site +- [Rush.js.io](https://rushjs.io/) - Rush build orchestrator documentation +- [Heft.rushstack.io](https://heft.rushstack.io/) - Heft build tool documentation +- [API Extractor](https://api-extractor.com/) - API documentation and rollups + +**Search Existing Issues:** +- Before creating new issues, search [rush-stack-builds issues](https://github.com/microsoft/rushstack/issues) + +### When to Search vs. Ask + +**Search these resources first when:** +- Encountering error messages +- Unsure about configuration options +- Looking for examples or tutorials +- Need to understand Rush behavior + +**Ask the user for clarification when:** +- The specific use case is unclear +- Multiple approaches are possible +- Context is missing to provide accurate guidance +- The issue might be environment-specific + +## Detailed References + +For expanded information on specific domains, see: +- `references/core-commands.md` - Detailed command reference +- `references/project-configuration.md` - Configuration file specifications +- `references/dependency-management.md` - Advanced dependency patterns +- `references/build-system.md` - Build optimization and caching +- `references/subspace.md` - Subspace setup and usage diff --git a/skills/rushstack-best-practices/references/build-system.md b/skills/rushstack-best-practices/references/build-system.md new file mode 100644 index 0000000000..b836cf0b98 --- /dev/null +++ b/skills/rushstack-best-practices/references/build-system.md @@ -0,0 +1,475 @@ +# Build System Reference + +## Build vs Rebuild + +### rush build (Incremental Build) + +**Purpose:** Build only changed projects and dependencies + +**Behavior:** +- Analyzes project dependency graph +- Builds only projects that changed +- Builds downstream dependents +- Uses build cache when available +- Supports parallel execution + +**Use Cases:** +- Daily development +- Quick iteration +- Testing changes + +**Examples:** +```bash +# Build all changed projects +rush build + +# Build specific project and dependencies +rush build --to @my-scope/my-app + +# Build project and downstream dependents +rush build --from @my-scope/my-lib + +# Parallel build (default for bulk commands) +rush build --parallel +``` + +### rush rebuild (Clean Build) + +**Purpose:** Complete clean build of all projects + +**Behavior:** +- Cleans previous build artifacts +- Builds all projects (even unchanged) +- Skips build cache +- Takes longer than incremental build + +**Use Cases:** +- After major dependency updates +- When investigating build issues +- Before releases +- Complete validation + +**Examples:** +```bash +# Rebuild everything +rush rebuild + +# Rebuild specific project and dependencies +rush rebuild --to @my-scope/my-app +``` + +## Build Selection Flags + +### Flag Comparison + +| Flag | Selects | Dependencies Built | Dependents Built | Use Case | +|------|---------|-------------------|------------------|----------| +| `--to ` | Project + dependencies | Yes | No | Build with full chain | +| `--to-except ` | Dependencies only | Yes | No | Pre-build dependencies | +| `--from ` | Project + dependents | No | Yes | Test downstream impact | +| `--impacted-by ` | Affected projects | No | Yes (only impacted) | Quick validation | +| `--impacted-by-except ` | Dependents only | No | Yes (only impacted) | Skip built project | +| `--only ` | Just the project | No | No | When deps are good | + +### --to (Project + Dependencies) + +Build project and all dependencies recursively: + +```bash +rush build --to @my-scope/my-app +``` + +**Use When:** +- Building an application for testing +- Need complete dependency chain +- Publishing a package + +**Dependency Graph Example:** +``` +my-app +├── ui-lib +│ └── utils +└── api-lib + └── utils + +rush build --to my-app builds: utils, ui-lib, api-lib, my-app +``` + +### --to-except (Dependencies Only) + +Build all dependencies, but not the project itself: + +```bash +rush build --to-except @my-scope/my-app +``` + +**Use When:** +- Pre-building dependencies +- Project will be built separately +- Validating dependency chain + +### --from (Project + Dependents) + +Build project and all downstream dependents: + +```bash +rush build --from @my-scope/utils +``` + +**Use When:** +- After library changes +- Testing impact on dependents +- Ensuring downstream compatibility + +**Dependency Graph Example:** +``` +utils (changed) +├── ui-lib +│ └── my-app +└── api-lib + └── my-app + +rush build --from utils builds: utils, ui-lib, api-lib, my-app +``` + +### --impacted-by (Affected Projects) + +Build projects that might be affected by changes: + +```bash +rush build --impacted-by @my-scope/utils +``` + +**Use When:** +- Quick change validation +- Dependencies are already built +- Faster than `--from` + +**Note:** Assumes dependencies are up-to-date + +### --impacted-by-except (Dependents Only) + +Like `--impacted-by` but excludes the project itself: + +```bash +rush build --impacted-by-except @my-scope/utils +``` + +**Use When:** +- Project already built +- Only need to test dependents +- Saving time + +### --only (Just the Project) + +Build only specified project, ignore dependency relationships: + +```bash +rush build --only @my-scope/my-app +``` + +**Use When:** +- Dependencies known to be correct +- Combining with other flags +- Quick single-project rebuild + +**Combined Example:** +```bash +# Build downstream dependents, but only rebuild utils +rush build --from utils --only utils +``` + +## Build Cache + +### Cache Principles + +Rush build cache accelerates builds by caching project outputs: + +**Cache Storage:** `common/temp/build-cache/` + +**Cache Key Based On:** +- Source file contents +- Dependency versions +- Environment variables +- Command line parameters +- Rush configuration + +**Behavior:** +- If cache key matches → Extract cached output +- If cache key differs → Rebuild and update cache + +### Cache Configuration + +**File:** `/config/rush-project.json` + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["lib", "dist"], + "disableBuildCacheForOperation": false, + "dependsOnEnvVars": ["MY_ENV_VAR", "API_KEY"] + } + ] +} +``` + +**Fields:** +- `operationName` - Script name in package.json +- `outputFolderNames` - Folders to cache +- `disableBuildCacheForOperation` - Disable caching for this operation +- `dependsOnEnvVars` - Environment variables that affect build + +### Environment Variables + +**Caching with Environment Variables:** + +```json +{ + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["dist"], + "dependsOnEnvVars": ["NODE_ENV", "API_ENDPOINT"] + } + ] +} +``` + +**Effect:** +- Cache key includes `NODE_ENV` and `API_ENDPOINT` values +- Changing these values invalidates cache +- Different values have different caches + +**Use Cases:** +- Production vs development builds +- Region-specific builds +- Feature flag configurations + +### Disabling Cache + +**Per Operation:** +```json +{ + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["dist"], + "disableBuildCacheForOperation": true // Disable + } + ] +} +``` + +**Per Command:** +```bash +# Rush rebuild always skips cache +rush rebuild + +# Rush build uses cache (unless disabled) +rush build +``` + +## Parallel Execution + +### Enabling Parallelism + +In `command-line.json`: + +```json +{ + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true +} +``` + +**Effect:** +- Builds independent projects simultaneously +- Respects dependency order +- Faster builds on multi-core machines + +### Parallel Build Behavior + +**Dependency Graph:** +``` +app1 depends on lib1 and lib2 +app2 depends on lib2 +lib1 and lib2 are independent +``` + +**Parallel Build Order:** +``` +Phase 1 (parallel): lib1, lib2 +Phase 2 (parallel): app1, app2 +``` + +### Limiting Parallelism + +```bash +# Limit concurrent build jobs +rush build --parallelism 4 +``` + +**Use Cases:** +- Resource-constrained machines +- Preventing memory issues +- CI environment limits + +## Build Best Practices + +### 1. Use Incremental Builds for Development + +**Incorrect:** +```bash +# Always rebuild everything +rush rebuild +``` + +**Correct:** +```bash +# Incremental build for development +rush build +``` + +### 2. Use Selection Flags to Reduce Scope + +**Incorrect:** +```bash +# Build everything when only one project changed +rush build +``` + +**Correct:** +```bash +# Build only affected projects +rush build --to @my-scope/changed-project +``` + +### 3. Configure Build Cache + +**Incorrect:** +```json +// No cache configuration +// Builds are always slow +``` + +**Correct:** +```json +{ + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["dist"], + "disableBuildCacheForOperation": false + } + ] +} +``` + +### 4. Enable Parallelism + +**Incorrect:** +```json +{ + "enableParallelism": false +} +``` + +**Correct:** +```json +{ + "enableParallelism": true +} +``` + +## Build Troubleshooting + +### Cache Issues + +**Symptom:** Build output seems stale + +**Solutions:** +```bash +# Clear cache and rebuild +rush rebuild + +# Or use purge +rush purge +rush build +``` + +### Dependency Build Order + +**Symptom:** Projects build in wrong order + +**Solutions:** +```bash +# Let Rush determine order +rush build # Automatic dependency order + +# Verify dependency graph +rush list --json +``` + +### Slow Builds + +**Symptom:** Builds take too long + +**Solutions:** +```bash +# Use selection flags +rush build --to @my-scope/target-project + +# Enable parallelism +# Check command-line.json has "enableParallelism": true + +# Configure cache +# Check rush-project.json has cache configured +``` + +## Build Scripts + +### package.json Scripts + +**Recommended Setup:** +```json +{ + "scripts": { + "build": "heft build", + "build:production": "heft build --production", + "clean": "heft clean", + "test": "heft test" + } +} +``` + +**Corresponding rush-project.json:** +```json +{ + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["lib", "dist"] + }, + { + "operationName": "build:production", + "outputFolderNames": ["dist"], + "dependsOnEnvVars": ["NODE_ENV"] + } + ] +} +``` + +**Usage:** +```bash +# Run project script directly +cd apps/my-app +rushx build + +# Or via Rush bulk command +rush build +``` diff --git a/skills/rushstack-best-practices/references/core-commands.md b/skills/rushstack-best-practices/references/core-commands.md new file mode 100644 index 0000000000..062461afc8 --- /dev/null +++ b/skills/rushstack-best-practices/references/core-commands.md @@ -0,0 +1,279 @@ +# Core Commands Reference + +## Command Tool Selection + +### rush (Repository-wide Operations) + +**Purpose:** Execute operations affecting the entire repository or multiple projects + +**Features:** +- Strict parameter validation and documentation +- Support for global and batch commands +- Suitable for standardized workflows + +**Use Cases:** +- Dependency installation (`rush install`, `rush update`) +- Building (`rush build`, `rush rebuild`) +- Publishing (`rush publish`) +- Version management (`rush change`, `rush version`) + +### rushx (Single Project Scripts) + +**Purpose:** Execute specific scripts for a single project + +**Features:** +- Similar to `npm run` or `pnpm run` +- Uses Rush version selector for toolchain consistency +- Prepares shell environment based on Rush configuration + +**Use Cases:** +- Running project-specific build scripts +- Executing tests for a single project +- Running development servers + +**Example:** +```bash +cd apps/my-app +rushx build # Equivalent to npm run build +rushx test # Equivalent to npm run test +rushx start # Equivalent to npm run start +``` + +### rush-pnpm (Direct PNPM with Rush Context) + +**Purpose:** Replace direct use of pnpm in Rush repository + +**Features:** +- Sets correct PNPM workspace context +- Supports Rush-specific enhancements +- Provides compatibility checks with Rush + +**Use Cases:** +- When direct PNPM commands are needed +- Troubleshooting PNPM-specific issues +- PNPM operations that Rush doesn't wrap + +**Example:** +```bash +rush-pnpm list # List packages in Rush context +rush-pnpm why # Check why a package is included +``` + +## Common Commands + +### rush update + +**Function:** Install and update dependencies, update shrinkwrap file + +**Important Parameters:** +- `-p, --purge` - Clean before installation +- `--bypass-policy` - Bypass gitPolicy rules +- `--no-link` - Don't create project symlinks +- `--network-concurrency COUNT` - Limit concurrent network requests + +**Use Cases:** +- After first cloning repository +- After pulling new Git changes +- After modifying package.json +- When dependencies need updating + +**Example:** +```bash +rush update # Standard update +rush update --purge # Clean then update +rush update --to @my/app # Update specific project and deps +``` + +### rush install + +**Function:** Install dependencies based on existing shrinkwrap file (read-only) + +**Features:** +- Won't modify shrinkwrap file +- Suitable for CI environment + +**Important Parameters:** +- `-p, --purge` - Clean before installation +- `--bypass-policy` - Bypass gitPolicy rules +- `--no-link` - Don't create project symlinks + +**Use Cases:** +- CI/CD pipelines +- Ensuring dependency version consistency +- Avoiding accidental shrinkwrap file updates + +**Example:** +```bash +rush install # Standard install +rush install --production # Install only production deps +``` + +### rush build + +**Function:** Incremental project build + +**Features:** +- Only builds changed projects and dependencies +- Supports parallel building +- Uses build cache when available + +**Use Cases:** +- Daily development builds +- Quick change validation + +**Example:** +```bash +rush build # Build all changed projects +rush build --to @my/app # Build app and dependencies +rush build --from @my/lib # Build lib and dependents +``` + +### rush rebuild + +**Function:** Complete clean build + +**Features:** +- Builds all projects +- Cleans previous build artifacts +- Skips build cache + +**Use Cases:** +- When complete build cleaning is needed +- When investigating build issues + +**Example:** +```bash +rush rebuild # Rebuild everything +rush rebuild --to @my/app # Rebuild app and dependencies +``` + +### rush add + +**Function:** Add dependencies to project + +**Usage:** `rush add -p [--dev] [--exact]` + +**Important Parameters:** +- `-p, --package` - Package name +- `--dev` - Add as development dependency +- `--exact` - Use exact version (no semver range) +- `--peer` - Add as peer dependency + +**Important:** Must be run in corresponding project directory + +**Example:** +```bash +cd apps/my-app +rush add -p lodash --dev # Add dev dependency +rush add -p react --exact # Add exact version +rush add -p typescript -D # Short for --dev +``` + +### rush remove + +**Function:** Remove project dependencies + +**Usage:** `rush remove -p ` + +**Example:** +```bash +cd apps/my-app +rush remove -p lodash # Remove lodash +``` + +### rush purge + +**Function:** Clean temporary files and installation files + +**Use Cases:** +- Clean build environment +- Resolve dependency issues +- Free up disk space + +**Example:** +```bash +rush purge # Clean all temp files +``` + +## Project Selection Flags + +### --to + +**Function:** Select specified project and all its dependencies + +**Use Cases:** +- Build specific project and its dependencies +- Ensure complete dependency chain build + +**Example:** +```bash +rush build --to @my-company/my-project +rush build --to my-project # Omit scope if unique +rush build --to . # Use current directory's project +``` + +### --to-except + +**Function:** Select all dependencies of specified project, but not the project itself + +**Use Cases:** +- Update project dependencies without processing project itself +- Pre-build dependencies + +**Example:** +```bash +rush build --to-except @my-company/my-project +``` + +### --from + +**Function:** Select specified project and all its downstream dependencies + +**Use Cases:** +- Validate changes' impact on downstream projects +- Build all projects affected by specific project + +**Example:** +```bash +rush build --from @my-company/my-library +``` + +### --impacted-by + +**Function:** Select projects that might be affected by specified project changes, excluding dependencies + +**Use Cases:** +- Quick test of project change impacts +- Use when dependency status is already correct + +**Example:** +```bash +rush build --impacted-by @my-company/my-library +``` + +### --impacted-by-except + +**Function:** Similar to `--impacted-by`, but excludes specified project itself + +**Use Cases:** +- Project itself has been manually built +- Only need to test downstream impacts + +**Example:** +```bash +rush build --impacted-by-except @my-company/my-library +``` + +### --only + +**Function:** Only select specified project, completely ignore dependency relationships + +**Use Cases:** +- Dependency status is known to be correct +- Combine with other selection parameters + +**Example:** +```bash +rush build --only @my-company/my-project +rush build --impacted-by projectA --only projectB +``` diff --git a/skills/rushstack-best-practices/references/dependency-management.md b/skills/rushstack-best-practices/references/dependency-management.md new file mode 100644 index 0000000000..262df0f476 --- /dev/null +++ b/skills/rushstack-best-practices/references/dependency-management.md @@ -0,0 +1,342 @@ +# Dependency Management Reference + +## Package Manager Selection + +### Choosing a Package Manager + +Configure in `rush.json`: + +```json +{ + // PNPM (Recommended) + "pnpmVersion": "8.x.x", + + // Or NPM + // "npmVersion": "8.x.x", + + // Or Yarn + // "yarnVersion": "1.x.x" +} +``` + +**Recommendations:** +- **PNPM** - Preferred: Efficient, strict, handles large monorepos well +- **NPM** - Standard: Good compatibility, widely supported +- **Yarn** - Legacy: Supported, but consider PNPM for new projects + +## Workspace Linking + +### Automatic Local Linking + +Rush automatically creates symlinks for local project dependencies: + +**In project A package.json:** +```json +{ + "dependencies": { + "@my-scope/project-b": "^1.0.0" + } +} +``` + +Rush automatically: +1. Detects `@my-scope/project-b` is a local project +2. Creates symlink in `node_modules/@my-scope/project-b` +3. Links to the actual project folder +4. Updates during each `rush install` or `rush update` + +**Benefits:** +- Live changes to dependencies immediately visible +- No need for npm link / pnpm link +- Automatic dependency resolution + +### Workspace Linking Behavior + +```bash +# After running +rush install + +# Rush creates +apps/my-app/node_modules/@my-scope/ + ├── my-lib -> ../../libraries/my-lib + └── other-lib -> ../../libraries/other-lib +``` + +## Version Management + +### common-versions.json + +**Purpose:** Configure NPM dependency versions affecting all projects in a subspace + +**Location:** `common/config/subspaces//common-versions.json` + +### Preferred Versions + +Restrict specific package versions: + +```json +{ + "preferredVersions": { + "react": "17.0.2", + "react-dom": "17.0.2", + "typescript": "~4.5.0", + "eslint": "^8.0.0" + } +} +``` + +**Use Cases:** +- Force consistent versions across projects +- Prevent version drift +- Ensure compatibility + +### Implicit Preferred Versions + +Automatically add all dependencies to preferredVersions: + +```json +{ + "implicitlyPreferredVersions": true +} +``` + +**Effect:** +- Every dependency used in any project becomes constrained to that version +- Prevents accidental version updates +- **Caution:** Can make dependency updates difficult + +**Recommendation:** Use `false` for active development, `true` for stable maintenance + +### Allowed Alternative Versions + +Allow certain dependencies to use multiple different versions: + +```json +{ + "preferredVersions": { + "typescript": "~4.5.0" + }, + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } +} +``` + +**Use Cases:** +- Gradual migration between major versions +- Testing new versions without full commitment +- Teams need different versions temporarily + +## Adding Dependencies + +### Using rush add + +**Always use Rush commands**, not npm/pnpm directly: + +```bash +# Navigate to project directory +cd apps/my-app + +# Add dependency +rush add -p lodash + +# Add dev dependency +rush add -p typescript --dev + +# Add exact version +rush add -p react --exact + +# Add peer dependency +rush add -p react-dom --peer + +# Add multiple +rush add -p lodash -p axios -p moment +``` + +**Important:** +- Must run in project directory +- Rush updates both package.json and shrinkwrap +- Automatically handles workspace dependencies + +###rush add Options + +| Option | Description | +|--------|-------------| +| `-p, --package ` | Package name | +| `-D, --dev` | Add as devDependency | +| `-E, --exact` | Use exact version | +| `--peer` | Add as peerDependency | +| `--caret` | Use caret range (default for dependencies) | +| `--tilde` | Use tilde range | + +## Removing Dependencies + +### Using rush remove + +```bash +# Navigate to project directory +cd apps/my-app + +# Remove dependency +rush remove -p lodash + +# Remove multiple +rush remove -p lodash -p axios +``` + +## Decoupled Local Dependencies + +### Handling Cyclic Dependencies + +When two projects depend on each other: + +```json +// In apps/my-app/rush.json +{ + "projects": [ + { + "packageName": "@my-scope/my-app", + "projectFolder": "apps/my-app", + "decoupledLocalDependencies": ["@my-scope/shared-lib"] + } + ] +} +``` + +**Effect:** +- Rush won't create symlink for `@my-scope/shared-lib` +- Project uses version from npm (or registry) +- Breaks cycle at build time + +**When to Use:** +- Circular dependency detected +- Temporary workaround during refactoring +- Runtime dependency only (not build-time) + +**Caution:** Should be used sparingly - indicates architecture issue + +## Dependency Best Practices + +### 1. Always Use Rush Commands + +**Incorrect:** +```bash +npm install lodash +pnpm add typescript +``` + +**Correct:** +```bash +rush add -p lodash +rush add -p typescript +``` + +### 2. Use Workspace References + +**Incorrect:** +```json +{ + "dependencies": { + "my-lib": "file:../libraries/my-lib" + } +} +``` + +**Correct:** +```json +{ + "dependencies": { + "@my-scope/my-lib": "^1.0.0" + } +} +``` + +### 3. Centralize Version Constraints + +Use `common-versions.json` instead of duplicating in each project: + +**Incorrect:** +- Every project has `"typescript": "~4.5.0"` in package.json + +**Correct:** +```json +// common/config/subspaces/default/common-versions.json +{ + "preferredVersions": { + "typescript": "~4.5.0" + } +} +``` + +### 4. Careful with implicitlyPreferredVersions + +**Good for:** +- Stable maintenance branches +- Released products +- Teams that want strict version control + +**Bad for:** +- Active development +- Libraries +- Frequent dependency updates + +## Troubleshooting Dependencies + +### Dependency Conflicts + +**Symptom:** Version conflicts or peer dependency warnings + +**Solutions:** +```bash +# Clean slate +rush purge +rush update --recheck + +# Check what depends on a package +rush-pnpm why + +# View dependency tree +rush-pnpm list --depth 0 +``` + +### Workspace Linking Issues + +**Symptom:** Local changes not reflected + +**Solutions:** +```bash +# Reinstall to recreate links +rush install + +# Check links are correct +ls -la node_modules/@my-scope/ +``` + +### Version Drift + +**Symptom:** Different projects using different versions + +**Solution:** +```json +// common-versions.json +{ + "preferredVersions": { + "problematic-package": "exact-version" + }, + "implicitlyPreferredVersions": false // Start with false +} +``` + +## Subspace Dependency Isolation + +When using subspaces, each has its own: +- `pnpm-lock.yaml` - Independent lock file +- `common-versions.json` - Independent version constraints +- Dependency tree - Isolated from other subspaces + +**Benefits:** +- Team A can use React 17 while Team B uses React 18 +- Dependency updates in one subspace don't affect others +- Faster installs (only affected subspace updated) + +**See:** `references/subspace.md` for detailed subspace configuration diff --git a/skills/rushstack-best-practices/references/project-configuration.md b/skills/rushstack-best-practices/references/project-configuration.md new file mode 100644 index 0000000000..fe3ccf1b2b --- /dev/null +++ b/skills/rushstack-best-practices/references/project-configuration.md @@ -0,0 +1,324 @@ +# Project Configuration Reference + +## Standard Directory Structure + +``` +/ +├── common/ # Rush common files directory +│ ├── autoinstallers/ # Autoinstaller tool configuration +│ ├── config/ # Configuration files directory +│ │ ├── rush/ # Rush core configuration +│ │ │ ├── command-line.json # Command line configuration +│ │ │ ├── build-cache.json # Build cache configuration +│ │ │ ├── experiments.json # Feature experiments +│ │ │ └── subspaces.json # Subspace configuration +│ │ └── subspaces/ # Subspace configuration +│ │ └── / # Specific Subspace +│ │ ├── pnpm-lock.yaml # Subspace dependency lock file +│ │ ├── .pnpmfile.cjs # PNPM hook script +│ │ ├── common-versions.json # Subspace version configuration +│ │ ├── pnpm-config.json # PNPM configuration +│ │ └── repo-state.json # Subspace state hash value +│ ├── scripts/ # Common scripts +│ └── temp/ # Temporary files +├── apps/ # Application projects +│ └── / # 2 levels deep required +├── libraries/ # Library projects +│ └── / # 2 levels deep required +├── tools/ # Tool projects +│ └── / # 2 levels deep required +├── rush.json # Rush main configuration file +└── pnpm-lock.yaml # Root lock file (if not using subspaces) +``` + +**Important:** Projects must be exactly 2 levels deep (`projectFolderMinDepth: 2`, `projectFolderMaxDepth: 2`) + +## rush.json + +**Purpose:** Main Rush configuration file + +**Location:** Repository root + +### Basic Structure + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + "rushVersion": "5.x.x", + + // Package Manager Selection (choose one) + "pnpmVersion": "8.x.x", + // "npmVersion": "8.x.x", + // "yarnVersion": "1.x.x", + + // Project Folder Depth + "projectFolderMinDepth": 2, + "projectFolderMaxDepth": 2, + + // Node.js Version Requirement + "nodeSupportedVersionRange": ">=14.15.0", + + // Projects Array + "projects": [] +} +``` + +### Project Configuration + +```json +{ + "projects": [ + { + "packageName": "@my-scope/my-project", // npm package name + "projectFolder": "libraries/my-project", // Path from repo root + "shouldPublish": true, // Should this be published? + "decoupledLocalDependencies": [], // For cyclic dependencies + "subspaceName": "my-subspace", // Optional: subspace assignment + "reviewCategory": "production" // Optional: review category + } + ] +} +``` + +**Project Fields:** +- `packageName` - The npm package name (must match package.json) +- `projectFolder` - Relative path from repository root +- `shouldPublish` - Whether package should be published to npm +- `decoupledLocalDependencies` - Array of local packages to exclude from link (for cyclic deps) +- `subspaceName` - Which subspace this project belongs to +- `reviewCategory` - Category for review purposes + +### Git Policy + +```json +{ + "gitPolicy": { + "allowedBranchRegExps": [ + "main", + "release/*", + "hotfix/*" + ], + "sampleEmail": "example@example.com" + } +} +``` + +## command-line.json + +**Purpose:** Define custom Rush commands + +**Location:** `common/config/rush/command-line.json` + +### Bulk Commands + +Execute separately for each project: + +```json +{ + "commandKind": "bulk", + "name": "build", + "summary": "Build all projects", + "description": "Builds all projects in dependency order", + "enableParallelism": true, + "ignoreMissingScript": false, + "safeForSimultaneousRushProcesses": false +} +``` + +**Bulk Command Fields:** +- `commandKind` - Must be "bulk" +- `name` - Command name +- `summary` - Short description +- `description` - Long description +- `enableParallelism` - Allow parallel execution +- `ignoreMissingScript` - Don't fail if project lacks this script +- `safeForSimultaneousRushProcesses` - Can multiple Rush instances run this? + +### Global Commands + +Execute once for entire repository: + +```json +{ + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "description": "Deploys the application to production", + "shellCommand": "node common/scripts/deploy.js", + "safeForSimultaneousRushProcesses": false +} +``` + +### Parameters + +Six parameter types supported: + +**Flag Parameter:** +```json +{ + "parameterKind": "flag", + "longName": "--production", + "shortName": "-p", + "description": "Production mode", + "required": false +} +``` + +**String Parameter:** +```json +{ + "parameterKind": "string", + "longName": "--environment", + "shortName": "-e", + "description": "Environment name", + "required": false, + "defaultValue": "development" +} +``` + +**String List Parameter:** +```json +{ + "parameterKind": "stringList", + "longName": "--tag", + "description": "Tags for the build", + "required": false +} +``` + +**Choice Parameter:** +```json +{ + "parameterKind": "choice", + "longName": "--locale", + "description": "Locale for the build", + "alternatives": ["en-us", "zh-cn", "ja-jp"], + "required": false, + "defaultValue": "en-us" +} +``` + +**Integer Parameter:** +```json +{ + "parameterKind": "integer", + "longName": "--timeout", + "description": "Timeout in milliseconds", + "required": false +} +``` + +**Integer List Parameter:** +```json +{ + "parameterKind": "integerList", + "longName": "--pr", + "description": "Pull request numbers", + "required": false +} +``` + +## rush-project.json + +**Purpose:** Project-specific Rush configuration + +**Location:** `/config/rush-project.json` + +### Build Cache Configuration + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["lib", "dist"], + "disableBuildCacheForOperation": false, + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"] + } + ] +} +``` + +**Fields:** +- `operationName` - Name of the operation (matches package.json script) +- `outputFolderNames` - Folders to cache +- `disableBuildCacheForOperation` - Disable caching for this operation +- `dependsOnEnvVars` - Environment variables that affect build + +## Example Complete Configuration + +### rush.json +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + "rushVersion": "5.109.0", + "pnpmVersion": "8.15.0", + "projectFolderMinDepth": 2, + "projectFolderMaxDepth": 2, + "nodeSupportedVersionRange": ">=18.17.0 <19.0.0", + "projects": [ + { + "packageName": "@my-scope/my-app", + "projectFolder": "apps/my-app", + "shouldPublish": true, + "subspaceName": "default" + }, + { + "packageName": "@my-scope/my-lib", + "projectFolder": "libraries/my-lib", + "shouldPublish": true, + "subspaceName": "default" + } + ] +} +``` + +### command-line.json +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true + }, + { + "commandKind": "bulk", + "name": "test", + "summary": "Test projects", + "enableParallelism": true + }, + { + "commandKind": "global", + "name": "clean", + "summary": "Clean build outputs", + "shellCommand": "node common/scripts/clean.js" + } + ], + "parameters": [ + { + "parameterKind": "flag", + "longName": "--production", + "shortName": "-p", + "description": "Production mode" + } + ] +} +``` + +### Project config/rush-project.json +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "build", + "outputFolderNames": ["dist"], + "disableBuildCacheForOperation": false + } + ] +} +``` diff --git a/skills/rushstack-best-practices/references/subspace.md b/skills/rushstack-best-practices/references/subspace.md new file mode 100644 index 0000000000..2989338055 --- /dev/null +++ b/skills/rushstack-best-practices/references/subspace.md @@ -0,0 +1,424 @@ +# Subspace Reference + +## What is Subspace? + +Subspace is a Rush feature that allows multiple PNPM lock files in a single Rush monorepo. + +### Benefits + +**Dependency Isolation:** +- Different teams can use different dependency versions +- Team A can use React 17 while Team B uses React 18 +- Reduce risk from dependency updates + +**Performance:** +- Only affected subspaces update during `rush install` +- Faster dependency operations +- Smaller lock files to manage + +**Team Autonomy:** +- Teams manage their own dependencies +- Less coordination needed +- Independent release cycles + +### When to Use Subspace + +**Consider using subspace when:** +- Repository has 50+ projects +- Multiple teams with different dependency needs +- Conflicting version requirements +- Performance issues with dependency operations +- Teams want autonomy for dependency choices + +**Avoid subspace when:** +- Small monorepo (< 20 projects) +- Single team or unified dependencies +- Simplicity is preferred +- Just starting with Rush + +## Subspace Configuration + +### Step 1: Enable Subspaces + +**File:** `common/config/rush/subspaces.json` + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + "subspacesEnabled": true, + "subspaceNames": ["team-a", "team-b", "shared"] +} +``` + +**Fields:** +- `subspacesEnabled` - Enable/disable subspace feature +- `subspaceNames` - List of subspace names + +### Step 2: Assign Projects to Subspaces + +**File:** `rush.json` + +```json +{ + "projects": [ + { + "packageName": "@team-a/app-1", + "projectFolder": "apps/team-a/app-1", + "subspaceName": "team-a" + }, + { + "packageName": "@team-a/lib-1", + "projectFolder": "libraries/team-a/lib-1", + "subspaceName": "team-a" + }, + { + "packageName": "@team-b/app-1", + "projectFolder": "apps/team-b/app-1", + "subspaceName": "team-b" + }, + { + "packageName": "@shared/utils", + "projectFolder": "libraries/shared/utils", + "subspaceName": "shared" + } + ] +} +``` + +**Important:** Each project must belong to exactly one subspace + +### Step 3: Subspace Configuration Files + +Each subspace has its own configuration directory: + +``` +common/config/subspaces/ +├── team-a/ +│ ├── pnpm-lock.yaml # Subspace lock file +│ ├── common-versions.json # Version constraints +│ ├── pnpm-config.json # PNPM settings +│ └── repo-state.json # State hash +├── team-b/ +│ ├── pnpm-lock.yaml +│ ├── common-versions.json +│ ├── pnpm-config.json +│ └── repo-state.json +└── shared/ + ├── pnpm-lock.yaml + ├── common-versions.json + ├── pnpm-config.json + └── repo-state.json +``` + +### Subspace common-versions.json + +**File:** `common/config/subspaces//common-versions.json` + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "preferredVersions": { + // Subspace-specific versions + "react": "17.0.2", + "typescript": "~4.5.0" + }, + "implicitlyPreferredVersions": true, + "allowedAlternativeVersions": {} +} +``` + +**Each subspace can have:** +- Different preferred versions +- Different implicit preferences +- Different allowed alternatives + +## Subspace Workflows + +### Initial Setup + +```bash +# 1. Create subspace configuration +mkdir -p common/config/subspaces/team-a + +# 2. Enable subspaces in subspaces.json +# Edit: common/config/rush/subspaces.json + +# 3. Assign projects in rush.json +# Edit: rush.json - add subspaceName to projects + +# 4. Run update to generate lock files +rush update +``` + +### Adding Projects to Subspace + +```bash +# 1. Create project directory +mkdir -p apps/team-a/new-app + +# 2. Add to rush.json +{ + "packageName": "@team-a/new-app", + "projectFolder": "apps/team-a/new-app", + "subspaceName": "team-a" +} + +# 3. Run update +rush update +``` + +### Updating Dependencies + +**Update specific subspace:** +```bash +# Only updates team-a subspace +rush update --to @team-a/app-1 +``` + +**Update all subspaces:** +```bash +# Updates all subspaces +rush update +``` + +## Subspace Isolation + +### Dependency Isolation + +Each subspace has its own dependency tree: + +**team-a subspace:** +``` +team-a/app-1/ +└── node_modules/ + ├── react@17.0.2 + └── typescript@4.5.0 +``` + +**team-b subspace:** +``` +team-b/app-1/ +└── node_modules/ + ├── react@18.2.0 + └── typescript@5.0.0 +``` + +### Cross-Subspace Dependencies + +Projects can depend on projects in other subspaces: + +```json +// team-a/app-1 depends on shared/utils +{ + "dependencies": { + "@shared/utils": "^1.0.0" + } +} +``` + +**Rush handles:** +- Workspace linking across subspaces +- Build order across subspaces +- Version compatibility + +### Shared Dependencies + +**Pattern:** Create a "shared" subspace for common libraries + +```json +// subspaces.json +{ + "subspaceNames": ["team-a", "team-b", "shared"] +} + +// rush.json +{ + "projects": [ + { + "packageName": "@shared/utils", + "projectFolder": "libraries/shared/utils", + "subspaceName": "shared" + }, + { + "packageName": "@team-a/app", + "projectFolder": "apps/team-a/app", + "subspaceName": "team-a" + } + ] +} +``` + +## Subspace Best Practices + +### 1. Organize by Team or Domain + +**Good:** +``` +subspaceNames: ["platform", "backend", "frontend", "shared"] +``` + +**Bad:** +``` +subspaceNames: ["subspace1", "subspace2", "subspace3"] +``` + +### 2. Use Shared Subspace for Common Code + +**Pattern:** +``` +- team-a: Team A's apps and libs +- team-b: Team B's apps and libs +- shared: Common libraries used by both teams +``` + +### 3. Minimize Cross-Subspace Dependencies + +**Good:** +``` +team-a/app → team-a/lib → shared/utils +team-b/app → team-b/lib → shared/utils +``` + +**Avoid:** +``` +team-a/app → team-b/lib # Creates coupling +``` + +### 4. Keep Subspace Sizes Balanced + +**Good:** +``` +team-a: 20 projects +team-b: 18 projects +shared: 10 projects +``` + +**Bad:** +``` +team-a: 2 projects +team-b: 50 projects # Imbalanced +``` + +## Subspace Troubleshooting + +### Lock File Conflicts + +**Symptom:** Subspace lock files out of sync + +**Solution:** +```bash +# Regenerate all lock files +rush update --purge +``` + +### Cross-Subspace Build Issues + +**Symptom:** Projects build in wrong order + +**Solution:** +```bash +# Verify dependency graph +rush list --json + +# Force rebuild across subspaces +rush rebuild +``` + +### Version Conflicts Across Subspaces + +**Symptom:** Different subspaces require different versions + +**Solution:** +```bash +# Update specific subspace +rush update --to @team-a/app-1 + +# Or use allowedAlternativeVersions +``` + +## Subspace vs No Subspace + +### No Subspace (Default) + +**Structure:** +``` +common/ +├── config/rush/ +└── temp/ +pnpm-lock.yaml (single lock file) +rush.json +``` + +**Pros:** +- Simpler setup +- Easier to understand +- Single source of truth for versions + +**Cons:** +- All projects share same dependency tree +- Dependency updates affect all projects +- Slower installs for large repos + +### With Subspace + +**Structure:** +``` +common/ +├── config/ +│ ├── rush/ +│ └── subspaces/ +│ ├── team-a/ +│ │ └── pnpm-lock.yaml +│ └── team-b/ +│ └── pnpm-lock.yaml +└── temp/ +rush.json +``` + +**Pros:** +- Independent dependency trees +- Faster installs (only affected subspaces) +- Team autonomy + +**Cons:** +- More complex setup +- More files to manage +- Potential for duplication + +## Migration to Subspace + +### Step-by-Step Migration + +1. **Plan your subspaces:** + ```json + { + "subspaceNames": ["team-a", "team-b", "shared"] + } + ``` + +2. **Enable subspaces:** + ```bash + # Edit common/config/rush/subspaces.json + ``` + +3. **Assign projects:** + ```bash + # Edit rush.json - add subspaceName to each project + ``` + +4. **Generate lock files:** + ```bash + rush update + ``` + +5. **Verify:** + ```bash + # Check lock files created + ls common/config/subspaces/*/pnpm-lock.yaml + ``` + +6. **Commit changes:** + ```bash + git add . + git commit -m "Enable Rush subspaces" + ```