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

Next.js 13: SWC Emotion Transform Plugin Breaks with root layout Server Component in app/ #41994

Closed
1 task done
karlhorky opened this issue Oct 27, 2022 · 39 comments · Fixed by #54284
Closed
1 task done
Assignees
Labels
bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team. locked

Comments

@karlhorky
Copy link
Contributor

karlhorky commented Oct 27, 2022

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

    Operating System:
      Platform: linux
      Arch: x64
      Version: Ubuntu 20.04.0 LTS Thu Oct 27 2022 20:19:36 GMT+0200 (Central European Summer Time)
    Binaries:
      Node: 16.14.2
      npm: 7.17.0
      Yarn: 1.22.19
      pnpm: 7.13.6
    Relevant packages:
      next: 13.0.1-canary.0
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Using the compiler: { emotion: true } option is throwing an error about React.createContext not being a function:

StackBlitz: https://stackblitz.com/edit/vercel-next-js-nlknru?file=app%2Fpage.tsx,app%2Flayout.tsx,app%2FEmotionRootStyleRegistry.tsx,package.json

event - compiled client and server successfully in 59 ms (403 modules)
error - (sc_server)/node_modules/@emotion/react/dist/emotion-element-b63ca7c6.cjs.dev.js (20:47) @ eval
error - TypeError: React.createContext is not a function
    at eval (webpack-internal:///(sc_server)/./node_modules/@emotion/react/dist/emotion-element-b63ca7c6.cjs.dev.js:19:49)
    at (sc_server)/./node_modules/@emotion/react/dist/emotion-element-b63ca7c6.cjs.dev.js (/home/projects/vercel-next-js-mxnxa7/.next/server/app/page.js:501:1)
    at __webpack_require__ (/home/projects/vercel-next-js-mxnxa7/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./node_modules/@emotion/react/jsx-dev-runtime/dist/emotion-react-jsx-dev-runtime.cjs.dev.js:7:22)
    at (sc_server)/./node_modules/@emotion/react/jsx-dev-runtime/dist/emotion-react-jsx-dev-runtime.cjs.dev.js (/home/projects/vercel-next-js-mxnxa7/.next/server/app/page.js:512:1)
    at __webpack_require__ (/home/projects/vercel-next-js-mxnxa7/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./app/layout.tsx:5:88)
    at (sc_server)/./app/layout.tsx (/home/projects/vercel-next-js-mxnxa7/.next/server/app/page.js:403:1)
    at __webpack_require__ (/home/projects/vercel-next-js-mxnxa7/.next/server/webpack-runtime.js:33:43)
    at Object.layout (webpack-internal:///(sc_server)/./node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fpage&appPaths=%2Fpage&pagePath=private-next-app-dir%2Fpage.tsx&appDir=%2Fhome%2Fprojects%2Fvercel-next-js-mxnxa7%2Fapp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=%2Fhome%2Fprojects%2Fvercel-next-js-mxnxa7&isDev=true&tsconfigPath=tsconfig.json!:22:99) {
  type: 'TypeError',
  page: '/'
}
null

Screenshot 2022-10-27 at 19 46 47


Making the root layout component into a client component does work, but this would be unfortunate:

StackBlitz: https://stackblitz.com/edit/vercel-next-js-rtrrxg?file=app%2Flayout.tsx,app%2Fpage.tsx,app%2FEmotionRootStyleRegistry.tsx,package.json


Workaround:

Disable the SWC Emotion transform plugin and use the /** @jsxImportSource @emotion/react */ directive instead:

Expected Behavior

It works to use the SWC Emotion transform plugin via compiler: { emotion: true } with a server component as the root layout

Link to reproduction

https://stackblitz.com/edit/vercel-next-js-nlknru?file=app%2Fpage.tsx,app%2Flayout.tsx,app%2FEmotionRootStyleRegistry.tsx,package.json

To Reproduce

  1. Install [email protected], @emotion/[email protected], @emotion/[email protected]
  2. Enable the app/ dir and the SWC Emotion Transform plugin using compiler: { emotion: true }, experimental: { appDir: true } in next.config.js
  3. Add the files as mentioned in @mitchellhamilton's post here: Plans to support Next.js 13 - /app directory emotion-js/emotion#2928 (comment)
  4. Remove the /** @jsxImportSource @emotion/react */ directive to rely on the SWC Emotion transform plugin to add css prop support
  5. Start the server and observe the error

NEXT-1368

@karlhorky karlhorky added the bug Issue was opened via the bug report template. label Oct 27, 2022
@r0mankon
Copy link

In the same way, I experience the same problem with @mui, which uses emotion under the hood.

@talentlessguy
Copy link

Same with @react-spring/web

@rolanday
Copy link

Ditto. mui5, which depends on emotion breaks with TypeError: React.createContext is not a function when attempting to wrap app layout with theme context provider.

@Romanapf
Copy link

Romanapf commented Oct 30, 2022

Same issue with framer-motion library

@karlhorky
Copy link
Contributor Author

karlhorky commented Oct 30, 2022

Maybe the people replying about different libraries here can also mention whether your reproduction uses SWC with compiler: { emotion: true } in next.config.js (or maybe also look if your library configures this internally for you). And then edit your posts to include this information.

If you are not using this config option, then actually your comments are not related to the subject of this issue.

@dan-turner
Copy link

dan-turner commented Oct 30, 2022

@karlhorky are you saying there's a correct way to make Next.JS v13 server components work with Emotion? Sorry new to this space

Edit: just noticed the workaround mentioned above. Will give it a try

@rolanday
Copy link

rolanday commented Oct 30, 2022

Maybe the people replying about different libraries here can also mention whether your reproduction uses SWC with compiler: { emotion: true } in next.config.js (or maybe also look if your library configures this internally for you). And then edit your posts to include this information.

If you are not using this config option, then actually your comments are not related to the subject of this issue.

I am using a vanilla Next 13.0.0 config created using npx create-next-app@latest --typescript, and the only changes are 1) setting experimental.appDir to true, and 2) addition of layout.tsx with MUI v5 Box component added, plus a no-op page.tsx. Result in same exact error as op posted.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  experimental: {
    appDir: true,
  }
}

