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

TypeError: Cannot read property 'key' of null on SSR #1728

Closed
ksweetie opened this issue Jan 17, 2020 · 18 comments
Closed

TypeError: Cannot read property 'key' of null on SSR #1728

ksweetie opened this issue Jan 17, 2020 · 18 comments

Comments

@ksweetie
Copy link

ksweetie commented Jan 17, 2020

Current behavior:

Using the css property works on the client, but on SSR gives this error:

Encountered error "#<ExecJS::ProgramError: TypeError: Cannot read property 'key' of null>" when prerendering HelloWorld with {"greeting":"Hello from react-rails."}
insertStyles ((execjs):2165:25)

Related issue: #1185

To reproduce:

The app I'm integrating this in is a Rails app using https://github.com/reactjs/react-rails so I made a repro with it. Hopefully you have ruby installed 🤞.

git clone git@github.com:ksweetie/emotion-ssr.git
cd emotion-ssr/
bundle
yarn
rails s
// visit localhost:3000/foo/foo

Here's a list of files I changed, otherwise it's a stock Rails app. Changing prerender: true to false in foo.html.erb should show that it's working on the client.

app/views/foo/foo.html.erb
app/javascript/components/HelloWorld.tsx
config/webpack/loaders/typescript.js
tsconfig.json
babel.config.js

Expected behavior:

Turning on SSR doesn't give an error.

Environment information:

  • react version: 16.12.0
  • emotion version: 10.0.27
@Andarist
Copy link
Member

This most likely is some configuration issue. Could you join our Slack and DM me there? We could discuss this further in a more prompt fashion.

@jkappers-ga
Copy link

What was the resolution?

@ksweetie
Copy link
Author

@jkappers-ga I never got it working, and unfortunately ran out of time to keep trying. 😕

@jkappers-ga
Copy link

@ksweetie I couldn't get v10 to work, but downgrading to the following versions works for a Rails 6 app, ruby 2.7, and react-rails 2.6.1

  • @emotion/core 10.0.27 -> emotion 9.2.12
  • @emotion/styled 10.0.27 -> react-emotion 9.2.12
  • emotion-theming 10.0.27 -> emotion-theming 9.2.9

@KevinGhadyani-minted
Copy link

KevinGhadyani-minted commented Mar 18, 2020

I was using emotion v10.0.9, and it was working fine. Once I went to v10.0.27, that's when the issue occurred.

The issue is that cache is null in render inside of @emotion/core. So when it calls utils.getRegisteredStyles and utils.insertStyles, it breaks.

The codebase I'm working with is using Enzyme. If I mount, it breaks the test in the same way as the original poster. All css props activate without a cache provider, and it's not creating one.

I believe it's because of this:

var EmotionCacheContext = React.createContext( // we're doing this to avoid preconstruct's dead code elimination in this one case
// because this module is primarily intended for the browser and node
// but it's also required in react native and similar environments sometimes
// and we could have a special build just for that
// but this is much easier and the native packages
// might use a different theme context in the future anyway
typeof HTMLElement !== 'undefined' ? createCache() : null);

Specifically typeof HTMLElement !== 'undefined'. It's not auto-creating a cache when that happens.

@Andarist
Copy link
Member

@KevinGhadyani-minted would you be willing to join our Slack and debug this with me?

@KevinGhadyani-minted
Copy link

Joined.

@jkappers-ga
Copy link

jkappers-ga commented Mar 19, 2020

In case it's useful to help diagnose the issue, we had success using this post_install script as a patch. The SSR build in react-rails had browser set.

#1246 (comment)

/*
https://github.com/emotion-js/emotion/issues/1246#issuecomment-468381891
Monkey patch called postinstall to rename the browser property in ever @emotion/* package so it doesn't get used.
*/

const fs = require('fs')
const { sync } = require('glob')

sync('./node_modules/@emotion/*/package.json').forEach(src => {
  const package = JSON.parse(fs.readFileSync(src, 'utf-8'))
  const browser = package.browser
  delete package.browser
  if (browser) {
    package._browser = browser
  }
  fs.writeFileSync(src, JSON.stringify(package, null, 2))
})

