emotion: @emotion/server crash on import in Worker environment
Current behavior:
Looks like @emotion/server always assumes a Node.js environment. However, it is now possible to do SSR in Workers environment (such as Cloudflare Workers). This package breaks on import because some dependencies (html-tokenize) try to access Buffer, Stream, and other Node-only APIs.
I’ve tried to get some of the problems fixed: https://github.com/LinusU/buffer-from/issues/13
However, html-tokenize have other issues.
To reproduce:
Run import createEmotionServer from '@emotion/server/create-instance' in a worker or a browser environment.
It cannot be reproduced in Codesandbox because looks like they add some Node API polyfills (Buffer, etc).
Expected behavior:
It should not crash on import. More specifically, it would be great if there was an ESM build or a way to import only the necessary functions. For example, importing createExtractCriticalToChunks and createConstructStyleTagsFromChunks, and leaving out createRenderStylesToStream, which is the one causing problems and not needed for this use case.
Right now I have this code, which works in Node but not in workers.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 18
- Comments: 19 (6 by maintainers)
Our eventual solution was to replace
@emotion/serverwith a “vendored” package in our monorepo.package.jsonindex.d.tsindex.jsThis exports a
createEmotionServerthat is a drop-in replacement for@emotion/server/create-instancein a web worker environment. It’s functionally identical to the actual package, just without the Node.js-only parts we don’t use.For others who might need a little extra guidance and building on the work of @aaronadamsCA
Create new directory
/app/vendor/@emotion/serverAdd
index.tsin this directory/app/vendor/@emotion/server/index.ts
/app/entry.server.tsxto use the new Emotion server/app.entry.server.tsx
@aaronadamsCA Thanks! I’m using Chakra-UI in a Remix project (specifically a Hydrogen Shopify app) and had the same issue. The workaround is very helpful.
So from my understanding currently the only workaround is by serving the content as a string with
renderToStringand add the emotion styles in the string. There are no workarounds if we need to userenderToReadableStream, correct?@aaronadamsCA thanks! This works like charm!
I’d prefer not to mix ESM with require - it’s a can of worms that I prefer closed ;p
We probably can’t do that because this would taint the whole function - it would have to become
asyncand that would be a breaking change.Ah, ye - I can see that. We need to restructure our package a little bit or provide different bundles for specific environments. This might require some changes in our bundling solution (https://github.com/preconstruct/preconstruct/) to make it all work.
It’s on the “roadmap”. However, lately, I don’t get as much free time for OSS as I used to have and I’m not certain when I will be able to actually work on this.
@Andarist You guessed right!
html-tokenizeis heavily dependent on Node.js. I’ve tried polyfilling its various needs to get it to run in a worker environment, without success; it gets upset with the absence ofBuffer, and doesn’t seem to tolerate a polyfill.html-tokenizeappears to be a dead project; the last major release was in 2016 (with one dependency update in 2020). I think the only way forward here would be to get rid of that dependency; the discussion in #2781 seems to be on the right track.