module.exports = nextConfig
- project root
   - app
      - layout.tsx
      - page.tsx

// layout.tsx
import { Box } from '@mui/material';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <head></head>
      <Box sx={{ display: 'flex', flexDirection: 'column' }}>
        <body>{children}</body>
      </Box>
    </html>
  )
}
// page.tsx
export default function Page() {
  return <div></div>
}

edit: here are project deps -- just noticed added some add'l modules in anticipation of using, but hit wall early with above issues (or different having same symptom), so extra modules unused).

  "dependencies": {
    "@emotion/cache": "^11.10.5",
    "@emotion/react": "^11.10.5",
    "@emotion/styled": "^11.10.5",
    "@mui/icons-material": "^5.10.9",
    "@mui/material": "^5.10.11",
    "next": "13.0.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-dropzone": "^14.2.3",
    "swiper": "^8.4.4"
  },

@karlhorky
Copy link
Contributor Author

That may be unrelated enough for a new issue (for MUI without this compiler: { emotion: true } config)

@mwskwong
Copy link

mwskwong commented Oct 31, 2022

As far as I recall, the doc mentioned at this moment Emotion doesn't work with app/ at all, isn't it?

@cody-ta
Copy link

cody-ta commented Oct 31, 2022

I have the same problem with React-redux. When trying to wrap {children} with a store Provider:

TypeError: (0 , _react.createContext) is not a function

Call Stack

eval
	(sc_server)/node_modules/react-redux/lib/components/Context.js (8:65)
