|
| 1 | +# CLI Package Build Architecture |
| 2 | + |
| 3 | +This document explains how `@voidzero-dev/vite-plus` is built and how it re-exports the test package. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The CLI package uses a **3-step build process**: |
| 8 | + |
| 9 | +1. **TypeScript Compilation** - Compile TypeScript source to JavaScript |
| 10 | +2. **NAPI Binding Build** - Compile Rust code to native Node.js bindings |
| 11 | +3. **Test Package Export Sync** - Re-export `@voidzero-dev/vite-plus-test` under `./test/*` |
| 12 | + |
| 13 | +This allows users to import everything from a single package (`@voidzero-dev/vite-plus`) instead of needing to know about the separate test package. |
| 14 | + |
| 15 | +## Build Steps |
| 16 | + |
| 17 | +### Step 1: TypeScript Compilation (`buildCli`) |
| 18 | + |
| 19 | +Compiles TypeScript source files using the TypeScript compiler API: |
| 20 | + |
| 21 | +```typescript |
| 22 | +const program = createProgram({ |
| 23 | + rootNames: fileNames, |
| 24 | + options, |
| 25 | + host, |
| 26 | +}); |
| 27 | +program.emit(); |
| 28 | +``` |
| 29 | + |
| 30 | +**Input**: `src/*.ts` files |
| 31 | +**Output**: `dist/*.js`, `dist/*.d.ts` |
| 32 | + |
| 33 | +### Step 2: NAPI Binding Build (`buildNapiBinding`) |
| 34 | + |
| 35 | +Builds native Rust bindings using `@napi-rs/cli`: |
| 36 | + |
| 37 | +```typescript |
| 38 | +const cli = new NapiCli(); |
| 39 | +await cli.build({ |
| 40 | + packageJsonPath: '../package.json', |
| 41 | + cwd: 'binding', |
| 42 | + platform: true, |
| 43 | + release: process.env.VITE_PLUS_CLI_DEBUG !== '1', |
| 44 | + esm: true, |
| 45 | +}); |
| 46 | +``` |
| 47 | + |
| 48 | +**Input**: `binding/*.rs` (Rust source) |
| 49 | +**Output**: `binding/*.node` (platform-specific binaries) |
| 50 | + |
| 51 | +The build generates platform-specific native binaries and formats the generated JavaScript wrapper with `oxfmt`. |
| 52 | + |
| 53 | +### Step 3: Test Package Export Sync (`syncTestPackageExports`) |
| 54 | + |
| 55 | +Reads the test package's exports and creates shim files that re-export everything under `./test/*`: |
| 56 | + |
| 57 | +```typescript |
| 58 | +// For each test package export like "./browser-playwright" |
| 59 | +// Creates a shim file: dist/test/browser-playwright.js |
| 60 | +export * from '@voidzero-dev/vite-plus-test/browser-playwright'; |
| 61 | +``` |
| 62 | + |
| 63 | +**Input**: `../test/package.json` exports |
| 64 | +**Output**: `dist/test/*.js`, `dist/test/*.d.ts`, updated `package.json` exports |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## Output Structure |
| 69 | + |
| 70 | +``` |
| 71 | +packages/cli/ |
| 72 | +├── dist/ |
| 73 | +│ ├── index.js # Main entry (ESM) |
| 74 | +│ ├── index.cjs # Main entry (CJS) |
| 75 | +│ ├── index.d.ts # Type declarations |
| 76 | +│ ├── bin.js # CLI entry point |
| 77 | +│ └── test/ # Synced test exports |
| 78 | +│ ├── index.js # Re-exports @voidzero-dev/vite-plus-test |
| 79 | +│ ├── index.cjs |
| 80 | +│ ├── index.d.ts |
| 81 | +│ ├── browser-playwright.js |
| 82 | +│ ├── browser-playwright.d.ts |
| 83 | +│ ├── plugins/ |
| 84 | +│ │ ├── runner.js |
| 85 | +│ │ ├── utils.js |
| 86 | +│ │ ├── spy.js |
| 87 | +│ │ └── ... (33+ plugin shims) |
| 88 | +│ └── ... |
| 89 | +├── binding/ |
| 90 | +│ ├── index.js # NAPI binding JS wrapper |
| 91 | +│ ├── index.d.ts # NAPI type declarations |
| 92 | +│ └── *.node # Platform-specific binaries |
| 93 | +└── bin/ |
| 94 | + └── vite # Shell entry point |
| 95 | +``` |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +## NAPI Targets |
| 100 | + |
| 101 | +The CLI builds native bindings for the following platform targets: |
| 102 | + |
| 103 | +| Target | Platform | Architecture | Output File | |
| 104 | +| --------------------------- | -------- | ------------ | --------------------------------- | |
| 105 | +| `aarch64-apple-darwin` | macOS | ARM64 | `vite-plus.darwin-arm64.node` | |
| 106 | +| `x86_64-apple-darwin` | macOS | x64 | `vite-plus.darwin-x64.node` | |
| 107 | +| `aarch64-unknown-linux-gnu` | Linux | ARM64 | `vite-plus.linux-arm64-gnu.node` | |
| 108 | +| `x86_64-unknown-linux-gnu` | Linux | x64 | `vite-plus.linux-x64-gnu.node` | |
| 109 | +| `aarch64-pc-windows-msvc` | Windows | ARM64 | `vite-plus.win32-arm64-msvc.node` | |
| 110 | +| `x86_64-pc-windows-msvc` | Windows | x64 | `vite-plus.win32-x64-msvc.node` | |
| 111 | + |
| 112 | +These targets are defined in `package.json` under the `napi.targets` field. |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +## Test Package Export Sync Details |
| 117 | + |
| 118 | +### Why Shim Files? |
| 119 | + |
| 120 | +Instead of copying the actual dist files from the test package, we create thin shim files that re-export from `@voidzero-dev/vite-plus-test`. This approach: |
| 121 | + |
| 122 | +1. **Keeps packages in sync** - No need to rebuild CLI when test package changes |
| 123 | +2. **Reduces duplication** - No file copying, just re-exports |
| 124 | +3. **Preserves module resolution** - Node.js resolves to the actual test package |
| 125 | + |
| 126 | +### Export Mapping |
| 127 | + |
| 128 | +All test package exports are mapped under `./test/*`: |
| 129 | + |
| 130 | +| Test Package Export | CLI Package Export | |
| 131 | +| ------------------------------------------------- | ------------------------------------------------- | |
| 132 | +| `@voidzero-dev/vite-plus-test` | `@voidzero-dev/vite-plus/test` | |
| 133 | +| `@voidzero-dev/vite-plus-test/browser` | `@voidzero-dev/vite-plus/test/browser` | |
| 134 | +| `@voidzero-dev/vite-plus-test/browser-playwright` | `@voidzero-dev/vite-plus/test/browser-playwright` | |
| 135 | +| `@voidzero-dev/vite-plus-test/plugins/runner` | `@voidzero-dev/vite-plus/test/plugins/runner` | |
| 136 | + |
| 137 | +### Conditional Export Handling |
| 138 | + |
| 139 | +The sync handles complex conditional exports with `import`/`require`/`node`/`types` conditions. |
| 140 | + |
| 141 | +**Test package's main export** (`"."`): |
| 142 | + |
| 143 | +```json |
| 144 | +".": { |
| 145 | + "import": { "types": "...", "node": "...", "default": "..." }, |
| 146 | + "require": { "types": "...", "default": "..." } |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +**Becomes CLI package export** (`"./test"`): |
| 151 | + |
| 152 | +```json |
| 153 | +"./test": { |
| 154 | + "import": { |
| 155 | + "types": "./dist/test/index.d.ts", |
| 156 | + "node": "./dist/test/index.js", |
| 157 | + "default": "./dist/test/index.js" |
| 158 | + }, |
| 159 | + "require": { |
| 160 | + "types": "./dist/test/index.d.cts", |
| 161 | + "default": "./dist/test/index.cjs" |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +For each condition, appropriate shim files are created: |
| 167 | + |
| 168 | +- `.js` for ESM imports |
| 169 | +- `.cjs` for CommonJS requires |
| 170 | +- `.d.ts` / `.d.cts` for type declarations |
| 171 | + |
| 172 | +### Shim File Contents |
| 173 | + |
| 174 | +**ESM shim** (`dist/test/browser-playwright.js`): |
| 175 | + |
| 176 | +```javascript |
| 177 | +export * from '@voidzero-dev/vite-plus-test/browser-playwright'; |
| 178 | +``` |
| 179 | + |
| 180 | +**CJS shim** (`dist/test/index.cjs`): |
| 181 | + |
| 182 | +```javascript |
| 183 | +module.exports = require('@voidzero-dev/vite-plus-test'); |
| 184 | +``` |
| 185 | + |
| 186 | +**Type shim** (`dist/test/browser-playwright.d.ts`): |
| 187 | + |
| 188 | +```typescript |
| 189 | +export * from '@voidzero-dev/vite-plus-test/browser-playwright'; |
| 190 | +``` |
| 191 | + |
| 192 | +--- |
| 193 | + |
| 194 | +## Build Dependencies |
| 195 | + |
| 196 | +| Package | Purpose | |
| 197 | +| -------------- | -------------------------------- | |
| 198 | +| `@napi-rs/cli` | NAPI build toolchain for Rust | |
| 199 | +| `oxfmt` | Code formatting for generated JS | |
| 200 | +| `typescript` | TypeScript compilation | |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +## Debug Mode |
| 205 | + |
| 206 | +To build with debug (unoptimized) Rust bindings: |
| 207 | + |
| 208 | +```bash |
| 209 | +VITE_PLUS_CLI_DEBUG=1 pnpm build |
| 210 | +``` |
| 211 | + |
| 212 | +This sets `release: false` in the NAPI build options, producing larger but faster-to-compile debug binaries. |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## Build Commands |
| 217 | + |
| 218 | +```bash |
| 219 | +# Build the CLI package |
| 220 | +pnpm -C packages/cli build |
| 221 | + |
| 222 | +# Build from monorepo root |
| 223 | +pnpm build --filter @voidzero-dev/vite-plus |
| 224 | + |
| 225 | +# Debug build |
| 226 | +VITE_PLUS_CLI_DEBUG=1 pnpm -C packages/cli build |
| 227 | +``` |
| 228 | + |
| 229 | +--- |
| 230 | + |
| 231 | +## Package Exports |
| 232 | + |
| 233 | +After building, the CLI package exports: |
| 234 | + |
| 235 | +| Export Path | Description | |
| 236 | +| --------------------------- | ------------------------------- | |
| 237 | +| `.` | Main entry (CLI utilities) | |
| 238 | +| `./bin` | CLI binary entry point | |
| 239 | +| `./binding` | NAPI native binding | |
| 240 | +| `./test` | Test package main entry | |
| 241 | +| `./test/browser` | Browser testing utilities | |
| 242 | +| `./test/browser-playwright` | Playwright integration | |
| 243 | +| `./test/plugins/*` | Plugin shims for pnpm overrides | |
| 244 | +| `./package.json` | Package metadata | |
| 245 | + |
| 246 | +See `package.json` for the complete list of exports. |
| 247 | + |
| 248 | +--- |
| 249 | + |
| 250 | +## Technical Reference |
| 251 | + |
| 252 | +### Build Flow |
| 253 | + |
| 254 | +``` |
| 255 | +1. buildCli() TypeScript compilation -> dist/*.js |
| 256 | +2. buildNapiBinding() Rust -> binding/*.node (per platform) |
| 257 | +3. syncTestPackageExports() Read test pkg exports -> dist/test/* |
| 258 | + ├── createShimForExport() Generate shim files |
| 259 | + ├── createConditionalShim() Handle import/require conditions |
| 260 | + └── updateCliPackageJson() Update exports in package.json |
| 261 | +``` |
| 262 | + |
| 263 | +### Key Constants |
| 264 | + |
| 265 | +```typescript |
| 266 | +// Test package name for re-exports |
| 267 | +const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test'; |
| 268 | +``` |
| 269 | + |
| 270 | +### Package.json Auto-Update |
| 271 | + |
| 272 | +The build script automatically updates `package.json`: |
| 273 | + |
| 274 | +1. Removes old `./test/*` exports |
| 275 | +2. Adds new exports from test package |
| 276 | +3. Ensures `dist/test` is in the `files` array |
| 277 | + |
| 278 | +This keeps the CLI package exports in sync with the test package without manual maintenance. |
0 commit comments