qwik: [🐞] Duplicate implementations of JSXNode Errors in RC, v0.103

Which component is affected?

Qwik Runtime

Describe the bug

I’m getting QWIK WARN Duplicate implementations of "JSXNode" found warnings when using Qwik Styled Vanilla Extract.

This happens with RC1 Starter, following Integration Docs. Please see Loom Example, if needed.

Also, with v1.0 around the corner, there are open PRs and Issues with styled-vanilla-extract that should get a little love since it’s listed in the official documentation integrations section.

Cc: @manucorporat, @wmertens

Reproduction

https://www.loom.com/share/9eab1daa92f0431d848f35ea67899258

Steps to reproduce

pnpm create qwik@latest
pnpm qwik add styled-vanilla-extract
pnpm dev

System Info

System:
    OS: macOS 13.3.1
    CPU: (8) arm64 Apple M1
    Memory: 65.23 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.0.0 - ~/.nvm/versions/node/v20.0.0/bin/node
    npm: 8.19.2 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 112.0.5615.137
    Firefox Developer Edition: 111.0
    Safari: 16.4
  npmPackages:
    @builder.io/qwik: 0.103.0 => 0.103.0
    @builder.io/qwik-city: ~0.103.0 => 0.103.0
    undici: 5.21.2 => 5.21.2
    vite: 4.2.2 => 4.2.2

Additional Information

No response

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 3
  • Comments: 31 (16 by maintainers)

Commits related to this issue

Most upvoted comments

Hi! I have seen the workaround commited from @kisaragi-hiu referencing this issue but it removes completely all errors thrown to the shell.

As a temporal workaround to avoid the noise caused using @qwikest/icons with all these warnings in console, I’m using the following script on top of the entry.ssr.tsx. By this way we don’t loose other console outputs. I hope it helps you @hbendev 😃

// entry.ssr.tsx
import { isDev } from '@builder.io/qwik/build'

if (isDev) {
  const consoleWarn = console.warn
  const SUPPRESSED_WARNINGS = ['Duplicate implementations of "JSXNode" found']

  console.warn = function filterWarnings (msg, ...args) {
    if (!SUPPRESSED_WARNINGS.some(entry => msg.includes(entry) || args.some(arg => arg.includes(entry))))
      consoleWarn(msg, ...args)
  }
}

I’ve come across this issue in v1.1.1 and v1.0.0. when using the library @qwikest/icons

The warning is still there when using @qwikest/icons 0.0.8 together with qwik 1.1.0 or qwik 1.1.4 and using import { HiXY } from "@qwikest/icons/heroicons".

I’d like to add that it seems like the error is harmless in the case of the icons package, but it can lead to actual things not working, see #4436

I very strongly second this, the only reasons the icons package is working, is that I’m not using any component$ inside there, but instead use regular function components / lite components. Otherwise the package would break during server side rendering afaik.

If I’d need to guess, the reason seems to be connected to the multiple entrypoints. Probably qwik is only perprocessing specfic entrypoints?

Ok I solved it.

This is what happens:

  • the qwikVite plugin forces bundling of Qwik
  • vanilla-extract generates an import from an external which doesn’t get bundled
  • but it contains an import of qwik
  • so then it will have a duplicate entry of qwik
  • duplicate spidermen pointing.jpeg
  • …and this is already thought of! In that same line, it includes vendorIds
  • …they are found by checking all the dependencies for package.json files that have qwik as a key!

So by having a key “qwik” at the root of your package.json, it will be bundled into the ssr build, which fixes the duplicate jsxnode.

This is somewhat documented, so it’s a matter of making it more clear.

Ideally, the node_modules qwik is somehow poisoned with an error so that it can be caught and corrected easily.

I do think it’s a bit confusing to have the "qwik" property be required and it not seemingly doing anything. It’s also not documented what it needs to point to - what if you have multiple entry points for qwik code?

So @NiklasPor add the “qwik” attribute to your package.

@mhevery @manucorporat what should the “qwik” attribute point at, exactly? And how to make it easier to discover that “.qwik.js” wasn’t generated or that the “qwik” attribute is missing?

