nextui-org / nextui

🚀 Beautiful, fast and modern React UI library.
https://nextui.org
MIT License
22.01k stars 1.54k forks source link

Next.js 13 support #849

Closed AlejandroRodarte closed 1 year ago

AlejandroRodarte commented 2 years ago

Describe the bug

Next.js 13 just launched with multiple breaking changes.

One of those changes replaces pages/_app.tsx and pages/_document.tsx with a single, root-layout component at app/layout.tsx.

This may require changes to the official documentation to include support for this new version of the framework.

I have not really tried an attempt to fix the issue. This is what I have for the app/layout.tsx root-layout component:

import { NextUIProvider, CssBaseline } from '@nextui-org/react';
import React from 'react';

import { darkTheme } from '../themes/dark.theme';

interface RootLayoutProps {
  children: React.ReactNode;
}

export default function RootLayout(props: RootLayoutProps) {
  const { children } = props;
  return (
    <html lang="en">
      <head>{CssBaseline.flush()}</head>
      <body>
        <NextUIProvider theme={darkTheme}>{children}</NextUIProvider>
      </body>
    </html>
  );
}

Launching the application with next dev yields the following error in the web browser.

Server Error

TypeError: t.default.createContext is not a function
This error happened while generating the page. Any console logs will be displayed in the terminal window.

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

  1. Install a project with the following dependencies:
"dependencies": {
  "@nextui-org/react": "^1.0.0-beta.10",
  "next": "^13.0.0",
  "react": "^18.2.0",
  "react-dom": "^18.2.0"
},
"devDependencies": {
  "@types/node": "18.8.5",
  "@types/react": "18.0.21",
  "@types/react-dom": "18.0.6",
  "eslint": "8.25.0",
  "eslint-config-next": "^13.0.0",
  "typescript": "4.8.4"
}
  1. Enable the appDir flag in next.config.js.
/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
  experimental: {
    appDir: true,
  },
};

module.exports = nextConfig;
  1. Create an app/ directory at the root of the project.
  2. Create a root-layout component app/layout.tsx.
  3. Wrap the children prop with the <NextUIProvider /> component.
import { NextUIProvider, CssBaseline } from '@nextui-org/react';
import React from 'react';

import { darkTheme } from '../themes/dark.theme';

interface RootLayoutProps {
  children: React.ReactNode;
}

export default function RootLayout(props: RootLayoutProps) {
  const { children } = props;
  return (
    <html lang="en">
      <head>{CssBaseline.flush()}</head>
      <body>
        <NextUIProvider theme={darkTheme}>{children}</NextUIProvider>
      </body>
    </html>
  );
}
  1. Create a sample root page app/page.tsx.
interface PageProps {}

export default async function Page(props: PageProps) {
  return <div>Page</div>;
}
  1. Launch the web development server with next dev.

Expected behavior

The application should not crash, with NextUI loading the corresponding styles and themes.

Screenshots or Videos

No response

Operating System Version

Linux (Ubuntu 22.04)

Browser

Firefox

wickY26 commented 2 years ago

This is not a bug of nextui. You can checkout similar issues which are created at nextjs repo. I think we still need some time to play with new app folder of nextjs.

https://github.com/vercel/next.js/issues/41994

Xariwey commented 2 years ago

Read the official Beta documentation for Nextjs, about how to render third-party context providers

https://beta.nextjs.org/docs/rendering/server-and-client-components#rendering-third-party-context-providers-in-server-components

hope that helps

AlejandroRodarte commented 2 years ago

@Xariwey Thank you for the reference! I did end up reading the documentation and was able to un-crash the application, with the NextUI styles partially working.

What I did was to simply move the UI provider into a Client Component.

app/layout.tsx (server component)

export default function Layout(props: LayoutProps) {
  const { children } = props;
  return (
    <html lang="en">
      <body>
        <RootLayout>{children}</RootLayout>
      </body>
    </html>
  );
}

app/RootLayout.component.tsx (client component)

'use client';
// ...
export function RootLayout(props: RootLayoutProps) {
  const { children } = props;
  return (
    <NextUIProvider theme={darkTheme}>
      <MainNavbar />
      <main className={classes.main}>{children}</main>
    </NextUIProvider>
  );
}

Again, some of the styles pertaining to the UI components are not working as they did back in Next 12. Definitely not the prettiest solution, but it's what works for now.

Xariwey commented 2 years ago

@AlejandroRodarte try with this and see if this fix ur broken styles

providers.js

'use client'

