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

Support NextJS 13 #183

Open
bfourgeaud opened this issue Nov 10, 2022 · 33 comments
Open

Support NextJS 13 #183

bfourgeaud opened this issue Nov 10, 2022 · 33 comments

Comments

@bfourgeaud
Copy link

Hello,

I am upgrading a project from NextJS12 to NextJs13 and there is an error concerning this package.

When I add a new Icon the application throws an error
<Icon icon="mdi:facebook" className="w-5 h-5"/>

error - (sc_server)\node_modules\@iconify\react\dist\iconify.js (1795:54) @ eval error - TypeError: Class extends value undefined is not a constructor or null at eval (webpack-internal:///(sc_server)/./node_modules/@iconify/react/dist/iconify.js:1643:55) at Object.(sc_server)/./node_modules/@iconify/react/dist/iconify.js (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:828:1) at __webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(sc_server)/./components/common/Footer.tsx:6:72) at Object.(sc_server)/./components/common/Footer.tsx (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:764:1) at __webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(sc_server)/./app/sites/[subdomain]/layout.tsx:13:83) at Object.(sc_server)/./app/sites/[subdomain]/layout.tsx (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:742:1) at __webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at Object.layout (webpack-internal:///(sc_server)/./node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fsites%2F%5Bsubdomain%5D%2Fpage&appPaths=%2Fsites%2F%5Bsubdomain%5D%2Fpage&pagePath=private-next-app-dir%2Fsites%2F%5Bsubdomain%5D%2Fpage.tsx&appDir=E%3A%5CJEEBIE.ME%5CProjets%5COCLR%5Coc-lr.com%20-%20V2%5Capp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=E%3A%5CJEEBIE.ME%5CProjets%5COCLR%5Coc-lr.com%20-%20V2&isDev=true&tsconfigPath=tsconfig.json!:28:129) { type: 'TypeError', page: '/sites/[subdomain]' }

I am using

"next": "^13.0.2"
"react": "^18.2.0"
"@iconify/react": "^4.0.0"

@cyberalien
Copy link
Member

Thanks for reporting!

I think I found what's causing conflict. Try installing @iconify/react@next, please tell me if it solves issue.

@bfourgeaud
Copy link
Author

Hello,

I just upgraded to @latest version.
There is still the same error but not at the same line on the iconify.mjs file ;)

