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

Compatibility with server-side Web API runtimes: Next.js Edge Runtime, Deno, Cloudflare Workers / Pages. #2801

Open
ItsWendell opened this issue Jun 30, 2022 · 16 comments

Comments

@ItsWendell
Copy link
Contributor

ItsWendell commented Jun 30, 2022

The problem

Next.js recently released Edge Runtime in version 12.2 as an experimental feature, this includes doing serverside rendering on the edge in a different runtime than Node.js. It's a runtime similar to Deno and Cloudflare Workers / Pages, they're built on the v8 browser engine, for the server.

I've experimented with running the with-emotion-swc-app example with the Experimental Edge runtime enabled, which initially caused the following issue:

error - node_modules/.pnpm/@emotion+cache@11.9.3/node_modules/@emotion/cache/dist/emotion-cache.browser.esm.js (245:0) @ <unknown>
ReferenceError: document is not defined

The compiler/bundler loads by default the .browser version of the build output of @chakra-ui/cache, this output doesn't have the isBrowser checks that the regular outputs have (since it assumes it's already in the browser). This was initially fixed for me locally when I manually replaced the .browser.esm.js file with the regular .esm.js file.

Proposed solution

  • Add isBrowser checks to browser bundles
  • Check for available Web API alternatives instead of node APIs, if available use those in all @emotion packages.

Supporting these runtimes would greatly benefit the ecosystem and allow users of Emotion, and everything built on top of it, to use Emotion in newer runtimes and frameworks like Deno (Fresh), Next.js Edge Runtime, and Cloudflare Workers.

@ItsWendell
Copy link
Contributor Author

This is probably related to this: #2777

@srmagura
Copy link
Member

There has been some work on this here: #2589. It is targeting Cloudflare Workers, but I assume there is considerable overlap with supporting the Next.js Edge Runtime.

@ItsWendell
Copy link
Contributor Author

@srmagura that's amazing, the Next.js Edge Runtime is actually confirmed to be built on Cloudflare Workers (at this time). So both should work here.

@ItsWendell
Copy link
Contributor Author

ItsWendell commented Aug 1, 2022

I've quickly tested this with the latest version of Emotion (#2589), since the worker runtime should have the same APIs as the Edge Runtime of Verce / Next.js.

I've created a repository here to quickly demonstrate the errors that showup:
https://github.com/ItsWendell/next-edge-runtime-chakra-ui-emotion

There's a couple of things that seem to go wrong here:

Next.js is having issues with body streams, but doesn't seem to be affecting the rest of the render process.

error - node_modules/next/dist/server/body-streams.js (43:0) @ eval
error - unhandledRejection: Cannot read properties of null (reading 'on')

Emotion is having issues with its cache and is loading the browser bundle instead of the worker bundle, which might actually fix this issue.

ReferenceError: document is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
<unknown>
node_modules/@emotion/cache/dist/emotion-cache.browser.esm.js (199:0)
eval
node_modules/@emotion/cache/dist/emotion-cache.browser.esm.js (199:0)
Server Error
TypeError: Cannot read properties of null (reading 'registered')

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
eval
webpack-internal:///./node_modules/@emotion/styled/base/dist/emotion-styled-base.browser.esm.js (142:134)
eval
webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-cbed451f.browser.esm.js (58:12)

Would love to see what it requires to make Emotion plug and play for the Edge Runtime of Next.js / Vercel too!

I've added a similar issue at Next.js too see if this is something they could fix with their compiler / bundler. vercel/next.js#39229

@Andarist
Copy link
Member

Andarist commented Aug 2, 2022

Emotion is having issues with its cache and is loading the browser bundle instead of the worker bundle, which might actually fix this issue.

Hm, it seems that we have forgotten to add a worker condition to @emotion/cache. Happy to accept a PR fixing this.

Actually... I'm going to release a new version with this condition in a moment.

Next.js is having issues with body streams, but doesn't seem to be affecting the rest of the render process.