and in package.json

"scripts": {
    "postinstall": "node ./postinstall_patch.js"
}

@johot
Copy link

johot commented Mar 19, 2020

This solved our problems also, we needed to do some SSR using ReactJS.NET (run React components in ASP.NET) and had to build using webpack with target: "web" (the default). The monkey patch works but what also worked for me that doesn't require the monkey patch was setting this in webpack:

resolve: {
    aliasFields: ["module"] // Setting to "main" also works
  },

This tells webpack to use the module or main field instead of the browser field. Could perhaps have effects on other packages though but worked for me... There is also a setting called mainFields in webpack but I am not sure what the difference is between mainField and aliasField, and setting the mainField did not work.

Would be interesting to hear if setting the aliasField works for you also?

@lucat1
Copy link

lucat1 commented Mar 26, 2020

Btw if you want a quick test repo this also happens inside next's with-emotion-11 example. I'd say that's expected as this seems to affect all builds in a node environment

@Andarist
Copy link
Member

@lucat1 this particular problem happens because .10 and .12 prereleases got mixed there and there were some breaking changes in between them, so older version of @emotion/css has been crashing while using newer @emotion/cache. I've prepared a PR to fix this: vercel/next.js#11414

@petrbela
Copy link

petrbela commented May 13, 2020

Just want to confirm that in my case, while using Expo Web, this issue was resolved when I set "@emotion/react": "^11.0.0-next.12",.

Note that currently, due to misaligned tags on npm, running yarn add @emotion/react@next actually installs version ^11.0.0-next.10. At the same time, running yarn add @emotion/native@next installs ^11.0.0-next.12 for the React Native version. You'll need to manually ensure that you installed the same version for both packages. Anyway, looks like this is fixed and any confusion will be resolved by a stable release once it lands.

@Andarist
Copy link
Member

Andarist commented May 14, 2020

Note that currently, due to misaligned tags on npm, running yarn add @emotion/react@next actually installs version ^11.0.0-next.10.

Thanks for mentioning that - it might be a bug in Changesets. Gonna report it over there when I dig a little bit more into this so I can report more details about the issue.

EDIT:// I've diagnosed the issue in Changesets and started working on a fix: changesets/changesets#369

@Andarist
Copy link
Member

I believe that @rails/webpacker when running on a server should create a slightly different webpack config. Based on looking at this file they don't do it. The change to SSR's webpack config is rather trivial - it just should use target: 'node' because the default is target: 'browser', this is described here:
https://webpack.js.org/configuration/target/#string

This is what other SSRing frameworks do, take a look at Gatsby:
https://github.com/gatsbyjs/gatsby/blob/9d7195fff663d3d01131627ab1f03dab1a6553da/packages/gatsby/src/utils/webpack.config.js#L469-L473

Closing this issue as it's not really actionable on our side. I would recommend reporting this to @rails/webpacker

@aaronamm
Copy link

aaronamm commented Jun 7, 2021

@jkappers-ga Thank you so much for the solution. You save my day. It took me many hours to fix this issue.
Your solution works like a charm.

I only need these packages:

    "@emotion/babel-preset-css-prop": "^11.2.0",
     "@emotion/react": "^11.4.0",

Now, I can use css prob in my ReactJS.NET SSR and ASP.NET Core MVC 5 project.

Here is my project code.
https://github.com/codesanook/codesanook-examples/tree/master/Codesanook.Examples.DotNetAuthorizationServer

@V1ruS32
Copy link

V1ruS32 commented Jul 14, 2022

if you are using jsDom or someHow You have defined "document" globally on server side, emotion-element won't recognize that the context is server.
var isBrowser = typeof document !== 'undefined';

@srmagura
Copy link
Member

@V1ruS32 Please open a new issue if that is causing a bug. If you do so, can you explain why document would be defined in a server-side environment?

@V1ruS32
Copy link

V1ruS32 commented Jul 14, 2022

@srmagura I don't think it's a bug. I was defining document globally on server side and I shouldn't do that.

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

No branches or pull requests

10 participants