error - (sc_server)\node_modules\@iconify\react\dist\iconify.mjs (1791:28) @ eval error - TypeError: Class extends value undefined is not a constructor or null at eval (webpack-internal:///(sc_server)/./node_modules/@iconify/react/dist/iconify.mjs:1657:64) at Object.(sc_server)/./node_modules/@iconify/react/dist/iconify.mjs (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:3940:1) at __webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(sc_server)/./components/common/Footer.tsx:6:72) at Object.(sc_server)/./components/common/Footer.tsx (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:775:1) at __webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(sc_server)/./app/sites/[subdomain]/layout.tsx:13:83) at Object.(sc_server)/./app/sites/[subdomain]/layout.tsx (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\app\sites\[subdomain]\page.js:753:1) at Function.__webpack_require__ (E:\JEEBIE.ME\Projets\OCLR\oc-lr.com - V2\.next\server\webpack-runtime.js:33:42) at processTicksAndRejections (node:internal/process/task_queues:96:5) { type: 'TypeError', page: '/sites/[subdomain]' }

@bfourgeaud
Copy link
Author

Edit: I just labeled the component using the Icons with "use client" and there is no error anymore.
The problem was the component was a server component and rendered on the server, which is incompatible with @iconify in it's basic usage as I understand.

@cyberalien
Copy link
Member

I think you've misread my message. Please try @next, not @latest. It includes a possible fix for that error message.

Though error about .mjs file is weird. That should not be happening at all.

@bfourgeaud
Copy link
Author

I have this version installed
"@iconify/react": "^4.0.1-beta.1"

The error message still appears when I do not add "use client" on top of component.
I created a wrapper component to use the Icon like before

"use client"
import { Icon as BaseIcon, IconProps } from "@iconify/react";

const Icon:React.FunctionComponent<IconProps> = (props) => <BaseIcon {...props} />
export default Icon

@cyberalien
Copy link
Member

Thanks. This is weird error message. In .js file Rollup created wrapper for require(), which could have been causing issues, but in .mjs file there is nothing that could trigger error: imports are all correct. I'll debug it.

@cyberalien
Copy link
Member

cyberalien commented Nov 17, 2022

I've debugged this. Component works correctly with NextJS 13 without any issues.

I've also reverted change to see if I'll get that error message, didn't get it. So I can't replicate issue. Using basic app created with pnpm create next-app, which created package with NextJS 13.0.3

edit: also cannot replicate issue using NextJS 12.2.5. I suspect issue is with outdated Webpack, not NextJS.

@bfourgeaud
Copy link
Author

I created a repository to show you the bug :
https://github.com/bfourgeaud/iconify-next13-bug

It has two pages /error and /success to show you how this error occurs

@cyberalien
Copy link
Member

Thanks a lot!

Now I'm seeing that bug and can debug it. This is very helpful!

@cyberalien
Copy link
Member

I'm very confused. In your code React.Component does not exist.

Icon component is fine. It uses React in intended way, but something else is messing with it. Somewhere in build process React package seem to be reduced.

These is everything that is exported from React using import React from 'react'; console.log(Object.keys(React));:

[
  'Children',
  'Fragment',
  'Profiler',
  'StrictMode',
  'Suspense',
  '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED',
  'cache',
  'cloneElement',
  'createElement',
  'createRef',
  'createServerContext',
  'forwardRef',
  'isValidElement',
  'lazy',
  'memo',
  'startTransition',
  'use',
  'useCallback',
  'useContext',
  'useDebugValue',
  'useId',
  'useMemo',
  'version'
]

These are keys I get when importing React in my demo app:

[
  'Children',
  'Component',
  'Fragment',
  'Profiler',
  'PureComponent',
  'StrictMode',
  'Suspense',
  '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED',
  'cloneElement',
  'createContext',
  'createElement',
  'createFactory',
  'createRef',
  'forwardRef',
  'isValidElement',
  'lazy',
  'memo',
  'startTransition',
  'unstable_act',
  'useCallback',
  'useContext',
  'useDebugValue',
  'useDeferredValue',
  'useEffect',
  'useId',
  'useImperativeHandle',
  'useInsertionEffect',
  'useLayoutEffect',
  'useMemo',
  'useReducer',
  'useRef',
  'useState',
  'useSyncExternalStore',
  'useTransition',
  'version'
]

It is missing the following keys:

[
  'Component',
  'PureComponent',
  'createContext',
  'createFactory',
  'unstable_act',
  'useDeferredValue',
  'useEffect',
  'useImperativeHandle',
  'useInsertionEffect',
  'useLayoutEffect',
  'useReducer',
  'useRef',
  'useState',
  'useSyncExternalStore',
  'useTransition'
]

So something is messing with React in your code. I don't know what is doing that.

@cyberalien
Copy link
Member

One more weird thing: I've installed React 18.2.0. It is installed correctly, I've checked files. However, in component when logging React.version, it returns 18.3.0-next-4bd245e9e-20221104. So there seem to be a second React instance somewhere, probably that's the bugged one.

@cyberalien
Copy link
Member

React is imported from this file: node_modules/next/dist/compiled/react/index.js, however, that file contains everything, including Component, but for some reason it does not exist in imported file.

I suspect Webpack is to blame here.

@bfourgeaud
Copy link
Author

The missing keys seems to be the one that you can't use anymore in Server Components, but only in Client Components (marked with "use client" at the top). That's just an idea.

Fyi, the project was simply created with npx create-next-app@latest

  • added the app/ and components/ folders
  • Edited next.config.js to use the new appDir
  • deleted unused files in pages/ folder
  • Created the files and folders in app/ and components/

@cyberalien
Copy link
Member

I can't find anything in Next documentation that states that class components are not allowed.

@bfourgeaud
Copy link
Author

When I console log React keys from IconWrapper.tsx it shows all the correct keys

"use client"
import { Icon as BaseIcon, IconProps } from "@iconify/react";

import React from 'react';


const Icon:React.FunctionComponent<IconProps> = (props) => {
  console.log(Object.keys(React));
  return <BaseIcon {...props} />
}
export default Icon
[
    "Children",
    "Component",
    "Fragment",
    "Profiler",
    "PureComponent",
    "StrictMode",
    "Suspense",
    "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
    "cache",
    "cloneElement",
    "createContext",
    "createElement",
    "createFactory",
    "createRef",
    "createServerContext",
    "forwardRef",
    "isValidElement",
    "lazy",
    "memo",
    "startTransition",
    "unstable_act",
    "unstable_useCacheRefresh",
    "use",
    "useCallback",
    "useContext",
    "useDebugValue",
    "useDeferredValue",
    "useEffect",
    "useId",
    "useImperativeHandle",
    "useInsertionEffect",
    "useLayoutEffect",
    "useMemo",
    "useReducer",
    "useRef",
    "useState",
    "useSyncExternalStore",
    "useTransition",
    "version"
]

@cyberalien
Copy link
Member

Indeed. Same when importing it in console. But add this to top of node_modules/@iconify/react/dist/iconify.mjs:

console.log('Imported React. Keys:', Object.keys(React));

and it will show short list.

@bfourgeaud
Copy link
Author

Only Client Components seem to be able to use React.Component.
And for that you have to add "use client" at top of component.

I don't know how to handle that with @iconify package ...
Maybe put IconComponent in a separate file labeled with "use client" ?

@cyberalien
Copy link
Member

With "use client" in component, it throws errors about missing "private-next-rsc-mod-ref-proxy" module.

@cyberalien
Copy link
Member

So it is not Webpack's fault. Found where stuff is missing: React is not being imported from file I've mentioned above, but from ./node_modules/next/dist/compiled/react/cjs/react.shared-subset.development.js and it is missing Component.

Looks like it is by design. But why?

@cyberalien
Copy link
Member

cyberalien commented Nov 17, 2022

This can't possibly be intended by design. Very weird.

I've reported this as bug to Next repository, including your demo repository: vercel/next.js#43051

@cyberalien
Copy link
Member

cyberalien commented Nov 18, 2022

Oh well, got response from NextJS team, missing support for class components is by design.

Looks like for now your solution with wrapper component is the only way to make it work.

Another option is to use @iconify-icon/react, but that seems to be bugged too. If I replace all references to @iconify/react to @iconify-icon/react, change wrapper code to this:

"use client";
import { Icon } from "@iconify-icon/react";

export default Icon;

It no longer throws errors. However, is still an issue:

  • Visiting http://localhost:3000/success works.
  • Visiting http://localhost:3000/error does not render anything because web component is not bundled.
  • Visiting http://localhost:3000/, then clicking "Working Wrapper", then clicking back, then clicking "Error Icon" works because web component is provided in /success.

So now there is a different bug: web component not being bundled on some pages.

What a clusterfuck Next13 is.

@cyberalien
Copy link
Member

Reported issue for web component not being bundled, based on your repo: vercel/next.js#43068

@nirglow
Copy link

nirglow commented Dec 6, 2022

Hey! I am also struggling with this. Any updates on this? Are we waiting for the issue to be resolved on their side?

@cyberalien
Copy link
Member

cyberalien commented Dec 6, 2022

Depends on which part of issue you are referring to.

If using @iconify/react, that is intended by NextJS design. It needs to be wrapped in client side component like in 6th post in this thread.

If using @iconify-icon/react, web component not being bundled seems to be a bug in NextJS and waiting for fix or at least for reply that it is intended behaviour. Though workaround is also wrapping it in client side component.

So either way it is better to just wrap it in client side component.

@loukamb
Copy link

loukamb commented Feb 5, 2023

I am also facing this issue in my project. By design, NextJS 13 does not support class components when a page is rendered on the server. You need to force the icon component to render on the client, which in my opinion is not a very good thing.

@cyberalien
Copy link
Member

It won't render anything on server side anyway, so forcing it to render on client side doesn't make any difference.

This component works by loading data dynamically from API, which means on first render icon data might not be available, so it doesn't render anything. Data is loaded only on client side.

If you need to render component immediately and on server side, there are different solutions:

unplugin-icons works by rendering it instantly and bundling data at build time.

If you do need dynamic icon data, iconify-icon is a web component that should work fine with NextJS. It renders icon independently from React, so doesn't have to deal with server/client side component shenanigans.

@MrBns
Copy link

MrBns commented Feb 14, 2024

Facing problem with Nextjs 14.
my component code is

            <button className="border-[2px] px-5 py-4 rounded-lg">
              Explore Now <Icon icon="solar:arrow-right-outline" />
            </button>

I found <iconify-icon icon="solar:arrow-right-outline"></iconify-icon> in element devtool.. but no shadow dom inside web component.
this tread also going for a long... if there any possible solution which gonna work ?

@cyberalien
Copy link
Member

You probably forgot to import iconify-icon (or @iconify-icon/react if you are using React wrapper), so web component didn't get bundled.

@MrBns
Copy link

MrBns commented Feb 14, 2024

You probably forgot to import iconify-icon (or @iconify-icon/react if you are using React wrapper), so web component didn't get bundled.

Hi thanks for your reply.. in Root layout of Application, I have included iconify-icon and in the component (where I am using Icon component) I have imported <Icon/> from @iconify-icon .. yeah. still not working.

@cyberalien
Copy link
Member

In browser console type customElements.get('iconify-icon')

It should return class for web component. If it doesn't return it, web component is not bundled.

@cyberalien
Copy link
Member

Did some more testing, found a possible issue why it might not always work in Next, published @iconify-icon/react version 2.0.1 with potential fix.

@aryankarim
Copy link

Did some more testing, found a possible issue why it might not always work in Next, published @iconify-icon/react version 2.0.1 with potential fix.

Thank you good sir. "@iconify-icon/react": "^2.1.0" works with "next": "14.2.1" flawlessly.

@cyberalien
Copy link
Member

cyberalien commented Apr 28, 2024

Published new version of @iconify/react that is compatible with Next.js.

Currently available as @iconify/react@next. It is a full rewrite of icon component, so need to do more testing before can mark it as stable, but so far works fine in my tests.

Long overdue. Sorry for delay.

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

No branches or pull requests

6 participants