Would be cool to get more info about this to assess where the problem is.

@Andarist
Copy link
Member

Andarist commented Aug 2, 2022

It's weird though that @emotion/styled and @emotion/react also loaded browser bundles in this case - I've expected worker bundles to be loaded for those.

@ItsWendell
Copy link
Contributor Author

Since Next.js Edge Runtime is sort of of a hybrid model, you can choose per page / endpoint which runtime you want to use, I'm not sure how their compiler handles importing the right modules, it at least seems to attempt browser modules, but worker would be even better here. That's also why I opened an issue at Next.js!

@Andarist
Copy link
Member

Andarist commented Aug 2, 2022

Did you have a chance to test this out with the new release of @emotion/cache?

@ItsWendell
Copy link
Contributor Author

@Andarist I just tested the latest version on the Next.js Ege Runtime. As we're discussing in vercel/next.js#39229, the browser bundle is still being loaded. If I manually replace the browser bundle with the worker bundle, it works without crashes, but the styles are not loading.

I did this by directly editing node_modules, removing the next.js cache (removing the .next folder), and rerunning the application.

If I manually replace the browser bundle with the regular ESM bundle, it actually works.

See these screenshots:

Using emotion-cache.worker.esm.js:
https://imgur.com/a/9C0e1N2

Using emotion-cache.esm.js:
https://imgur.com/a/W5oikU8

@Andarist
Copy link
Member

Andarist commented Aug 2, 2022

Could you tell me what HTML got flushed to the browser when using the worker bundle?

@ItsWendell
Copy link
Contributor Author

@Andarist I actually just made this work with a little custom webpack configuration for conditionNames on the package.json exports. Initially, I had some style hydration issue because of the custom cache but that now actually seems to work properly, a very basic implementation of Chakra uI also works with this.

Here's the update I just did: ItsWendell/next-edge-runtime-chakra-ui-emotion@8d6b389

With the /chakra URL / demo on this repository, I'm actually getting some hydration / SSR-related warnings/issues from Next.js, like Text content does not match server-rendered HTML. errors, but that could also very well be an issue with Chakra UI.

@Andarist
Copy link
Member

Andarist commented Aug 3, 2022

With the /chakra URL / demo on this repository, I'm actually getting some hydration / SSR-related warnings/issues from Next.js, like Text content does not match server-rendered HTML. errors, but that could also very well be an issue with Chakra UI.

Yeah, we are not really that concerned with the text content so I don't think that the hydration mismatch comes from Emotion itself.

To sum it up... it feels like there is nothing actionable on our side here, right? The only problem is that this doesn't work out of the box with Next.js as they don't use the worker condition by default (and instead they prefer browser which is also a potentially questionable choice here).

@Andarist
Copy link
Member

There are some new APIs~ coming to React in the future. In the face of those possibilities, I'm not sure if it's worth working on a custom streaming solution: https://twitter.com/joshcstory/status/1559482199388426240

Maybe we could work on a custom stream transformer, but I would be hesitant to add any code to Emotion itself (I mean our components etc) to support this.

@akazwz
Copy link

akazwz commented Oct 8, 2022

No plan for this?

@mwskwong
Copy link

@Andarist I actually just made this work with a little custom webpack configuration for conditionNames on the package.json exports. Initially, I had some style hydration issue because of the custom cache but that now actually seems to work properly, a very basic implementation of Chakra uI also works with this.

Here's the update I just did: ItsWendell/next-edge-runtime-chakra-ui-emotion@8d6b389

With the /chakra URL / demo on this repository, I'm actually getting some hydration / SSR-related warnings/issues from Next.js, like Text content does not match server-rendered HTML. errors, but that could also very well be an issue with Chakra UI.

Tried your workaround, doesn't seem to be working anymore after upgrading Next.js to a newer version (not only 13, but also 12.x).

@tyteen4a03
Copy link

@joacub @beast911 Since you two have offered to help I thought I'd x-tag you here in case your company is able to support.

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

6 participants