Skip to content

Vitest working with Nitro v2, but not with Nitro v3.0.1-alpha.0 #3659

Closed

Description

@theoludwig

Environment

npx --yes envinfo --system --binaries

  System:
    OS: Linux 6.17 Arch Linux
    Container: Yes
    Shell: 5.9 - /usr/bin/zsh
  Binaries:
    Node: 24.10.0
    npm: 11.6.2
    pnpm: 10.18.3

Reproduction

https://github.com/theoludwig/vite-nitro-issues

Unfortunately this is not a "as minimal as possible reproduction", but I thought it was still worth to open the issue as an early tester of Nitro v3 alpha version, and that it was working with v2. The provided reproduction is a TanStack Start application following their documentation about Nitro usage: https://tanstack.com/start/latest/docs/framework/react/guide/hosting#using-nitro-v2

I haven't had time to investigate the issue further yet.

Describe the bug

node --run test which is using vitest run doesn't work with Nitro v3, but works with Nitro v2.

I did 2 commits in the reproduction example:

  • chore: nitro v2 which use @tanstack/nitro-v2-vite-plugin and has a green CI, no problems.
  • chore: nitro v3, with as you can see in the commit, the only change, is that it's using "nitro": "3.0.1-alpha.0", and the CI doesn't work (same behavior as locally), and fails with vitest run.

Additional context

No response

Logs

info Using tsconfig paths for react-docgen

⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯
TypeError: Cannot read properties of undefined (reading 'onMessage')
    at Object.on (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/nitro@3.0.1-alpha.0_vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6_/node_modules/nitro/dist/_chunks/plugin.mjs:348:13)
    at Object.setInvokeHandler (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vite/dist/node/chunks/dep-B0GuR2De.js:28475:16)
    at new DevEnvironment (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vite/dist/node/chunks/dep-B0GuR2De.js:35006:12)
    at new FetchableDevEnvironment (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/nitro@3.0.1-alpha.0_vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6_/node_modules/nitro/dist/_chunks/plugin.mjs:318:5)
    at createFetchableDevEnvironment (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/nitro@3.0.1-alpha.0_vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6_/node_modules/nitro/dist/_chunks/plugin.mjs:313:10)
    at Object.createEnvironment (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/nitro@3.0.1-alpha.0_vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6_/node_modules/nitro/dist/_chunks/plugin.mjs:525:50)
    at _createServer (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vite@7.1.10_@types+node@24.7.2_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vite/dist/node/chunks/dep-B0GuR2De.js:27964:132)
    at async createViteServer (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vitest@3.2.4_@types+node@24.7.2_@vitest+browser@3.2.4_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vitest/dist/chunks/cli-api.BkDphVBG.js:6911:17)
    at async createVitest (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vitest@3.2.4_@types+node@24.7.2_@vitest+browser@3.2.4_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vitest/dist/chunks/cli-api.BkDphVBG.js:10202:17)
    at async prepareVitest (file:///home/runner/work/vite-nitro-issues/vite-nitro-issues/node_modules/.pnpm/vitest@3.2.4_@types+node@24.7.2_@vitest+browser@3.2.4_jiti@2.6.1_lightningcss@1.30.1_tsx@4.20.6/node_modules/vitest/dist/chunks/cli-api.BkDphVBG.js:10541:14)

Activity

  1. hi-ogawa commented on Oct 17, 2025

    @hi-ogawa
    Contributor

    For unit testing, server runtime is irrelevant, so nitro should be disabled. One quick way is to skip the plugin based on process.env.VITEST such as plugins: [!process.env.VITEST && nitro()]. Tanstack start's Nitro v2 plugin was essentially build only, so it didn't manifest any issues.

  2. added a commit that references this issue on Oct 18, 2025
  3. theoludwig commented on Oct 18, 2025

    @theoludwig
    Author

    For unit testing, server runtime is irrelevant, so nitro should be disabled. One quick way is to skip the plugin based on process.env.VITEST such as plugins: [!process.env.VITEST && nitro()]. Tanstack start's Nitro v2 plugin was essentially build only, so it didn't manifest any issues.

    Ah, okay, it makes sense, thanks for the reply.
    I tried it, and indeed it seems to work: theoludwig/vite-nitro-issues@8255b85

  4. reopened this on Oct 19, 2025
  5. pi0 commented on Oct 19, 2025

    @pi0
    Member

    reopening issue to try to make nitro plugin behavior smarter when running within tests.

  6. kricsleo commented on Oct 21, 2025

    @kricsleo
    Member

    behavior smarter when running within tests.

    Means Nitro could skip internally when detected running with tests? If that's it, I can help. 🙌

  7. theoludwig commented on Nov 10, 2025

    @theoludwig
    Author

    behavior smarter when running within tests.

    Means Nitro could skip internally when detected running with tests? If that's it, I can help. 🙌

    Is the above could be a solution? @pi0

    For now users, must have in their vite.config.ts the following:

    import { nitro } from "nitro/vite"
    import { defineConfig } from "vite"
    
    const IS_TEST = process.env["NODE_ENV"] === "test"
    
    export default defineConfig({
      plugins: [
        ...(!IS_TEST ? [nitro()] : []),
      ],
    })
  8. pi0 commented on Nov 10, 2025

    @pi0
    Member

    @theoludwig yes it is a good workaround.

    i am investigating first-class vitest support, nitro already can setup a good vitest runner enviornment small changes needed.

  9. hi-ogawa commented on Nov 11, 2025

    @hi-ogawa
    Contributor

    I also wonder whether completely disabling nitro plugin is good. For example, it might be nice if some nitro specific module convention (virtual module etc.) works inside Vitest.

    (For the context, for example, sveltekit plugin can work with Vitest and it allows $lib/.., $env etc. module convention.)

  10. pi0 commented on Nov 18, 2025

    @pi0
    Member

    /cc @juliusmarminge. You should disable plugin for test environment.

    Probably best we do it out of the box until vitest support lands.

  11. theoludwig commented on Nov 23, 2025

    @theoludwig
    Author

    When fixing this issue, it might also be worth to check support for Storybook as well: storybookjs/storybook#33010

  12. dlukt commented on Oct 1, 2026

    @dlukt

    Hi 👋 — adding another (distinct) manifestation of this issue with a full diagnosis, in case it helps pin the root cause.

    Environment

    • Node 24, Vite 8.3.1, Vitest 4.1.11
    • nitro 3.0.260903-beta, @tanstack/react-start 1.168.60, react 19.3.0
    • TanStack Start app using the nitro() vite plugin alongside tanstackStart()

    Symptom

    vitest run prints this on every run (tests still pass — it's console noise from the dev runner), plus the close timed out after 10000ms / hanging-process behavior from #4144:

    ReferenceError: module is not defined
        at .../node_modules/react/index.js:6:3
        at ESModulesEvaluator.runInlinedModule (.../vite/dist/node/module-runner.js:811:163)
        at ModuleRunner.directRequest (.../vite/dist/node/module-runner.js:1272:80)
    

    Bisected the plugin set: the error only appears when both nitro() and tanstackStart() are present — each one alone is clean.

    Mechanism (traced via instrumentation)

    1. Nitro's dev worker (dist/runtime/internal/vite/dev-worker.mjs) registers env runners — for this setup:
      • nitro → nitro/dist/runtime/internal/vite/dev-entry.mjs
      • ssr → @tanstack/react-start/dist/plugin/default-entry/server.ts
        and eagerly imports each entry (this.entry = await this.runner.import(this.entryPath)).
    2. The ssr entry graph is: server.ts → @tanstack/react-start/server → @tanstack/react-start-server → StartServer.js, whose first line is a bare import "react".
    3. react resolves to its raw CJS build (react/index.js). By the time the runner requests it, the specifier is a resolved file path, and vite's fetchModule() only takes the externalize branch for bare specifiers with an importer (url[0] !== "." && url[0] !== "/") — path-form URLs always go through transformRequest and get inlined. The ESModulesEvaluator then evaluates the CJS file as ESM → module is not defined. (resolve.external / ssr.external are never consulted for these fetches, so they can't intercept it.)
    4. Under vite dev this doesn't happen because react-start adds optimizeDeps.include: ["react", ...] for the server environments, so react is pre-bundled to ESM. Under vitest, react-start's needsOptimizeDeps is false (vitest sets optimizeDeps.noDiscovery = true), so no pre-bundle happens and the raw CJS file is what reaches the runner.
    5. The error is caught by the dev-worker reload path (console.error(error); this.entryError = error), which is why it only surfaces as noise and doesn't fail the run.

    So it looks like the intersection of: nitro v3's dev runner eagerly evaluating the SSR entry + react-start disabling deps optimization under vitest (see also TanStack/router#6074, which is the flip side — it fixes dual-react-instance hook errors by skipping optimizeDeps in VITEST).

    Reproduction

    A vite config with just:

    import { defineConfig } from 'vite'
    import { nitro } from 'nitro/vite'
    import { tanstackStart } from '@tanstack/react-start/plugin/vite'
    
    export default defineConfig({ plugins: [nitro(), tanstackStart()] })

    plus any passing test file, triggers it with vitest run. vite dev and vite build are both unaffected (dev serves SSR fine, no errors).

    Workaround

    Same as suggested in #4144 — skip the plugin under vitest:

    ...(process.env.VITEST ? [] : [nitro()]),

    Happy to provide a full standalone repro repo if useful. Thanks for the work on v3! 🙏

  13. pi0x commented on Oct 18, 2026

    @pi0x
    Contributor

    Vitest support landed in #4748, so the original report may be fixed on the latest beta. Could you check? The newer report above (CJS react inlined in the ssr env runner when using TanStack Start under Vitest) looks like a separate problem and might be easier to track in its own issue.

    Triaged with AI assistance.

  14. pi0 commented on Oct 18, 2026

    @pi0
    Member

    (vitest support in next release and currently on v3 nightly)

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions