Skip to content

Commit 4fd98a4

Browse files
committed
docs: update RFC to document wrapper package pattern and new install flows
1 parent f3bd656 commit 4fd98a4

1 file changed

Lines changed: 83 additions & 11 deletions

File tree

rfcs/merge-global-and-local-cli.md

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,62 @@ packages/cli/
5050
│ ├── create.js
5151
│ ├── migrate.js
5252
│ └── version.js
53-
├── install.sh / install.ps1 # Global install scripts (from global)
54-
├── templates/ # Project templates (from global)
55-
├── rules/ # Oxlint rules (from global)
53+
├── install.sh / install.ps1 # Global install scripts
54+
├── templates/ # Project templates
55+
├── rules/ # Oxlint rules
5656
├── snap-tests/ # Local CLI snap tests
57-
└── snap-tests-global/ # Global CLI snap tests (from global)
57+
└── snap-tests-global/ # Global CLI snap tests
5858
```
5959

60+
### Global Install Directory (`~/.vite-plus/`)
61+
62+
The global install directory uses a wrapper package pattern. Each version directory
63+
declares `vite-plus` as an npm dependency instead of extracting its internals directly.
64+
This decouples the `vp` binary from vite-plus's internal file layout.
65+
66+
```
67+
~/.vite-plus/
68+
├── bin/
69+
│ └── vp # Symlink to current/bin/vp
70+
├── current -> <version>/ # Symlink to active version
71+
├── <version>/
72+
│ ├── bin/
73+
│ │ └── vp # Rust binary (from platform package)
74+
│ ├── package.json # Wrapper: { "dependencies": { "vite-plus": "<version>" } }
75+
│ └── node_modules/
76+
│ ├── vite-plus/ # Installed as npm dependency
77+
│ │ ├── dist/bin.js # JS entry point (found by Rust binary)
78+
│ │ ├── dist/global/ # Bundled global commands
79+
│ │ ├── binding/ # NAPI loader
80+
│ │ ├── templates/ # Project templates
81+
│ │ ├── rules/ # Oxlint rules
82+
│ │ └── package.json # Real vite-plus package.json
83+
│ ├── @voidzero-dev/ # Platform package (via optionalDeps)
84+
│ │ └── vite-plus-<platform>/ # Contains .node NAPI binary
85+
│ └── [other transitive deps]
86+
├── env, env.fish, env.ps1 # Shell PATH configuration
87+
└── packages/ # Globally installed packages (vp install -g)
88+
```
89+
90+
**Install flows:**
91+
92+
- **Production** (`curl -fsSL https://viteplus.dev/install.sh | bash`):
93+
Downloads platform tarball (extracts only `vp` binary), generates wrapper `package.json`,
94+
runs `vp install --silent` which installs `vite-plus` + all transitive deps via npm.
95+
96+
- **Upgrade** (`vp upgrade`):
97+
Downloads platform tarball (binary only), generates wrapper `package.json`,
98+
runs `vp install --silent`. No main tarball download needed.
99+
100+
- **Local dev** (`pnpm bootstrap-cli`):
101+
Copies `vp` binary, generates wrapper `package.json`, symlinks
102+
`node_modules/vite-plus` to `packages/cli/` source with transitive deps
103+
symlinked from `packages/cli/node_modules/`.
104+
105+
- **CI** (`pnpm bootstrap-cli:ci --tgz <path>`):
106+
Copies `vp` binary, generates wrapper `package.json` with `file:` protocol
107+
refs to tgz files, runs `npm install`.
108+
60109
### Command Routing
61110

62111
The Rust `vp` binary (`crates/vite_global_cli/`) routes commands in two categories:
@@ -107,6 +156,19 @@ The Rust `vp` binary (`crates/vite_global_cli/`) routes commands in two categori
107156
- **Category A (Package Manager)**: `install`, `add`, `remove`, `update`, etc. — Handled directly in Rust
108157
- **Category B (JavaScript)**: All other commands (`build`, `test`, `lint`, `create`, `migrate`, `--version`, etc.) — Rust uses `oxc_resolver` to find the project's local `vite-plus/dist/bin.js` and runs it. Falls back to the global installation's `dist/bin.js` if no local installation exists. The unified `bin.ts` entry point then routes to either NAPI bindings (task commands) or rolldown-bundled modules in `dist/global/` (create, migrate, version).
109158

