feat: detect Vite+ projects and launch vp lint/fmt --lsp (POC)#199
Draft
fengmk2 wants to merge 4 commits into
Draft
feat: detect Vite+ projects and launch vp lint/fmt --lsp (POC)#199fengmk2 wants to merge 4 commits into
vp lint/fmt --lsp (POC)#199fengmk2 wants to merge 4 commits into
Conversation
POC of the editor-extension detection rule from the Vite+ RFC voidzero-dev/vite-plus#1614. Today oxc-zed implicitly relies on vite-plus's `bin/oxlint` / `bin/oxfmt` wrappers (launched via `node_modules/vite-plus/bin/oxlint --lsp`); those wrappers are removed by vite-plus#1557, which would break the extension. This replaces the implicit handoff with explicit Vite+ detection ported into Rust. - src/vite_plus.rs: portable Phase 1-3 detector behind a `FileSystem` trait, host-testable; unit tests cover all 10 RFC conformance fixtures plus edge cases. - src/lsp.rs: `WorktreeFs` adapter backing the detector with Zed's `Worktree`; oxlint/oxfmt launch `vp lint --lsp` / `vp fmt --lsp` when Vite+ is runnable, and fall back to plain oxlint/oxfmt otherwise. The detector targets `node_modules/vite-plus/bin/vp` validated by `name === "vite-plus"`. Phase 3 (`$PATH` lookup) is implemented via `Worktree::which`, contrary to the RFC's note that it is unimplementable in Zed.
…ble) Discovered while preparing the live smoke test: zed#10760 (closed as not planned) confirms `Worktree::read_text_file` on `node_modules` "works sometimes but mostly doesn't" and `Path::exists` doesn't work in the WASM sandbox. The shipping extension already sidesteps this by reading only the root `package.json` and constructing-and-trusting the `node_modules/...` binary path. So read-verifying `node_modules/vite-plus/bin/vp` (and validating its package.json `name`) — which the RFC's core rule calls for — is not reliably implementable in Zed and would mostly yield false "declared but not installed" results for real installs. - Add `FileSystem::can_read_node_modules()` (default true). - When false (Zed), Phase 2 trusts the conventional vp path at the declaring directory instead of probing; a missing install surfaces as a spawn-time error, the RFC's anticipated upgrade-hint trigger. - `WorktreeFs` returns false; the read-verify path stays for the portable algorithm and conformance tests.
Author
✅ Live smoke test in Zed 1.4.4 (dev extension)Installed this branch as a dev extension and opened two projects. Vite+ project ( → Detected Vite+ and launched Non-Vite+ project (the oxc-zed repo itself) — same log: → No Zed also compiled the extension cleanly through its own build pipeline ( |
The RFC's Phase 3 (a global `vp` on $PATH) is implementable in Zed
(`Worktree::which` exists) but can't actually rescue a missing install:
a real project's `vite.config.ts` imports `vite-plus`, so a global `vp`
dies with UNRESOLVED_IMPORT regardless of binary source. Drop it; the
detector is now purely Phases 1-2 (detect declaration -> resolve a
project-scoped `vp`).
- Remove `FileSystem::which`, the Phase 3 block, `WorktreeFs::which`,
and the test scaffolding (`path_vp` / `vp_on_path` / `which` impl).
- Remove the two tests that only exercised the fallback; a missing
install now uniformly yields `{ root, vp_path: None }` (install hint).
- README: in a Vite+ project the LSP is `vp lint/fmt --lsp`, which resolves config from the Vite config, so `configPath` (oxlint) and `fmt.configPath` (oxfmt) are ignored; other LSP settings still apply. - examples/both: comment the two ignored config-path settings. - Replace em dashes in doc comments with commas/colons/parentheses.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
POC of the editor-extension detection rule from the Vite+ RFC voidzero-dev/vite-plus#1614 ("Vite+ Project Detection for Editor Extensions").
Why
Today oxc-zed implicitly relies on vite-plus's per-package
bin/oxlint/bin/oxfmtwrappers: when a project declaresvite-plus,lsp.rslaunchesnode node_modules/vite-plus/bin/oxlint --lsp. vite-plus#1557 removes those wrappers, which breaks the current extension. The RFC's fix: each editor explicitly detects a Vite+ project and launchesvp lint --lsp/vp fmt --lspinstead.How
src/vite_plus.rs: the RFC algorithm ported to Rust behind a smallFileSystemtrait so the core logic is host-testable. Unit tests cover the RFC conformance fixtures plus edge cases. 13 tests, all green.package.jsonthat directly declaresvite-plus, bounded by the root workspace.node_modules/vite-plus/bin/vp(Zed targets the real launcher, not the pnpm.bin/vpshell shim).vpon$PATH) is deliberately not implemented, see finding 2.src/lsp.rs: aWorktreeFsadapter backs theFileSystemtrait with Zed'sWorktree.oxlint/oxfmtlaunchvp <lint|fmt> --lspwhen Vite+ is detected, and fall back to plainoxlint/oxfmtotherwise.Findings for the RFC
node_modulesreads are unreliable in Zed, the RFC's Phase 2 "validate against a realvite-pluspackage (name === "vite-plus")" is not portable to Zed. zed#10760 (closed not planned) confirmsWorktree::read_text_fileonnode_modules"works sometimes but mostly doesn't," andPath::existsdoesn't work in the WASM sandbox. The shipping extension already sidesteps this by reading only the rootpackage.jsonand constructing-and-trusting the binary path. So this POC trustsnode_modules/vite-plus/bin/vprather than read-verifying it; a missing install surfaces as a clearCannot find module …/vite-plus/bin/vp("runpnpm install").$PATHnor a process-spawn capability," butWorktree::which/shell_envhave existed since WIT v0.0.1, so a$PATHlookup does work. However, live testing showed it can't actually help: a real project'svite.config.tsimportsvite-plus, so with no local installvp(global or not) dies withUNRESOLVED_IMPORT; a missingnode_modulesbreaksvpregardless of binary source. So this POC deliberately uses a local-only design with no global fallback (thewhichlookup was prototyped, then removed).Worktree::read_text_fileis confined to the worktree, so Phase 1 cannot read aboveworktree.root_path(). Opening a monorepo root where only a subpackage declaresvite-plusreturnsnull, the single-root gap the RFC already acknowledges for Zed. Captured byzed_worktree_root_misses_subpackage_declaration.Verification
cargo fmt --check,cargo check --all-targets,cargo test(13/13),cargo clippy -D warnings,cargo doc -D warnings, andcargo build --release --target wasm32-wasip2all pass.Live smoke test in Zed 1.4.4 (dev extension): verified against a real vite-plus project (
node-modules/urllib), Zed's LSP log showsnode …/urllib/node_modules/vite-plus/bin/vp lint --lspand… fmt --lsp, with the servers running. A non-Vite+ project launches plainoxfmt --lsp. Deletingnode_modulesproduces the expectedCannot find module …/vite-plus/bin/vp(vp needs the install regardless, see finding 2).Open / out of scope
vpsurfaces at spawn time instead.