Skip to content

defineConfig always injects vite-plus:vitest-resolver into vp build / vp dev even when Vitest isn't used #2307

Open

Description

@cursor

Describe the bug

defineConfig from vite-plus always prepends Vitest-only plugins into every Vite config, including for vp build / vp dev:

  • vite-plus:vitest-resolver
  • vite-plus:auto-inline-matcher
  • vite-plus:coverage-version-guard

Projects that use Vite+ for toolchain (fmt / lint / build) but run tests with another runner (e.g. Bun's bun:test) still pay for these plugins on every production build.

Rolldown/Vite plugin timings report:

[PLUGIN_TIMINGS] Your build spent significant time in plugins. Here is a breakdown:
  - vite-plus:vitest-resolver (87%)

The resolver is an enforce: "pre" resolveId hook, so it runs on every module resolve. It early-returns for non-vitest / @vitest/* ids, but with a large graph that still dominates plugin time.

There is no documented opt-out. lazyPlugins only gates user plugins during config-metadata loads; it does not skip these injected plugins on build/dev. vite-plus/prefer-vite-plus-imports also pushes app configs to import defineConfig from vite-plus rather than vite, so switching away isn't a clean escape hatch.

Reproduction

  1. Use import { defineConfig } from "vite-plus" in an app vite.config.ts
  2. Do not configure or run vp test / Vitest
  3. Run vp build (with plugin timings enabled)
  4. Observe vite-plus:vitest-resolver near the top of [PLUGIN_TIMINGS]

Expected

Vitest helper plugins should only be injected when running tests (vp test / Vitest), or there should be an explicit opt-out for projects that don't use Vitest.

System Info

  • vite-plus: 0.2.5
  • Tests: Bun (bun:test), not Vitest
  • Apps build via vp build

Suggested fix

  • Gate injection on test command / presence of test config, or
  • Add a config flag such as test: false / vitest: false to skip injection, or
  • Document a supported way to opt out without fighting prefer-vite-plus-imports

Related

Activity

  1. SohelIslamImran commented on Aug 3, 2026

    @SohelIslamImran

    Follow-up: PLUGIN_TIMINGS % is misleading (measurements)

    We instrumented vite-plus:vitest-resolver during real vp build runs and A/B-stripped the injected vite-plus:* plugins. Absolute impact is much smaller than the warning suggests.

    Instrumentation (resolveId)

    App resolveId calls Vitest hits JS time inside hook
    portal 12,143 0 2.78 ms
    web 15,973 0 3.53 ms

    On build, the plugin only early-returns null — it never does useful Vitest resolution work.

    A/B wall-clock (portal, warm)

    Config built in Top PLUGIN_TIMINGS entry
    with vitest-resolver 11.21–11.28s vite-plus:vitest-resolver 87–90%
    stripped vite-plus:* plugins 11.42–11.95s @rolldown/plugin-babel ~81%

    Stripping the plugins did not speed up the build (noise / slightly slower). It only changed who owns the pie chart.

    Corrected framing

    • Not a meaningful build bottleneck for us (~3ms JS work; wall-clock unchanged).
    • The 87% figure is share of plugin time, inflated by many cheap async resolveId Rust↔JS calls next to a fast Rolldown core.
    • The remaining issue is still valid as a design / DX request:
      • Vitest helper plugins are injected for every defineConfig consumer on vp build / vp dev
      • That produces a noisy [PLUGIN_TIMINGS] warning even when Vitest isn’t used (and even when it is used — build still doesn’t need these hooks)
      • Prefer gating injection to vp test / Vitest, or documenting an opt-out

    Sorry for the initial overstatement of perf impact — happy to close if you consider the warning acceptable, but gating/opt-out would still remove false alarms for Bun/bun:test-only (and Vitest) users.

  2. fengmk2 commented on Aug 3, 2026

    @fengmk2
    Member

    @SohelIslamImran Can you provide a minimal reproduction repository?

  3. jasonkuhrt commented on Nov 11, 2026

    @jasonkuhrt

    Written by an AI agent (Claude) on behalf of @jasonkuhrt.

    #3434 gives the resolver a resolveId hook filter, so its handler runs only for vitest, vitest/*, @vitest/* and vite-plus/test ids. The plugin stays injected, so whether to inject it at all remains this issue's question.

    What it adds to the measurements above: the cost is the call into JavaScript, not the handler's body. The follow-up measured the body at 2.78 ms over 12,143 calls. On a generated graph that is all resolution, alternating the published 1.6.0 defineConfig and the filtered one, the build's median drops from 305 ms to 195 ms at 12,000 resolveId calls, about 110 ms, and from 1,927 ms to 1,364 ms at 40,000. That is about 9 to 14 µs per skipped call on that graph, so one or two tenths of a second for the 12,000 to 16,000 calls measured above, which fits that A/B finding no clear difference. The script is in the PR.

    On v1.6.0 [PLUGIN_TIMINGS] no longer names the resolver: Rolldown 1.2.18 times each callback inside JavaScript and lists one only from one second (source), and the follow-up above measured it at 2.78 ms and 3.53 ms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions