|
| 1 | +# Vite-Plus |
| 2 | + |
| 3 | +A monorepo task runner (like nx/turbo) with intelligent caching and dependency resolution. |
| 4 | + |
| 5 | +## Core Concept |
| 6 | + |
| 7 | +**Task Execution**: Run tasks across monorepo packages with automatic dependency ordering. |
| 8 | + |
| 9 | +```bash |
| 10 | +# Built-in commands |
| 11 | +vp build # Run Vite build (dedicated command) |
| 12 | +vp test # Run Vitest (dedicated command) |
| 13 | +vp lint # Run oxlint (dedicated command) |
| 14 | + |
| 15 | +# Run tasks across packages (explicit mode) |
| 16 | +vp run -r build # recursive with topological ordering |
| 17 | +vp run app#build web#build # specific packages |
| 18 | +vp run -r --no-topological build # recursive without implicit deps |
| 19 | + |
| 20 | +# Run task in current package (implicit mode - for non-built-in tasks) |
| 21 | +vp run dev # runs dev script from package.json |
| 22 | +``` |
| 23 | + |
| 24 | +## Key Architecture |
| 25 | + |
| 26 | +- **Entry**: `crates/vite_task/src/lib.rs` - CLI parsing and main logic |
| 27 | +- **Workspace**: `crates/vite_task/src/config/workspace.rs` - Loads packages, creates task graph |
| 28 | +- **Task Graph**: `crates/vite_task/src/config/task_graph_builder.rs` - Builds dependency graph |
| 29 | +- **Execution**: `crates/vite_task/src/schedule.rs` - Executes tasks in dependency order |
| 30 | + |
| 31 | +## Task Dependencies |
| 32 | + |
| 33 | +1. **Explicit** (always applied): Defined in `vite-task.json` |
| 34 | + |
| 35 | + ```json |
| 36 | + { |
| 37 | + "tasks": { |
| 38 | + "test": { |
| 39 | + "command": "jest", |
| 40 | + "dependsOn": ["build", "lint"] |
| 41 | + } |
| 42 | + } |
| 43 | + } |
| 44 | + ``` |
| 45 | + |
| 46 | +2. **Implicit** (when `--topological`): Based on package.json dependencies |
| 47 | + - If A depends on B, then A#build depends on B#build automatically |
| 48 | + |
| 49 | +## Key Features |
| 50 | + |
| 51 | +- **Topological Flag**: Controls implicit dependencies from package relationships |
| 52 | + - Default: ON for `--recursive`, OFF otherwise |
| 53 | + - Toggle with `--no-topological` to disable |
| 54 | + |
| 55 | +- **Boolean Flags**: All support `--no-*` pattern for explicit disable |
| 56 | + - Example: `--recursive` vs `--no-recursive` |
| 57 | + - Conflicts handled by clap |
| 58 | + - If you want to add a new boolean flag, follow this pattern |
| 59 | + |
| 60 | +## Path Type System |
| 61 | + |
| 62 | +- **Type Safety**: All paths use typed `vite_path` instead of `std::path` for better safety |
| 63 | + - **Absolute Paths**: `vite_path::AbsolutePath` / `AbsolutePathBuf` |
| 64 | + - **Relative Paths**: `vite_path::RelativePath` / `RelativePathBuf` |
| 65 | + |
| 66 | +- **Usage Guidelines**: |
| 67 | + - Use methods such as `strip_prefix`/`join` provided in `vite_path` for path operations instead of converting to std paths |
| 68 | + - Only convert to std paths when interfacing with std library functions, and this should be implicit in most cases thanks to `AsRef<Path>` implementations |
| 69 | + - Add necessary methods in `vite_path` instead of falling back to std path types |
| 70 | + |
| 71 | +- **Converting from std paths** (e.g., `TempDir::path()`): |
| 72 | + |
| 73 | + ```rust |
| 74 | + let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap(); |
| 75 | + ``` |
| 76 | + |
| 77 | +- **Function signatures**: Prefer `&AbsolutePath` over `&std::path::Path` |
| 78 | + |
| 79 | +- **Passing to std functions**: `AbsolutePath` implements `AsRef<Path>`, use `.as_path()` when explicit `&Path` is required |
| 80 | + |
| 81 | +## Clippy Rules |
| 82 | + |
| 83 | +All **new** Rust code must follow the custom clippy rules defined in `.clippy.toml` (disallowed types, macros, and methods). Existing code may not fully comply due to historical reasons. |
| 84 | + |
| 85 | +## CLI Output |
| 86 | + |
| 87 | +All user-facing output must go through shared output modules instead of raw print calls. |
| 88 | + |
| 89 | +- **Rust**: Use `vite_shared::output` functions (`info`, `warn`, `error`, `note`, `success`) — never raw `println!`/`eprintln!` (enforced by clippy `disallowed-macros`) |
| 90 | +- **TypeScript**: Use `packages/cli/src/utils/terminal.ts` functions (`infoMsg`, `warnMsg`, `errorMsg`, `noteMsg`, `log`) — never raw `console.log`/`console.error` |
| 91 | + |
| 92 | +## Git Workflow |
| 93 | + |
| 94 | +- Run `vp check --fix` before committing to format and lint code |
| 95 | + |
| 96 | +## Quick Reference |
| 97 | + |
| 98 | +- **Compound Commands**: `"build": "tsc && rollup"` splits into subtasks |
| 99 | +- **Task Format**: `package#task` (e.g., `app#build`) |
| 100 | +- **Path Types**: Use `vite_path` types instead of `std::path` types for type safety |
| 101 | +- **Tests**: Run `cargo test -p vite_task` to verify changes |
| 102 | +- **Debug**: Use `--debug` to see cache operations |
| 103 | + |
| 104 | +## Tests |
| 105 | + |
| 106 | +- Run `cargo test` to execute all tests |
| 107 | +- You never need to run `pnpm install` in the test fixtures dir, vite-plus should able to load and parse the workspace without `pnpm install`. |
| 108 | + |
| 109 | +### Environment Variables in Tests |
| 110 | + |
| 111 | +- **Prefer `EnvConfig::test_scope()`**: For tests needing custom config values (VP_HOME, npm registry, etc.), use thread-local `EnvConfig::test_scope()` or `EnvConfig::test_guard()` from `vite_shared` — no `unsafe`, no `#[serial]`, full parallelism |
| 112 | +- **`#[serial]` required for `std::env::set_var`/`remove_var`**: Any test that directly modifies process env vars (PATH, VP_SHIM_TOOL, etc.) MUST have `#[serial_test::serial]` to prevent concurrent access races |
| 113 | +- **Clean up ALL related env vars**: When clearing env vars before a test, clear ALL vars that the function under test reads — not just the one being tested |
| 114 | + |
| 115 | +## Build |
| 116 | + |
| 117 | +- Run `pnpm bootstrap-cli` from the project root to build all packages and install the global CLI |
| 118 | + - This builds all `@voidzero-dev/*` and `vite-plus` packages |
| 119 | + - Compiles the Rust NAPI bindings and the `vp` Rust binary |
| 120 | + - Installs the CLI globally to `~/.vite-plus/` |
| 121 | + |
| 122 | +## Snap Tests |
| 123 | + |
| 124 | +Snap tests are located in `packages/cli/snap-tests/` (local CLI) and `packages/cli/snap-tests-global/` (global CLI). Each test case is a directory containing: |
| 125 | + |
| 126 | +- `package.json` - Package configuration for the test |
| 127 | +- `steps.json` - Commands to run and environment variables |
| 128 | +- `src/` - Source files for the test |
| 129 | +- `snap.txt` - Expected output (generated/updated by running the test) |
| 130 | + |
| 131 | +```bash |
| 132 | +# Run all snap tests (local + global) |
| 133 | +pnpm -F vite-plus snap-test |
| 134 | + |
| 135 | +# Run only local CLI snap tests |
| 136 | +pnpm -F vite-plus snap-test-local |
| 137 | +pnpm -F vite-plus snap-test-local <name-filter> |
| 138 | + |
| 139 | +# Run only global CLI snap tests |
| 140 | +pnpm -F vite-plus snap-test-global |
| 141 | +pnpm -F vite-plus snap-test-global <name-filter> |
| 142 | +``` |
| 143 | + |
| 144 | +The snap test will automatically generate/update the `snap.txt` file with the command outputs. It exits with zero status even if there are output differences; you need to manually check the diffs(`git diff`) to verify correctness. |
0 commit comments