import { useServerInsertedHTML } from 'next/navigation'
import { CssBaseline } from '@nextui-org/react'
import { NextUIProvider } from '@nextui-org/react'
import { SomeProvider } from 'somepackage'

export default function Providers({ children }) {
  useServerInsertedHTML(() => {
    return <>{CssBaseline.flush()}</>
  })

  return (
    <>
      <SomeProvider>
        <NextUIProvider>
          {children}
        </NextUIProvider>
      </SomeProvider>
    </>
  )
}

and wrap ur layout in them

import Providers from './providers'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </head>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

keep in mind that in every place that u will ned to use a nextui component u will need to use 'use client', follow NextJS recomendations for this https://beta.nextjs.org/docs/rendering/server-and-client-components#moving-client-components-to-the-leaves

AlejandroRodarte commented 2 years ago

@Xariwey Thank you so much for your help. Interestingly enough, upgrading to v13.0.3-canary.0 fixed the few styling issues I had. However, my code lacked the CssBaseline.flush(), so I will also implement it.

Thank you again!

Update: So I included the CssBaseline.flush() line in the Providers Client Component. I get the following warning:

Warning: Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.

I assume that it is a harmless warning, so I will leave it like that for now.

AivarGabd commented 2 years ago

To the Brave Souls who decided to jump into next js and ssr, i hope temporary solution to use next ui components - they need to be client side rendered

` 'use client' import { Button } from "@nextui-org/react";

const TestComponent = () => (
    <div>
        {/**Your content */}
        <Button>
            Test
        </Button>
    </div>
)
export default TestComponent`
anuragk15 commented 1 year ago

Tried the solutions mentioned here. And although NextUI components are working, when the page is loaded there is a flicker effect. For the first .5 - 1 second, there seems to be no CSS styling then suddenly it is applied. Also, I don't know how relevant this is to this issue, but in the old pages directory, even if I set a custom theme in _app.jsx and reload the page, the default color is first loaded, and then quickly my custom theme is loaded.

import { NextUIProvider } from '@nextui-org/react';
import { createTheme, Text } from "@nextui-org/react"
import { SSRProvider } from 'react-aria';
const theme = createTheme({
    type: "light", // it could be "light" or "dark"
    theme: {
        colors: {
            // brand colors
            primaryLight: '$purple200',
            primaryLightHover: '$purple300',
            primaryLightActive: '$purple400',
            primaryLightContrast: '$purple600',
            primary: '#b078ef',
            primaryBorder: '$purple500',
            primaryBorderHover: '$purple600',
            primarySolidHover: '$purple700',
            primarySolidContrast: '$white',
            primaryShadow: '$purple500',
            secondaryLight: '$yellow200',
            secondaryLightHover: '$yellow300',
            secondaryLightActive: '$yellow400',
            secondaryLightContrast: '$yellow600',
            secondary: '#f1c232',
            secondaryBorder: '$yellow500',
            secondaryBorderHover: '$yellow600',
            secondarySolidHover: '$yellow700',
            secondarySolidContrast: '$white',
            secondaryShadow: '$yellow500',
            // ...  more colors
        },
        space: {},
        fonts: {}
    }
})
function MyApp({ Component, pageProps }) {

    return (
        // 2. Use at the root of your app
        <SSRProvider>
 <NextUIProvider theme={theme}>
                <Component {...pageProps} />
            </NextUIProvider>
        </SSRProvider>

    );
}

export default MyApp;
Xariwey commented 1 year ago

@anuragk15

Tried the solutions mentioned here. And although NextUI components are working, when the page is loaded there is a flicker effect. For the first .5 - 1 second, there seems to be no CSS styling then suddenly it is applied.

it could be realted to ur flicker issue but if u remove the <head /> tag in your root layout theres a few bugs happening within nextjs13 including the flickering / broken styles like u mention...

jallynme commented 1 year ago

the default color is first loaded, and then quickly my custom theme is loaded.

same here

romainmarchand commented 1 year ago

@Xariwey @jallynme Hi, regarding the flickering issue, using next-themes solved the problem for me as suggested by @tianenpang here: #935

CurtisTD commented 1 year ago

I've tried the steps @Xariwey mentioned, on a brand new typescript project, but I keep getting these errors:

Unhandled Runtime Error

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Callstack:

parseModel
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (33:0)
resolveModule
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (749:0)
processFullRow
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (825:0)
processBinaryChunk
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (869:0)
progress
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (1476:0)

The web app will not load; as soon as I add the <Providers/> wrapper around the children in layout.tsx, it breaks.

