next.js icon indicating copy to clipboard operation
next.js copied to clipboard

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

Open karlhorky opened this issue 2 years ago • 20 comments

Verify canary release

  • [X] 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:

  • https://github.com/emotion-js/emotion/issues/2928#issuecomment-1293885043

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: https://github.com/emotion-js/emotion/issues/2928#issuecomment-1293012737
  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

karlhorky avatar Oct 27 '22 18:10 karlhorky

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

r0mankon avatar Oct 27 '22 18:10 r0mankon

Same with @react-spring/web

talentlessguy avatar Oct 28 '22 17:10 talentlessguy

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.

rolanday avatar Oct 29 '22 21:10 rolanday

Same issue with framer-motion library

Romanapf avatar Oct 30 '22 09:10 Romanapf

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.

karlhorky avatar Oct 30 '22 10:10 karlhorky

@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

dan-turner avatar Oct 30 '22 11:10 dan-turner

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"
  },

rolanday avatar Oct 30 '22 18:10 rolanday

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

karlhorky avatar Oct 30 '22 21:10 karlhorky

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

mwskwong avatar Oct 31 '22 02:10 mwskwong

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)```

cody-ta avatar Oct 31 '22 03:10 cody-ta

@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"

dan-turner avatar Oct 31 '22 03:10 dan-turner

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).

karlhorky avatar Oct 31 '22 06:10 karlhorky

@karlhorky To what description are you referring?

Rafcin avatar Nov 01 '22 23:11 Rafcin

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

creazy231 avatar Nov 09 '22 07:11 creazy231

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.

magnuen2k avatar Nov 09 '22 14:11 magnuen2k

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

tisonkun avatar Nov 09 '22 14:11 tisonkun

@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.

magnuen2k avatar Nov 09 '22 14:11 magnuen2k

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

iSuslov avatar Nov 13 '22 22:11 iSuslov

@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.

Rafcin avatar Nov 13 '22 23:11 Rafcin

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

AChristoff avatar Nov 14 '22 12:11 AChristoff

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

Daavidaviid avatar Nov 24 '22 17:11 Daavidaviid

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"

JustKira avatar Dec 02 '22 00:12 JustKira

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

antiproblemist avatar Dec 09 '22 13:12 antiproblemist

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....

Zubayer94 avatar Dec 10 '22 12:12 Zubayer94

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.

malikalimoekhamedov avatar Dec 17 '22 00:12 malikalimoekhamedov

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

Daavidaviid avatar Dec 17 '22 01:12 Daavidaviid

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.

rtrembecky avatar Feb 25 '23 11:02 rtrembecky

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

Systemcluster avatar Feb 26 '23 07:02 Systemcluster

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?

dasblitz avatar Mar 20 '23 15:03 dasblitz

I've tried everything. This is so cursed

Zagorodnyi avatar Mar 31 '23 22:03 Zagorodnyi