Skip to content

Commit 861cc36

Browse files
authored
feat(cli): align vite exports with upstream vite package (#375)
Add missing exports to vite-plus CLI package to match vite's export map: - ./client (types only, ambient declarations) - ./module-runner - ./internal - ./dist/client/* - ./types/* - ./types/internal/* (blocked) This enables imports like: ```typescript import type { ImportGlobFunction } from '@voidzero-dev/vite-plus/types/importGlob.d.ts'; ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Aligns the CLI package’s export map with upstream Vite by generating shims that re-export from the core package and refining test shims. > > - Add `syncCorePackageExports()` to `build.ts` to create shims for `./client` (triple-slash types), `./module-runner`, `./internal`, `./dist/client/*` (JS), and `./types/*` (type-only `export type *`), with `./types/internal/*` blocked > - Require core build artifacts; mirror `dist/vite/client` and `dist/vite/types` into `dist/client` and `dist/types` > - Update `packages/cli/package.json` exports to include the new Vite-compatible subpaths and precedence (`./types/internal/*` before `./types/*`) > - Enhance test export shims to include side-effect imports in `.d.ts` to preserve augmentations; keep auto-sync of `./test/*` > - Expand `BUNDLING.md` to document the new 4-step build, export mapping, output structure, and rationale > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 714de68. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent c4d9a09 commit 861cc36

3 files changed

Lines changed: 321 additions & 27 deletions

File tree

packages/cli/BUNDLING.md

Lines changed: 148 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
# CLI Package Build Architecture
22

3-
This document explains how `@voidzero-dev/vite-plus` is built and how it re-exports the test package.
3+
This document explains how `@voidzero-dev/vite-plus` is built and how it re-exports from both the core and test packages to serve as a drop-in replacement for `vite`.
44

55
## Overview
66

7-
The CLI package uses a **3-step build process**:
7+
The CLI package uses a **4-step build process**:
88

99
1. **TypeScript Compilation** - Compile TypeScript source to JavaScript
1010
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/*`
11+
3. **Core Package Export Sync** - Re-export `@voidzero-dev/vite-plus-core` under `./client`, `./types/*`, etc.
12+
4. **Test Package Export Sync** - Re-export `@voidzero-dev/vite-plus-test` under `./test/*`
1213

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+
This architecture allows users to import everything from a single package (`@voidzero-dev/vite-plus`) as a drop-in replacement for `vite`, without needing to know about the separate core and test packages.
1415

1516
## Build Steps
1617

@@ -50,7 +51,39 @@ await cli.build({
5051

5152
The build generates platform-specific native binaries and formats the generated JavaScript wrapper with `oxfmt`.
5253

53-
### Step 3: Test Package Export Sync (`syncTestPackageExports`)
54+
### Step 3: Core Package Export Sync (`syncCorePackageExports`)
55+
56+
Creates shim files that re-export from `@voidzero-dev/vite-plus-core`, enabling this package to be a drop-in replacement for upstream `vite`. This is critical for compatibility with existing Vite plugins and configurations.
57+
58+
**Prerequisites**: The core package must be built first (its `dist/vite/` directory must exist).
59+
60+
**Export paths created**:
61+
62+
| Export Path | Type | Description |
63+
| -------------------- | ---------- | --------------------------------------------------------------------------------------- |
64+
| `./client` | Types only | Triple-slash reference for ambient type declarations (CSS modules, asset imports, etc.) |
65+
| `./module-runner` | JS + Types | Re-exports the Vite module runner for SSR/environments |
66+
| `./internal` | JS + Types | Re-exports internal Vite APIs |
67+
| `./dist/client/*` | JS | Client runtime files (`.mjs`, `.cjs`) |
68+
| `./types/*` | Types only | Type-only re-exports using `export type *` |
69+
| `./types/internal/*` | Blocked | Set to `null` to prevent access to internal types |
70+
71+
**Shim file examples**:
72+
73+
```typescript
74+
// dist/client.d.ts (triple-slash reference for ambient types)
75+
/// <reference types="@voidzero-dev/vite-plus-core/client" />
76+
77+
// dist/module-runner.js
78+
export * from '@voidzero-dev/vite-plus-core/module-runner';
79+
80+
// dist/types/importMeta.d.ts (type-only export)
81+
export type * from '@voidzero-dev/vite-plus-core/types/importMeta.d.ts';
82+
```
83+
84+
**Note on export ordering**: In `package.json`, the `./types/internal/*` export (set to `null`) must appear before `./types/*` for correct precedence. More specific patterns must precede wildcards.
85+
86+
### Step 4: Test Package Export Sync (`syncTestPackageExports`)
5487

5588
Reads the test package's exports and creates shim files that re-export everything under `./test/*`:
5689

@@ -74,6 +107,21 @@ packages/cli/
74107
│ ├── index.cjs # Main entry (CJS)
75108
│ ├── index.d.ts # Type declarations
76109
│ ├── bin.js # CLI entry point
110+
│ ├── client.d.ts # ./client types (triple-slash ref)
111+
│ ├── module-runner.js # ./module-runner shim
112+
│ ├── module-runner.d.ts
113+
│ ├── internal.js # ./internal shim
114+
│ ├── internal.d.ts
115+
│ ├── client/ # Synced client runtime files
116+
│ │ ├── client.mjs # ESM client shim
117+
│ │ ├── client.d.ts
118+
│ │ ├── env.mjs
119+
│ │ └── ...
120+
│ ├── types/ # Synced type definitions
121+
│ │ ├── importMeta.d.ts # Type shims (export type *)
122+
│ │ ├── importGlob.d.ts
123+
│ │ ├── customEvent.d.ts
124+
│ │ └── ...
77125
│ └── test/ # Synced test exports
78126
│ ├── index.js # Re-exports @voidzero-dev/vite-plus-test
79127
│ ├── index.cjs
@@ -113,6 +161,62 @@ These targets are defined in `package.json` under the `napi.targets` field.
113161

114162
---
115163

164+
## Core Package Export Sync Details
165+
166+
### Why Shim Files?
167+
168+
The CLI package creates thin shim files that re-export from `@voidzero-dev/vite-plus-core` rather than bundling the actual code. This approach:
169+
170+
1. **Enables drop-in replacement** - Users can replace `vite` with `@voidzero-dev/vite-plus` without changing imports
171+
2. **Keeps packages in sync** - No need to rebuild CLI when core package changes
172+
3. **Reduces duplication** - No file copying, just re-exports
173+
4. **Preserves module resolution** - Node.js resolves to the actual core package
174+
175+
### Export Mapping (Core)
176+
177+
| Upstream Vite Export | CLI Package Export | Description |
178+
| -------------------- | --------------------------------------- | ------------------------------------------ |
179+
| `vite/client` | `@voidzero-dev/vite-plus/client` | Ambient types for HMR, CSS modules, assets |
180+
| `vite/module-runner` | `@voidzero-dev/vite-plus/module-runner` | SSR/Environment module runner |
181+
| `vite/internal` | `@voidzero-dev/vite-plus/internal` | Internal APIs |
182+
| `vite/dist/client/*` | `@voidzero-dev/vite-plus/dist/client/*` | Client runtime files |
183+
| `vite/types/*` | `@voidzero-dev/vite-plus/types/*` | Type definitions |
184+
185+
### Type-Only Exports
186+
187+
For `./types/*` exports, shim files use `export type *` syntax (TypeScript 5.0+) to ensure only type information is re-exported:
188+
189+
```typescript
190+
// dist/types/importMeta.d.ts
191+
export type * from '@voidzero-dev/vite-plus-core/types/importMeta.d.ts';
192+
```
193+
194+
This is important because `./types/*` only exposes `.d.ts` files and should never include runtime code.
195+
196+
### Internal Types Blocking
197+
198+
The `./types/internal/*` export is set to `null` in package.json to block access to internal type definitions:
199+
200+
```json
201+
"./types/internal/*": null,
202+
"./types/*": { "types": "./dist/types/*" }
203+
```
204+
205+
The `syncTypesDir()` helper skips the top-level `internal` directory when creating shims, since access is blocked at the exports level.
206+
207+
### Client Types (Triple-Slash Reference)
208+
209+
The `./client` export uses a triple-slash reference instead of a regular export because Vite's `client.d.ts` contains ambient type declarations (for CSS modules, assets, etc.) that should be globally available:
210+
211+
```typescript
212+
// dist/client.d.ts
213+
/// <reference types="@voidzero-dev/vite-plus-core/client" />
214+
```
215+
216+
This allows TypeScript to pick up types like `import.meta.hot`, CSS module types, and asset imports without explicit imports.
217+
218+
---
219+
116220
## Test Package Export Sync Details
117221

118222
### Why Shim Files?
@@ -123,7 +227,7 @@ Instead of copying the actual dist files from the test package, we create thin s
123227
2. **Reduces duplication** - No file copying, just re-exports
124228
3. **Preserves module resolution** - Node.js resolves to the actual test package
125229

126-
### Export Mapping
230+
### Export Mapping (Test)
127231

128232
All test package exports are mapped under `./test/*`:
129233

@@ -186,9 +290,12 @@ module.exports = require('@voidzero-dev/vite-plus-test');
186290
**Type shim** (`dist/test/browser-playwright.d.ts`):
187291

188292
```typescript
293+
import '@voidzero-dev/vite-plus-test/browser-playwright';
189294
export * from '@voidzero-dev/vite-plus-test/browser-playwright';
190295
```
191296

297+
Note: Type shims include a side-effect import to preserve module augmentations (e.g., `toMatchSnapshot` on the `Assertion` interface).
298+
192299
---
193300

194301
## Build Dependencies
@@ -216,10 +323,10 @@ This sets `release: false` in the NAPI build options, producing larger but faste
216323
## Build Commands
217324

218325
```bash
219-
# Build the CLI package
326+
# Build the CLI package (requires core package to be built first)
220327
pnpm -C packages/cli build
221328

222-
# Build from monorepo root
329+
# Build from monorepo root (builds all dependencies first)
223330
pnpm build --filter @voidzero-dev/vite-plus
224331

225332
# Debug build
@@ -232,16 +339,21 @@ VITE_PLUS_CLI_DEBUG=1 pnpm -C packages/cli build
232339

233340
After building, the CLI package exports:
234341

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 |
342+
| Export Path | Description |
343+
| --------------------------- | ----------------------------------- |
344+
| `.` | Main entry (CLI utilities) |
345+
| `./client` | Client types (ambient declarations) |
346+
| `./module-runner` | Vite module runner for SSR |
347+
| `./internal` | Internal Vite APIs |
348+
| `./dist/client/*` | Client runtime files |
349+
| `./types/*` | Type definitions |
350+
| `./bin` | CLI binary entry point |
351+
| `./binding` | NAPI native binding |
352+
| `./test` | Test package main entry |
353+
| `./test/browser` | Browser testing utilities |
354+
| `./test/browser-playwright` | Playwright integration |
355+
| `./test/plugins/*` | Plugin shims for pnpm overrides |
356+
| `./package.json` | Package metadata |
245357

246358
See `package.json` for the complete list of exports.
247359

@@ -252,17 +364,26 @@ See `package.json` for the complete list of exports.
252364
### Build Flow
253365

254366
```
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
367+
1. buildCli() TypeScript compilation -> dist/*.js
368+
2. buildNapiBinding() Rust -> binding/*.node (per platform)
369+
3. syncCorePackageExports() Read core pkg dist -> dist/client/, dist/types/
370+
├── createClientShim() Triple-slash reference for ./client
371+
├── createModuleRunnerShim() JS + types for ./module-runner
372+
├── createInternalShim() JS + types for ./internal
373+
├── syncClientDir() Shims for ./dist/client/*
374+
└── syncTypesDir() Type-only shims for ./types/*
375+
4. syncTestPackageExports() Read test pkg exports -> dist/test/*
376+
├── createShimForExport() Generate shim files
377+
├── createConditionalShim() Handle import/require conditions
378+
└── updateCliPackageJson() Update exports in package.json
261379
```
262380

263381
### Key Constants
264382

265383
```typescript
384+
// Core package name for Vite compatibility exports
385+
const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core';
386+
266387
// Test package name for re-exports
267388
const TEST_PACKAGE_NAME = '@voidzero-dev/vite-plus-test';
268389
```
@@ -275,4 +396,6 @@ The build script automatically updates `package.json`:
275396
2. Adds new exports from test package
276397
3. Ensures `dist/test` is in the `files` array
277398

278-
This keeps the CLI package exports in sync with the test package without manual maintenance.
399+
Core package exports (`./client`, `./module-runner`, `./internal`, `./dist/client/*`, `./types/*`) are defined statically in `package.json` and not auto-generated, since they match upstream Vite's exports structure.
400+
401+
This keeps the CLI package exports in sync with both upstream Vite and the test package without manual maintenance.

0 commit comments

Comments
 (0)