159+
### Global scripts_dir Resolution (Rust)
160+
161+
The `vp` binary auto-detects the JS scripts directory from its own location:
162+
163+
```rust
164+
// Auto-detect from binary location
165+
// ~/.vite-plus/<version>/bin/vp -> ~/.vite-plus/<version>/node_modules/vite-plus/dist/
166+
let exe_path = std::env::current_exe()?;
167+
let bin_dir = exe_path.parent()?; // ~/.vite-plus/<version>/bin/
168+
let version_dir = bin_dir.parent()?; // ~/.vite-plus/<version>/
169+
let scripts_dir = version_dir.join("node_modules").join("vite-plus").join("dist");
170+
```
171+
110172
### Local vite-plus Resolution (Rust)
111173

112174
```rust
@@ -160,33 +222,43 @@ if (command === 'create') {
160222
- Removed JS shim layer — no more `dist/index.js` intermediary
161223
- Updated all command entry points from `index.js` to `bin.js`
162224
- Changed `MAIN_PACKAGE_NAME` from `vite-plus-cli` to `vite-plus`
163-
- Added `binding/` to install entries for upgrade command
225+
- Scripts dir resolution: `version_dir/node_modules/vite-plus/dist/`
226+
227+
4. **Restructured global install directory** (`~/.vite-plus/<version>/`):
228+
- Wrapper `package.json` declares `vite-plus` as a dependency
229+
- `vite-plus` installed into `node_modules/` by npm (not extracted from tarball)
230+
- `.node` NAPI binaries installed via npm optionalDependencies (not manually copied)
231+
- Removed `extract_main_package()`, `strip_dev_dependencies()`, `MAIN_PACKAGE_ENTRIES`
232+
- Added `generate_wrapper_package_json()` for upgrade command
233+
- Simplified install scripts: only extract `vp` binary + generate wrapper
234+
- Simplified `install-global-cli.ts`: symlink-based local dev, wrapper-based CI
164235

165-
4. **Updated build system**:
236+
5. **Updated build system**:
166237
- Added `rolldown.config.ts` to bundle global CLI modules into `dist/global/`
167238
- `treeshake: false` required for dynamic imports
168239
- Plugin to fix binding import paths in rolldown output
169240
- Simplified root `package.json` build scripts (removed global package steps)
170241

171-
5. **Updated CI/CD**:
242+
6. **Updated CI/CD**:
172243
- Simplified `build-upstream` action (removed global package build steps)
173244
- Simplified `release.yml` (removed global package publish, now 3 packages instead of 4)
174-
- Bumped cache key from `v2` to `v3`
245+
- `get_cli_version()` reads from `node_modules/vite-plus/package.json`
175246

176-
6. **Removed `vite` bin alias** — Only `vp` binary entry remains
247+
7. **Removed `vite` bin alias** — Only `vp` binary entry remains
177248

178-
7. **Updated package.json**:
249+
8. **Updated package.json**:
179250
- Added runtime deps: `cross-spawn`, `picocolors`
180251
- Added devDeps from global: `semver`, `yaml`, `glob`, `minimatch`, `mri`, etc.
181252
- Added `snap-test-global` script
182253
- Added `files` entries: `AGENTS.md`, `rules`, `templates`
183254

184-
8. **Updated documentation**: `CLAUDE.md`, `CONTRIBUTING.md`
255+
9. **Updated documentation**: `CLAUDE.md`, `CONTRIBUTING.md`
185256

186257
## Verification
187258

188259
- `cargo test -p vite_global_cli` — Rust unit tests pass
189260
- `pnpm -F vite-plus snap-test-local` — Local CLI snap tests pass
190261
- `pnpm -F vite-plus snap-test-global` — Global CLI snap tests pass
191262
- `pnpm bootstrap-cli` — Full build and global install succeeds
263+
- `VITE_PLUS_VERSION=test bash packages/cli/install.sh` — Production install from npm works
192264
- Manual testing: `vp create`, `vp migrate`, `vp --version`, `vp build`, `vp test` all work

0 commit comments

Comments
 (0)