I figured it out. In the repro above I added console.log(new Error('loading qwik [prod] [mjs|cjs]')) in the node_modules qwik core files, and indeed qwik gets loaded multiple times.

What happens is: Vanilla-extract runs the css.ts files at build time and generates a file that imports styled-vanilla-extract/qwik-styled which in turn imports qwik. https://github.com/wmertens/styled-vanilla-extract/blob/4f03da0fc8d53d2f6bd19a52e523c4c7f30571ee/src/ve-style.ts#L44

This generated import doesn’t get bundled by vite. You can see it at the top of server/entry.preview.mjs:

import { styled } from "styled-vanilla-extract/qwik-styled";

I added the vite inspect plugin to the repro so you can see all the transforms. Everything seems correct, but the dev build does import core.prod.mjs even though I can’t find what imports it.

For dev mode, I assume the same thing is happening.


So the problem is either:

  • vite is bundling qwik into the server entry, or
  • vite is not bundling styled-vanilla-extract as well

I think it would be safer if the server build did not bundle qwik

FYI @n8sabes , I’ve managed to “fix” this by merging all my original entry points into a single one. But after this the qwik compiler is too heavy for my machine and the build fails because it runs out of heap (~about 24k qwik components)

@wmertens Seems like my local testing everything went fine with this, can’t believe that this small thing made the change 🤯 I’ll check if it works with the community, thanks a lot ❤️ 0.0.9 of @qwikest/icons includes the change, I’m just pointing to an empty entrypoint 😆

Always happy to help, I’d love it when we get the packages to work without problems – kinda important for the ecosystem 😁

@mhevery I posted a repro in #4436, https://stackblitz.com/edit/qwik-starter-wadzsa?file=src/routes/index.tsx

it happens in dev mode too, and it breaks in production. Qwik is definitely packaged only once. The error indicates that the JSXNodeImpl class is instantiated twice, but I can’t figure out how.

I’m pretty sure this happens, because you also use multiple named exports in the package.json. With @qwikest/icons I did not get any issues when I merged all code behind a single default export (sadly this wasn’t an option for the package).

Maybe there’s something hardcoded in Qwik which looks exactly for an entrypoint . like mentioned in the qwik lib docs?

    ".": {
      "import": "./lib/index.qwik.mjs",
      "require": "./lib/index.qwik.cjs",
      "types": "./lib-types/index.d.ts"
    }

The docs also impose some restrictions on how the file must be named:

The file must be called with the .qwik.mjs extension, otherwise the Qwik Optimizer will not recognize it.

In styled-vanilla-extract it looks like this:

    "./qwik": {
      "import": "./lib/index.js",
      "require": "./lib/index.cjs",
      "types": "./lib-types/index.d.ts"
    },
    "./vite": {
      "import": "./lib/vite.js",
      "require": "./lib/vite.cjs",
      "types": "./lib-types/vite.d.ts"
    },
    "./qwik-styled": {
      "import": "./lib/qwik-styled.js",
      "require": "./lib/qwik-styled.cjs"
    },
    "./package.json": "./package.json"

I would love it if we get to support multi-entrypoint packages.

I’d like to add that it seems like the error is harmless in the case of the icons package, but it can lead to actual things not working, see #4436

Hi! I have seen the workaround commited from @kisaragi-hiu referencing this issue but it removes completely all errors thrown to the shell.

As a temporal workaround to avoid the noise caused using @qwikest/icons with all these warnings in console, I’m using the following script on top of the entry.ssr.tsx. By this way we don’t loose other console outputs. I hope it helps you @hbendev 😃

// entry.ssr.tsx
import { isDev } from '@builder.io/qwik/build'

if (isDev) {
  const consoleWarn = console.warn
  const SUPPRESSED_WARNINGS = ['Duplicate implementations of "JSXNode" found']

  console.warn = function filterWarnings (msg, ...args) {
    if (!SUPPRESSED_WARNINGS.some(entry => msg.includes(entry) || args.some(arg => arg.includes(entry))))
      consoleWarn(msg, ...args)
  }
}

Works fine, thank you. 😃

However, I guess solving the problem actually would be a better solution at the end of the day. 😃