Object.(sc_server)/./node_modules/react-redux/lib/components/Context.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5035:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/hooks/useReduxContext.js (8:15)
Object.(sc_server)/./node_modules/react-redux/lib/hooks/useReduxContext.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5167:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/hooks/useSelector.js (9:23)
Object.(sc_server)/./node_modules/react-redux/lib/hooks/useSelector.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5178:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/index.js (22:19)```

@dan-turner
Copy link

@karlhorky are you saying there's a correct way to make Next.JS v13 server components work with Emotion? Sorry new to this space

Edit: just noticed the workaround mentioned above. Will give it a try

Doesn't seem to work without "use client"

@karlhorky
Copy link
Contributor Author

karlhorky commented Oct 31, 2022

Doesn't seem to work without "use client"

There is a version that works with a root layout as a server component (does not have use client). The page and provider are still client components because they rely on context. You can find this workaround link in the section marked Workaround in the description of this PR at the top of the thread on this page (you can find it by searching for the section mentioning @jsxImportSource @emotion/react).

@Rafcin
Copy link

Rafcin commented Nov 1, 2022

@karlhorky To what description are you referring?

@creazy231
Copy link

Same problem using react-select https://github.com/jedwatson/react-select

@magnuen2k
Copy link

Issues with different libraries workaround

I have the same problem with React-redux. When trying to wrap {children} with a store Provider:

TypeError: (0 , _react.createContext) is not a function

Same issue with framer-motion library

Workaround

My workaround was creating my own custom wrapper for the providers with "use client" like this:

Custom Wrapper Wrapper.tsx

'use client'

export const Wrapper = ({ children }: { children: React.ReactNode }) => {
  return (
    <Provider store={store}>
      {children}
    </Provider>
  );
};

Then wrapping the children in layout.tsx like this:

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Wrapper>{children}</Wrapper>
      </body>
    </html>
  );
}

Not sure if this is optimal, but it works for now.

@tisonkun
Copy link

tisonkun commented Nov 9, 2022

@magnuen2k I believe we should finally avoid 'use client' since we shouldn't need a client module in this case.

@magnuen2k
Copy link

@tisonkun I think the issue here is that you cannot use context etc. without specifying that the component is a client component. And react-redux etc. does not specify that.

@iSuslov
Copy link

iSuslov commented Nov 13, 2022

Overall, is it valid to say that MUI does not work with Nextjs v13?

@Rafcin
Copy link

Rafcin commented Nov 13, 2022

@iSuslov I mean it works, but yea you can't leverage app dir etc. I think soon we'll start seeing solutions. People depend on MUI and people use CSS-in-JS solutions for a lot of existing projects so a fix will come.

@AChristoff
Copy link

AChristoff commented Nov 14, 2022

Yep I'm stuck too. I can`t fully migrate to v13 and adopt it because the project depends on MUI

@Daavidaviid
Copy link

So we cannot use react-spring currently with server component and Nextjs v13 ?

@JustKira
Copy link

JustKira commented Dec 2, 2022

if anyone is using some sort of wrapper make sure to define "use client" in frist line of script of wrapper. anything that has useSomthing in it must be in script that start with "use client"

@antiproblemist
Copy link

Same issue exists when using antd with NextJS v13 appdir
The workaround I used was to declare 'use client' on top of layout.js where antd components were imported
Still waiting for a proper fix

@Zubayer94
Copy link

I have the same problem with React-redux. When trying to wrap {children} with a store Provider:

TypeError: (0 , _react.createContext) is not a function

Call Stack

eval
	(sc_server)/node_modules/react-redux/lib/components/Context.js (8:65)
Object.(sc_server)/./node_modules/react-redux/lib/components/Context.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5035:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/hooks/useReduxContext.js (8:15)
Object.(sc_server)/./node_modules/react-redux/lib/hooks/useReduxContext.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5167:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/hooks/useSelector.js (9:23)
Object.(sc_server)/./node_modules/react-redux/lib/hooks/useSelector.js
	file:///Users/cody/Code/lafuong-web/.next/server/app/page.js (5178:1)
