Skip to content

feat(cli): add oxlint rule to prefer vite-plus imports#1408

Merged
fengmk2 merged 53 commits into
voidzero-dev:mainfrom
Han5991:issue/1301-import-rule
May 16, 2026
Merged

feat(cli): add oxlint rule to prefer vite-plus imports#1408
fengmk2 merged 53 commits into
voidzero-dev:mainfrom
Han5991:issue/1301-import-rule

Conversation

@Han5991
Copy link
Copy Markdown
Contributor

@Han5991 Han5991 commented Apr 17, 2026

Summary

  • add a bundled Oxlint JS plugin rule that rewrites vite/vitest imports to vite-plus
  • enable the rule by default in generated and migrated lint config
  • cover the new wiring with unit tests and snapshot tests

Testing

  • pnpm exec tsc --noEmit --pretty false
  • pnpm exec tsc --ignoreConfig --noEmit --pretty false --module esnext --moduleResolution bundler --target es2022 --skipLibCheck packages/cli/snap-tests/lint-vite-plus-imports/vite.config.ts
  • local snap tests for command-init-inline-config and lint-vite-plus-imports

Closes #1301
Closes #1457

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 17, 2026

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit 7f1b389
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a0813539f1a4b000880572a

@Han5991 Han5991 force-pushed the issue/1301-import-rule branch from 1fe3184 to 3a43e6d Compare April 17, 2026 08:44
@Han5991 Han5991 marked this pull request as ready for review April 17, 2026 11:51
Comment thread packages/cli/src/oxlint-plugin.ts
Comment thread packages/cli/snap-tests/lint-vite-plus-imports/steps.json
@fengmk2
Copy link
Copy Markdown
Member

fengmk2 commented Apr 17, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7eceea6afe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/oxlint-plugin.ts Outdated
@fengmk2
Copy link
Copy Markdown
Member

fengmk2 commented Apr 17, 2026

Awesome, the import rewrite logic can be completely replaced with the oxlint plugin.

@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented Apr 17, 2026

Awesome, the import rewrite logic can be completely replaced with the oxlint plugin.

Makes sense. I focused this PR on the unsafe rewrite fix first, and I can move the remaining import rewrite logic into the oxlint plugin in a follow-up.

Comment thread packages/cli/src/oxlint-plugin.ts Outdated
Comment thread packages/cli/src/oxlint-plugin.ts Outdated
Comment thread packages/cli/src/oxlint-plugin.ts Outdated
Copy link
Copy Markdown
Contributor

@camc314 camc314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! but we should definitely use oxlint's types rather than handrolling it, it duplicates code, and might cause issues in future!

@Han5991 Han5991 force-pushed the issue/1301-import-rule branch from b757aaf to 57897c7 Compare April 21, 2026 11:17
@Han5991 Han5991 requested review from camc314 and fengmk2 April 21, 2026 11:18
Comment thread packages/cli/src/oxlint-plugin.ts Outdated
@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented Apr 21, 2026

@fengmk2

The failure appears to come from a version skew in the global snap test.

In this test, vp create and vp check are executed by the locally built Vite+ CLI under test. However, after vp install, the generated application installs vite-plus@latest from the npm registry into its own node_modules.

The local CLI generates a lint config that references vite-plus/oxlint-plugin. When oxlint loads that config, it resolves vite-plus/oxlint-plugin from the generated application's node_modules, not from the local CLI package.

That means oxlint sees the registry-installed vite-plus@latest. That published package does not currently expose the new ./oxlint-plugin subpath, so resolution fails.