Inam-ulrehman commented 1 year ago

I've tried the steps @Xariwey mentioned, on a brand new typescript project, but I keep getting these errors:

Unhandled Runtime Error

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Callstack:

parseModel
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (33:0)
resolveModule
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (749:0)
processFullRow
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (825:0)
processBinaryChunk
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (869:0)
progress
    node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-client.browser.development.js (1476:0)

The web app will not load; as soon as I add the <Providers/> wrapper around the children in layout.tsx, it breaks.

This is happening because of version 13.3.0 , also mine is working fine with 13.2.4 . This issue is raised with NextJs13 team and people are waiting to get update.

rizkiandrianto commented 1 year ago

@AlejandroRodarte try with this and see if this fix ur broken styles

providers.js

'use client'

import { useServerInsertedHTML } from 'next/navigation'
import { CssBaseline } from '@nextui-org/react'
import { NextUIProvider } from '@nextui-org/react'
import { SomeProvider } from 'somepackage'

export default function Providers({ children }) {
  useServerInsertedHTML(() => {
    return <>{CssBaseline.flush()}</>
  })

  return (
    <>
      <SomeProvider>
        <NextUIProvider>
          {children}
        </NextUIProvider>
      </SomeProvider>
    </>
  )
}

and wrap ur layout in them

import Providers from './providers'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </head>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

keep in mind that in every place that u will ned to use a nextui component u will need to use 'use client', follow NextJS recomendations for this https://beta.nextjs.org/docs/rendering/server-and-client-components#moving-client-components-to-the-leaves

With this approach, I got double rendered styles with id stitches, 1 under the head, 1 inside the body. Still finding the root cause. But I'm not facing FOUC with this approach.

vicgolob commented 1 year ago

Hang in there baby, still flickering but it's going much better

I tried putting the CssBaseline.flush() inside the <NextUIProvider> wrapper and it works better. I'm still getting the flicker but is much less frequent. I tried to refresh and open an incognito window, seems to load without the flicker (maybe it's there all the time but is imperceptible. I'm sharing a video of a screen recording and my layout.js and providers.js.

https://www.loom.com/share/65f7519ea6a54a30b8120472c7bb8ff1?sid=0685f4ef-4211-499b-82bd-8f5bdddf7e96

// app/layout.js

import { Inter } from "next/font/google";
import Providers from "./providers";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
    title: "Create Next App",
    description: "Generated by create next app",
};

export default function RootLayout({ children }) {
    return (
        <html lang="en">
            <body className={inter.className}>
                <Providers>{children}</Providers>
            </body>
        </html>
    );
}
// app/provider.js
"use client";

import { CssBaseline, NextUIProvider } from "@nextui-org/react";
import "./globals.css";

export default function Providers({ children }) {
    return (
        <NextUIProvider>
            <div className="app">
                {CssBaseline.flush()}
                {children}
            </div>
        </NextUIProvider>
    );
}
Tuan2002 commented 1 year ago

I see this warning via nextjs 13 with provider setup: Support for defaultProps will be removed from memo components in a future major release. Use JavaScript default parameters instead.

jrgarciadev commented 1 year ago

Hey please upgrade to V2 since V1 will no receive more updates.

NextUI V2 fully supports the latest Next.js and React versions including RSC components

KevinKeyssx commented 1 year ago

Hello, I have version 2.1.5 of nextui still working with problems whit next13, plus CssBaseline is no longer available

jrgarciadev commented 1 year ago

Hey @KevinKeyssx use any of these Next.js 13 templates as guidance

https://github.com/nextui-org/next-app-template (App directory) https://github.com/nextui-org/next-pages-template (Pages directory)

BenMukebo commented 1 year ago

Hello guys, is CssBaseline module functional ? because I'm importing and it I get the error: Module '"@nextui-org/react"' has no exported member 'CssBaseline' I'm using "next": "13.4.19" version

here is my code:

 "use client";
import { ReactNode } from "react";
import { NextUIProvider, CssBaseline } from '@nextui-org/react';
import { useServerInsertedHTML } from 'next/navigation'

type Props = {
  children: ReactNode;
};

export default function ThemeProvider({ children }: Props) {
  useServerInsertedHTML(() => {
    return <>{CssBaseline.flush()}</>
  })

  return (
    <NextUIProvider>
      {children}
    </NextUIProvider>
  );
}
tianenpang commented 1 year ago

Hi @BenMukebo no longer need CssBaseline if you are using v2, please follow the the documentation of NextUI + Next.js