__webpack_require__
	file:///Users/cody/Code/lafuong-web/.next/server/webpack-runtime.js (33:43)
eval
	(sc_server)/node_modules/react-redux/lib/index.js (22:19)```

@codyslex1a did you find any solution? I faced the same problem here....

@malikalimoekhamedov
Copy link

So we cannot use react-spring currently with server component and Nextjs v13 ?

I know I can't. 'use client' workaround is not doing it for me even if I truffle all of my components with it.

@Daavidaviid
Copy link

Daavidaviid commented Dec 17, 2022

So we cannot use react-spring currently with server component and Nextjs v13 ?

I know I can't. 'use client' workaround is not doing it for me even if I truffle all of my components with it.

Now that I've been using nextjs13appDir for a little while I realize how stupid my previous comment was 😅

'use client' is working for me.
Just try using it as deep as you can in the tree of components.

Only where it's necessary to not lose the benefits of Server components

@rtrembecky
Copy link

guys. @karlhorky tried to explain multiple times - this issue is about the compiler option in next.config.js AFTER you work around the basic emotion or MUI setup using "use client" directives for CacheProvider and all the components that will use emotion. If you comment out the emotion: true line in next.config.js in his StackBlitz (https://stackblitz.com/edit/vercel-next-js-nlknru?file=next.config.js), the app doesn't throw, but also it doesn't work (the rendered text isn't green). You currently need another workaround because of this, as shown in the second @karlhorky's StackBlitz (https://stackblitz.com/edit/vercel-next-js-ajvkxp?file=app/page.tsx) - put /** @jsxImportSource @emotion/react */ on top of page.tsx.

@Systemcluster
Copy link

Adding /** @jsxImportSource react */ to the top of the root layout makes { compiler: { emotion: true } } work.

@dasblitz
Copy link

You currently need another workaround because of this, as shown in the second @karlhorky's StackBlitz (https://stackblitz.com/edit/vercel-next-js-ajvkxp?file=app/page.tsx) - put /** @jsxImportSource @emotion/react */ on top of page.tsx.

In the linked example, adding the 'use client' directive to page.tsx makes it impossible to use ServerComponents I think? Since they can only be passed as via props or as children, or am I missing something here?

@Zagorodnyi
Copy link

I've tried everything. This is so cursed

@tchryssos
Copy link

tchryssos commented Apr 8, 2023

Adding /** @jsxImportSource react */ to the top of the root layout makes { compiler: { emotion: true } } work.

Just want to expand on this / highlight it a little since this lowers the overhead quite a bit for people who DON'T want to disable compile: { emotion: true } (and/or the equivalent in tsconfig since that seems to throw the same issue)

The vast majority of my files are going to be components that use styled or @mui, so having my jsx source be emotion is pretty important.

As some commenters in this thread and the "workaround" thread have mentioned, you can specify jsxImportSource on a file-by-file basis, though most people seem to be doing that to enable emotion specifically on their 'use client' files; by not specifying the emotion compiler in next.config.js you're falling back to regular react for jsx which does work with server components and avoids all the errors people are posting above.

What @Systemcluster posted helped me realize that the opposite was true as well; I could leave my compiler settings intact so that my ~99% of files that are using MUI or some custom styled component only need 'use client' (which was always going to be the case in app directory world, at least for now) since they'll be using the emotion compiler by default, but if I have something I know could be a server component I can just specify /** @jsxImportSource react */ explicitly in that file, which will override the compile setting (they mentioned the root layout which is true, but afaict this should work anywhere in the tree).

Following other advice here about weaving the client and server components together means that everything works the way I expected after just reading the next docs: I get root layouts that are server (with metadata support, which was actually what I cared about when I started looking into this) and my client children play nicely with them, with "minimum" file prefixing.

@karlhorky
Copy link
Contributor Author

Updates from the React Server Components Emotion ecosystem:

  1. Seems like Chakra UI (another UI library dependent on Emotion) is going to switch away from Emotion and to a zero runtime CSS-in-JS solution called Panda:

Zero runtime CSS-in-JS [Panda]

This is the most common and most challenging request we get from users.

Runtime CSS-in-JS and style props are powerful features that allow developers to build dynamic UI components that are composable, predictable, and easy to use. However, it comes at the cost of performance and runtime.

With the release of React Server Components, providing the ability to write Chakra UI components on the server has become crucial. This is a huge win for performance, development, and user experience.

We're building a new, framework-agnostic styling solution that keeps most of the great features of Chakra's styling system but extracts styles at build time. It'll also feature a PostCSS plugin that extracts styles at postcss run time during development.

Panda will leverage new modern platform features like CSS variables, cascade layers, and W3C token spec.

https://www.adebayosegun.com/blog/the-future-of-chakra-ui

  1. MUI is also considering switching to a different solution: [system] Support new style engine that generates static CSS files at build time mui/material-ui#34826

@mattrltrent
Copy link

mattrltrent commented Jun 4, 2023

I had to add the "use client" directive to the top of my page.js file in /app.

@dzcpy
Copy link

dzcpy commented Jun 20, 2023

Is there any solution yet?

@Systemcluster
Copy link

Is there any solution yet?

Add /** @jsxImportSource react */ to your layouts, and "use client" to your pages and components.

@timneutkens timneutkens added the linear: next Confirmed issue that is tracked by the Next.js team. label Jul 3, 2023
@huozhi huozhi self-assigned this Aug 19, 2023
@kodiakhq kodiakhq bot closed this as completed in #54284 Aug 20, 2023
kodiakhq bot pushed a commit that referenced this issue Aug 20, 2023
### What & Why

emotion-js has its own [jsx transform](https://emotion.sh/docs/typescript#emotionreact) which is being applied when `compiler.emotion` is enabled in `next.config.js`.

Thanks to emotion-js team that provided an emotion-js example setup with app router [here](emotion-js/emotion#2928 (comment)), so that we can use it as test example with app router. Based on the setup, we create a test case working with emotion js but failed with error mentioned in #41994 that some client hooks appearing in server components. That is because the emotion-js jsx factory includes some client hooks.

### How

For server components, css-in-js is not recommended to apply so we disabled the transform before, the emotion jsx factory is a separate config that should also not be applied in server components. So in this case we still use react jsx factory instead of the emotion-js one for server components then it won't error. The test case can also be used as an example for basic emotion-js use case with app router.


Fixes #41994
Closes NEXT-1368
@karlhorky
Copy link
Contributor Author

karlhorky commented Aug 20, 2023

Thanks for the fix in #54284 @huozhi 🙌

Once this is released in the next canary version, can someone from this thread who uses Emotion check the new version and provide some proof that it's working in your app? Make sure to install [email protected] (once this version is released).

cc @Zagorodnyi @dzcpy @dan-turner @Systemcluster @magnuen2k if you could test as mentioned above, that would be great!

@dan-turner
Copy link

Will give it a look first thing tomorrow 🙏.

Love this community ❤️

@mwskwong
Copy link

Thanks for the fix in #54284 @huozhi 🙌

Once this is released in the next canary version, can someone from this thread who uses Emotion check the new version and provide some proof that it's working in your app? Make sure to install [email protected] (once this version is released).

cc @Zagorodnyi @dzcpy @dan-turner @Systemcluster @magnuen2k if you could test as mentioned above, that would be great!

Seems to be working for me with MUI:

Repo: mwskwong/mwskwong.com@f4092af
Live build: https://resume-82bwpwy6q-mwskwong.vercel.app

@github-actions
Copy link
Contributor

github-actions bot commented Sep 4, 2023

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot added the locked label Sep 4, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team. locked
Projects
None yet
Development

Successfully merging a pull request may close this issue.