This also explains why the other vite-plus/* imports appear to work: those subpaths already exist in the published package, while vite-plus/oxlint-plugin only exists in the local build being tested.

@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented Apr 21, 2026

I think there are three possible ways to address this.

  1. Install the local Vite+ artifact in the generated app

The failure is caused by mixing the locally built CLI under test with vite-plus@latest from the registry. We could make the generated app install the same local Vite+ artifact set as the CLI under test, for example via a packed local tarball.

This avoids the version skew and keeps the test focused on the current build. A packed tarball seems better than link: because it is closer to a real package install and still verifies the published package shape, including package.json#exports.

  1. Resolve the built-in oxlint plugin from the CLI package

Another option is to make vp check resolve Vite+’s built-in oxlint plugin from the CLI package itself before passing the lint config to oxlint.

That would keep the generated app’s registry-installed dependencies intact, but it changes production resolution behavior. I would be careful with this because it may be harder to justify unless built-in Vite+ plugins are explicitly meant to be provided by the running CLI rather than by the project’s installed vite-plus.

  1. Treat this as a registry/local version skew exposed by the snap

We could also leave the test behavior as-is and consider the failure expected until the package containing ./oxlint-plugin is published.

This is the most conservative option, but it means the global snap test can fail whenever the local CLI starts generating config that depends on an unreleased vite-plus subpath.

@Han5991 Han5991 requested a review from camc314 April 21, 2026 23:50
@fengmk2 fengmk2 mentioned this pull request Apr 23, 2026
3 tasks
@Han5991 Han5991 force-pushed the issue/1301-import-rule branch from 7930f65 to 7ab5df7 Compare April 23, 2026 10:19
@Han5991 Han5991 force-pushed the issue/1301-import-rule branch from 359fd37 to 273e4fb Compare April 24, 2026 01:34
@Han5991 Han5991 marked this pull request as draft April 24, 2026 04:52
@Han5991 Han5991 marked this pull request as ready for review April 24, 2026 05:01
Comment thread packages/tools/src/snap-test.ts
@Han5991 Han5991 force-pushed the issue/1301-import-rule branch from d38d6fc to b6ef1e7 Compare April 24, 2026 13:56
@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented Apr 29, 2026

@fengmk2 @camc314

Started splitting plugin verification into a dedicated CI workflow and hit a tradeoff:

  • migration-* snaps don't run vp lint; the diff is just captured lint-config output. Removing the override infra → still pass.
  • create-framework-shim-astro / vue run vp install + vp check, which actually resolves vite-plus/oxlint-plugin. They only pass today because checkout-packages.json swaps vite-plus for the local pack. Drop that override and they fail until a vite-plus version exposing ./oxlint-plugin is on npm.

Options:

  1. Drop the lint step from framework-shim snaps; rely on the new CI for plugin behavior.
  2. Gate auto-injection of the plugin into generated configs until the export is published.
  3. Keep a minimal vite-plus → local-pack override; new CI on top.
  4. Land this PR after publishing vite-plus with ./oxlint-plugin, then drop the override entirely.

I'd lean (1). Which do you prefer?

@Han5991 Han5991 requested a review from fengmk2 May 8, 2026 12:56
@fengmk2 fengmk2 added test: e2e Auto run e2e tests test: create-e2e Run `vp create` e2e tests labels May 9, 2026
Comment thread pnpm-workspace.yaml
Comment thread packages/tools/src/snap-test.ts
Comment thread packages/tools/src/snap-test.ts
Comment thread packages/cli/src/oxlint-plugin.ts Outdated
Copy link
Copy Markdown
Contributor

@camc314 camc314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - the plugin code all looks good to me.

As for the testing infra/bundling. @fengmk2 is probably best placed to review.

Thanks!

fengmk2 and others added 2 commits May 16, 2026 09:45
…ate literal checks

Simplified code by removing the unused `isStringLiteralLike` helper function and improving type safety in literal handling logic.
@fengmk2 fengmk2 self-assigned this May 16, 2026
@fengmk2
Copy link
Copy Markdown
Member

fengmk2 commented May 16, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a5d9dfac9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/migration/migrator.ts
Comment thread packages/cli/src/oxlint-plugin-config.ts
Comment thread packages/cli/src/migration/migrator.ts
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 16, 2026

Open in StackBlitz

vite-plus

npm i https://pkg.pr.new/voidzero-dev/vite-plus@1408

@voidzero-dev/vite-plus-core

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-core@1408

@voidzero-dev/vite-plus-prompts

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-prompts@1408

@voidzero-dev/vite-plus-test

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-test@1408

@voidzero-dev/vite-plus-cli-darwin-arm64

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-darwin-arm64@1408

@voidzero-dev/vite-plus-cli-darwin-x64

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-darwin-x64@1408

@voidzero-dev/vite-plus-cli-linux-arm64-gnu

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-linux-arm64-gnu@1408

@voidzero-dev/vite-plus-cli-linux-arm64-musl

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-linux-arm64-musl@1408

@voidzero-dev/vite-plus-cli-linux-x64-gnu

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-linux-x64-gnu@1408

@voidzero-dev/vite-plus-cli-linux-x64-musl

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-linux-x64-musl@1408

@voidzero-dev/vite-plus-cli-win32-arm64-msvc

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-win32-arm64-msvc@1408

@voidzero-dev/vite-plus-cli-win32-x64-msvc

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-cli-win32-x64-msvc@1408

@voidzero-dev/vite-plus-darwin-arm64

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-darwin-arm64@1408

@voidzero-dev/vite-plus-darwin-x64

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-darwin-x64@1408

@voidzero-dev/vite-plus-linux-arm64-gnu

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-linux-arm64-gnu@1408

@voidzero-dev/vite-plus-linux-arm64-musl

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-linux-arm64-musl@1408

@voidzero-dev/vite-plus-linux-x64-gnu

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-linux-x64-gnu@1408

@voidzero-dev/vite-plus-linux-x64-musl

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-linux-x64-musl@1408

@voidzero-dev/vite-plus-win32-arm64-msvc

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-win32-arm64-msvc@1408

@voidzero-dev/vite-plus-win32-x64-msvc

npm i https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-win32-x64-msvc@1408

commit: 3a5d9df

@fengmk2
Copy link
Copy Markdown
Member

fengmk2 commented May 16, 2026

@Han5991 The VSCode extension is working normally, thank you for your contribution! Great job!

Screen.Recording.2026-05-16.at.13.15.05.mov
image

@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented May 16, 2026

@Han5991 The VSCode extension is working normally, thank you for your contribution! Great job!

Screen.Recording.2026-05-16.at.13.15.05.mov
image

Wow, it's working really well! That's awesome!

@Han5991
Copy link
Copy Markdown
Contributor Author

Han5991 commented May 16, 2026

@fengmk2

It seems like the CI failure is unrelated to the current PR. What should I do?

@fengmk2
Copy link
Copy Markdown
Member

fengmk2 commented May 16, 2026

@fengmk2

It seems like the CI failure is unrelated to the current PR. What should I do?

Similar to the problem with musl, you can skip it first.

Add musl-based platform exclusion to align with existing snap-test skips for NAPI conflicts.
@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​oxlint/​plugins@​1.61.0781009994100

View full report

@fengmk2 fengmk2 changed the title feat(cli): enforce vite-plus import lint rule feat(cli): add oxlint rule to prefer vite-plus imports May 16, 2026
@fengmk2 fengmk2 merged commit 99d3e41 into voidzero-dev:main May 16, 2026
93 checks passed
@Han5991 Han5991 deleted the issue/1301-import-rule branch May 16, 2026 08:48
fengmk2 added a commit that referenced this pull request May 19, 2026
Release vite-plus v0.1.22: Security Patch, Parallel Global Install & Scaffold Polish

A critical Vitest browser-mode security fix, parallel `vp add -g`
installs, a built-in oxlint rule to prefer `vite-plus` imports, and a
new `--git` switch for `vp create`.

### Highlights

- **Security**: bundled `vitest` bumped to `4.1.6` to address
[GHSA-2h32-95rg-cppp](GHSA-2h32-95rg-cppp)
(Critical, CVSS 9.6), an XSS to RCE chain via the `otelCarrier` query
parameter in Vitest browser mode
([#1633](#1633))
- **Parallel global install**: `vp add/install/update -g` now installs
packages concurrently with a progress bar and a `--concurrency` flag
(default 5)
([#1597](#1597))
- **Prefer vite-plus imports**: new bundled oxlint rule rewrites
`vite`/`vitest` imports to `vite-plus`, enabled by default in generated
and migrated `lint` configs
([#1408](#1408))
- **Git init on scaffold**: `vp create` learns `--git`/`--no-git`
(interactive prompt; auto-commits "Initial commit from Vite+")
([#1484](#1484))

### Features

- Spawn npm for global installation in parallel with a progress bar and
a `--concurrency` option
([#1597](#1597)), by
@liangmiQwQ
- Add bundled oxlint rule to prefer `vite-plus` imports over
`vite`/`vitest`
([#1408](#1408)), by
@Han5991
- `vp create`: initialize a git repository and create an initial commit
on scaffold
([#1484](#1484)), by
@ryohidaka
- `vp create`: rename underscore-prefixed files (`_gitignore`, `_npmrc`,
`_yarnrc.yml`) to dotfiles for `@org/create` bundled templates
([#1574](#1574)), by
@jong-kyung
- Add `VP_PR_VERSION` env var to install unreleased PR builds via
pkg.pr.new
([#1578](#1578)), by
@fengmk2

### Fixes & Enhancements

- Skip merging standalone `.oxfmtrc`/`.oxlintrc` config when the
`fmt:`/`lint:` key is already declared in `vite.config.ts` (fixes
duplicate-block regression in `vp create fate`)
([#1601](#1601)), by
@fengmk2
- Suppress the `VITE+ - The Unified Toolchain for the Web` banner for
`vp lint --lsp`, `vp fmt --lsp`, and `vp fmt --stdin-filepath` so stdout
stays a pure LSP / formatter stream
([#1619](#1619)), by
@fengmk2
- `vp create`: detect output directory when running in the current
directory
([#1606](#1606)), by
@jong-kyung
- `vp update -g`: skip installs when the recorded global package version
already matches the npm-resolved version, and tolerate string/array
outputs from `npm view ... version --json`
([#1596](#1596)), by
@leno23
- `vp create`: preserve single-segment project path in
`updateWorkspaceConfig`
([#1582](#1582)), by
@jong-kyung
- `vp env use`: keep the change session-scoped on Windows
([#1577](#1577)), by
@fengmk2
- `vp rebuild`: accept positional package names
([#1564](#1564)), by
@fengmk2
- Adopt the new vite-task error formatter; errors now print as `error:
<top-level>` plus `* <source>` chain lines, with bold-red highlight on a
TTY
([vite-task#390](voidzero-dev/vite-task#390)),
by @branchseer
- vite-task: forward `LOCALAPPDATA` so Node's compile cache stays
outside the workspace on Windows
([vite-task#389](voidzero-dev/vite-task#389)),
by @branchseer
- Bump vite-task to `c945cc0`
([#1628](#1628)), by
@branchseer

### Refactor

- Revert `vp pm plugin` command (per discussion in #1038)
([#1623](#1623)), by
@jong-kyung

### Docs

- Add `vitepress-plugin-llms` to the docs site so the published docs
include LLM-friendly outputs (`/llms.txt`)
([#1625](#1625)), by
@jong-kyung
- Refresh home stats for oxlint, vite, and vitest
([#1512](#1512)), by
@nozomee
- Mention `vp env doctor` in agent instructions
([#1603](#1603)), by
@leno23

### Chore

- Consolidate the upstream build chain into a single `pnpm build` script
(justfile recipe now just calls `pnpm build`)
([#1626](#1626)), by
@fengmk2
- Fix bootstrap-cli on Windows
([#1583](#1583)), by
@fengmk2
- Refresh trusted stack stats
([#1573](#1573),
[#1616](#1616)), by
@voidzero-guard[bot]
- Update GitHub Actions
([#1611](#1611),
[#1612](#1612)), by
@renovate[bot]
- Address zizmor findings in composite actions and the release workflow;
drop unused `actions-cool/issues-helper`
([#1630](#1630)), by
@Boshen
- Switch plain checkouts to `taiki-e/checkout-action`
([#1620](#1620)), by
@Boshen
- Switch release to a version-bump PR + push trigger flow
([#1575](#1575)), by
@Boshen
- Gate release publish on environment approval with a Discord notice
([#1571](#1571)), by
@Boshen
- Enable `cargo clippy` with `-D warnings`
([#1579](#1579)), by
@Boshen
- Drop unused `setup-node` from the version-check job
([#1600](#1600)), by
@fengmk2
- Add Void deploy workflows for the docs site
([#1590](#1590)), by
@fengmk2
- Add `--help` case to config snap tests for npm10/yarn1/yarn4
([#1585](#1585)), by
@jong-kyung
- Add `--help` case to publish snap tests for npm10/yarn1/yarn4
([#1584](#1584)), by
@jong-kyung
- Verify `.gitignore` and `.yarnrc.yml` in the new-vite-monorepo snap
([#1576](#1576)), by
@jong-kyung
- vite-task: bump pnpm to `11.1.2`
([vite-task#383](voidzero-dev/vite-task#383)),
by @branchseer
- vite-task: update lint-staged to v17
([vite-task#385](voidzero-dev/vite-task#385)),
by @renovate[bot]

### Bundled Versions

| Tool | Version | Source |
| --- | --- | --- |
| vite | `8.0.11` |
[`66f3194`](vitejs/vite@66f3194)
|
| rolldown | `1.0.0` |
[`ac5c710`](rolldown/rolldown@ac5c710)
|
| tsdown | `0.22.0` | [npm](https://npmx.dev/package/tsdown/v/0.22.0) |
| vitest | `4.1.6` | [npm](https://npmx.dev/package/vitest/v/4.1.6) |
| oxlint | `1.63.0` | [npm](https://npmx.dev/package/oxlint/v/1.63.0) |
| oxlint-tsgolint | `0.22.1` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/0.22.1) |
| oxfmt | `0.48.0` | [npm](https://npmx.dev/package/oxfmt/v/0.48.0) |

### New Contributors

Welcome to all new contributors! 🎉

@nozomee, @ryohidaka, @leno23

**Full Changelog**:
v0.1.21...v0.1.22

---

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg.pr.new test: create-e2e Run `vp create` e2e tests test: e2e Auto run e2e tests

Projects

None yet

3 participants