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: https://github.com/emotion-js/emotion/issues/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 [email protected]: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.0emotion version: 10.0.27This 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.
What was the resolution?
@jkappers-ga I never got it working, and unfortunately ran out of time to keep trying. 馃槙
@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
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.
@KevinGhadyani-minted would you be willing to join our Slack and debug this with me?
Joined.
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.
https://github.com/emotion-js/emotion/issues/1246#issuecomment-468381891
/*
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"
}
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?
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
@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: https://github.com/zeit/next.js/pull/11414
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.
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: https://github.com/atlassian/changesets/pull/369
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
Most helpful comment
I was using emotion
v10.0.9, and it was working fine. Once I went tov10.0.27, that's when the issue occurred.The issue is that
cacheisnullinrenderinside of@emotion/core. So when it callsutils.getRegisteredStylesandutils.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. Allcssprops activate without a cache provider, and it's not creating one.I believe it's because of this:
Specifically
typeof HTMLElement !== 'undefined'. It's not auto-creating a cache when that happens.