Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSX runtime bundled incorrectly when running browser tests #7294

Open
6 tasks done
kayahr opened this issue Jan 19, 2025 · 2 comments
Open
6 tasks done

JSX runtime bundled incorrectly when running browser tests #7294

kayahr opened this issue Jan 19, 2025 · 2 comments
Labels
feat: browser Issues and PRs related to the browser runner p3-minor-bug An edge case that only affects very specific usage (priority)

Comments

@kayahr
Copy link

kayahr commented Jan 19, 2025

Describe the bug

I want to write a TypeScript web application which uses a JSX web frontend framework. JSX frameworks usually provide two entry-points, one for the framework as a library and one for the framework as a jsx-runtime which is referenced in the tsconfig.json like this:

"jsx": "react-jsx",
"jsxImportSource": "jsx-framework-of-the-day",

The JSX runtime is then automatically imported as jsx-framework-of-the-day/jsx-runtime. This cannot be changed but this should usually not be a problem because the JSX framework can simply point this export to the same script as the main export in the package.json:

"exports": {
    ".": "./lib/framework.js",
    "./jsx-runtime": "./lib/framework.js",
    "./jsx-dev-runtime": "./lib/framework.js"
},

All this works fine during runtime and also with Vite, but it doesn't work with Vitest unfortunately. Vitest bundles the JSX framework runtime into a different bundle, so types which are shared by the framework library and the JSX runtime are duplicated and instanceof checks are not working.

Reproduction

For reproduction I created a minimal useless JSX framework-of-the-day and a small demo using this framework. The NPM module of the framework is referenced as a tarball in the demo project because I don't want to publish it to the NPM registry. Just assume it would be a normal NPM dependency.

  1. Clone and prepare demo project:

     git clone [email protected]:kayahr/tsx-vitest-problem.git
     cd tsx-vitest-problem
     npm install
    
  2. Start the web application with npm start and open it in browser to validate that it works (Prints Works! on the page). This uses Vite without any custom config. So no problem with Vite itself.

  3. Run unit tests with npm test. They will fail because the component created by the JSX framework cannot be rendered by the render method of the frameworks main library because it does not recognize the type.

My dummy JSX framework prints a console message when it is imported, together with the import URL, and this demonstrates the actual problem:

stdout | unknown test
=== Imported jsx-framework-of-the-day from http://localhost:63315/node_modules/.vite/deps/chunk-GH264CMS.js?v=de5bdd42 ===
stdout | unknown test
=== Imported jsx-framework-of-the-day from http://localhost:63315/node_modules/.vite/deps/jsx-framework-of-the-day.js?v=27bca618 ===

This shows that vitest bundles the JSX framework twice, which breaks the framework.

EDIT: Sometimes the test may succeed by repeatedly running vitest. It breaks again when clearing the cache in node_modules/.vite.

System Info

System:
    OS: Linux 6.12 Debian GNU/Linux trixie/sid
    CPU: (32) x64 AMD Ryzen 9 7950X3D 16-Core Processor
    Memory: 40.72 GB / 62.51 GB
    Container: Yes
    Shell: 5.2.37 - /bin/bash
  Binaries:
    Node: 22.13.0 - /usr/bin/node
    Yarn: 1.22.22 - ~/.local/bin/yarn
    npm: 11.0.0 - ~/.local/bin/npm
    pnpm: 9.15.4 - ~/.local/bin/pnpm
  Browsers:
    Chrome: 132.0.6834.83
  npmPackages:
    @vitest/browser: 3.0.2 => 3.0.2 
    @vitest/coverage-v8: 3.0.2 => 3.0.2 
    vite: 6.0.7 => 6.0.7 
    vitest: 3.0.2 => 3.0.2

Used Package Manager

npm

Validations

@kayahr
Copy link
Author

kayahr commented Jan 19, 2025

Hm... Maybe I should have read the warning printed by Vitest:

5:41:38 PM [vite] (client) ✨ new dependencies optimized: jsx-framework-of-the-day/jsx-dev-runtime
5:41:38 PM [vite] (client) ✨ optimized dependencies changed. reloading

[vitest] Vite unexpectedly reloaded a test. This may cause tests to fail, lead to flaky behaviour or duplicated test runs.
For a stable experience, please add mentioned dependencies to your config's `optimizeDeps.include` field manually.

So I added this to the vitest config and the problem vanishes:

    optimizeDeps: {
        include: [
            "jsx-framework-of-the-day/jsx-runtime",
            "jsx-framework-of-the-day/jsx-dev-runtime"
        ]
    },

But it's not nice that every user of such a JSX framework has to do that. Maybe Vitest or Vite (no idea who is responsible) could detect used JSX runtimes automatically and add them to this optimization list?

@hi-ogawa hi-ogawa added p3-minor-bug An edge case that only affects very specific usage (priority) feat: browser Issues and PRs related to the browser runner and removed pending triage labels Jan 20, 2025
@hi-ogawa
Copy link
Contributor

hi-ogawa commented Jan 20, 2025

This is likely a Vite issue. If I remember correctly, Vite's deps optimizer doesn't check custom jsxImportSource in tsconfig, so it doesn't discover jsx-framework-of-the-day/jsx-dev-runtime on initial run. On Vite, such late discovery is not much noticeable for users, so I didn't end up making an issue there, but technically we probably want to fix it there if we need to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: browser Issues and PRs related to the browser runner p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
Development

No branches or pull requests

2 participants