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

Add support for Cloudflare Worker environment in @emotion/cache, @emotion/styled, @emotion/react, and @emotion/server #2554

Closed
tbrockman opened this issue Nov 19, 2021 · 23 comments · Fixed by #2819

Comments

@tbrockman
Copy link

tbrockman commented Nov 19, 2021

Some discussion of the issue in the emotion Slack channel.

Current behavior:

Attempting to render a React application using emotion as guided by the documentation will result in the Cloudflare Worker immediately crashing, as described here.

This is because stream is not present in a Worker environment.

After removing the code in @emotion/server which imports which indirectly imports stream through through, the Worker will no longer immediate crash on startup, but will throw an error on rendering:

ReferenceError: document is not defined
    at createCache (./index.mjs:1173:38)
    at handleRequest (./index.mjs:2241:19)
    at Object.fetch (./index.mjs:2236:22) at line 1172, col 36

This is due to the Worker bundler targeting the browser. Rollup (webpack untested) will optimize away isBrowser checks (as it should always be true), which still leaves references to document, which is undefined in the Worker environment. This issue is also described here. Hardcoding isBrowser = false results in successful rendering.

To reproduce:

Clone this Github repository and follow the README.

Expected behavior:

Ideally, emotion + react + SSR should work within Workers.

Environment information:

  • react version: 17.0.2
  • @emotion/react version: 11.6.0
  • @emotion/server version: 11.4.0
  • @emotion/cache version: 11.6.0
  • @emotion/styled version: 11.6.0
@tbrockman tbrockman changed the title Add support for Cloudflare Workers in @emotion/cache, @emotion/styled, @emotion/react, and @emotion/server Add support for Cloudflare Worker environment in @emotion/cache, @emotion/styled, @emotion/react, and @emotion/server Nov 19, 2021
@Andarist
Copy link
Member

Hardcoding isBrowser = false results in successful rendering.

I wonder - in which file do you patch this variable? with nodeResolve({ browser: true }) I would expect it to pick up a file that doesnt have this in its code because a browser file already inlines such checks as those file target browser and thus this doesnt have to be checked at runtime 🤔

@tbrockman
Copy link
Author

Not sure if I understand the question entirely, but I made the changes directly in emotion/utils and the other emotion packages with similar let isBrowser = typeof document !== 'undefined' references, then built and published versions to my local registry.

@Andarist
Copy link
Member

Ah, ok - this makes more sense now. I've thought that you patched your node_modules somehow and wasn't sure how you have made it work given the minimal changes that you have described.

@dan-lee
Copy link

dan-lee commented Nov 24, 2021

@tbrockman do you think you can provide the changes you've made? I'd love it if you could share them :)
I probably would use patch-package to get them in

@Andarist
Copy link
Member

@dan-lee u could try removing the browser field from our package.json files. There is a chance that this would work

@dan-lee
Copy link

dan-lee commented Nov 24, 2021

@Andarist thanks, that's good suggestion and actually seems to work! Unfortunately patch-package doesn't patch the files after the fact after they're installed.
Seems like I need to come up with my own postinstall script. This is not ideal but would make it work at least

@Andarist
Copy link
Member

Hm, this might depend on the package manager. If you already have Emotion installed then having:

"postinstall": "patch-package"

should usually be enough

@dan-lee
Copy link

dan-lee commented Nov 24, 2021

Unfortunately, it doesn't work (with yarn). Might be this issue though ds300/patch-package#49

@Andarist
Copy link
Member

You might want to take a look at this: https://github.com/ds300/patch-package#yarn

@nicksrandall
Copy link
Contributor

nicksrandall commented Dec 10, 2021

Update: I have a PR into preconstruct (which emotion uses to build its packages) to support "custom package exports conditionals" -- including support for a new "worker" conditional that can be used for Cloudflare worker style environments.

I also have a PR to emotion (currently in draft mode) that uses this new version of precontruct to enable package exports on all the relevant packages, including the new "worker" conditional.

Finally, I have a super simple Cloudflare Worker deployed using the updated emotion packages and it works!

@chasoft
Copy link

chasoft commented Feb 8, 2022

I got the same issue when trying to integrate emotion to Remix!

If i use

const { extractCriticalToChunks } = createEmotionServer(cache)

then, i would get following error

image

if i remove createEmotionServer, then, i got following error

image

@pavi2410
Copy link

pavi2410 commented Feb 9, 2022

I got the same issue when trying to integrate emotion to Remix!

If i use

const { extractCriticalToChunks } = createEmotionServer(cache)

then, i would get following error

image

if i remove createEmotionServer, then, i got following error

image

Exactly the same issue for me as well.

Is it possible to disable emotion SSR?

@aiji42
Copy link

aiji42 commented Feb 9, 2022

@chasoft @pavi2410 Hi, this is a repository of samples for running Remix and emotion with cloudflare workers. Please refer to this sample to get by until this issue is resolved.
https://github.com/aiji42/remix-emotion-on-cloudflare#conform-to-emotion

I hope this is helpful to you.

@dan-cooke
Copy link

dan-cooke commented Feb 11, 2022

Temporary patch to get remix + Cloudflare pages + emotion playing nice

Using @aiji42 fanastic solution for getting Cloudflare Workers + emotion.

I have extended it for wrangler to get emotion working with Cloudflare Pages

Heres how:

  1. Patch remix-run
    patches/@remix-run+dev+1.1.3.patch
diff --git a/node_modules/@remix-run/dev/compiler.js b/node_modules/@remix-run/dev/compiler.js
index 1a6cabc..3cf652f 100644
--- a/node_modules/@remix-run/dev/compiler.js
+++ b/node_modules/@remix-run/dev/compiler.js
@@ -297,6 +297,7 @@ async function createBrowserBuild(config, options) {
     platform: "browser",
     format: "esm",
     external: externals,
+    jsxFactory: "jsx",
     inject: [reactShim],
     loader: loaders.loaders,
     bundle: true,
@@ -329,6 +330,7 @@ async function createServerBuild(config, options) {
     format: config.serverModuleFormat,
     mainFields: config.serverModuleFormat === "esm" ? ["module", "main"] : ["main", "module"],
     target: options.target,
+    jsxFactory: "jsx",
     inject: [reactShim],
     loader: loaders.loaders,
     bundle: true,
diff --git a/node_modules/@remix-run/dev/compiler/shims/react.ts b/node_modules/@remix-run/dev/compiler/shims/react.ts
index eb0f102..b86e5da 100644
--- a/node_modules/@remix-run/dev/compiler/shims/react.ts
+++ b/node_modules/@remix-run/dev/compiler/shims/react.ts
@@ -1,2 +1,3 @@
+import { jsx } from "@emotion/react";
 import * as React from "react";
-export { React };
+export { jsx, React };
  1. Patch wrangler
    patches/wrangler+0.0.0-78acd24
diff --git a/node_modules/wrangler/wrangler-dist/cli.js b/node_modules/wrangler/wrangler-dist/cli.js
index a4a2148..f297c4f 100644
--- a/node_modules/wrangler/wrangler-dist/cli.js
+++ b/node_modules/wrangler/wrangler-dist/cli.js
@@ -136277,6 +136277,7 @@ var import_node_path14 = require("node:path");
 var import_node_url8 = require("node:url");
 var import_chokidar2 = __toESM(require_chokidar());
 var import_mime = __toESM(require_mime2());
+var alias = require('esbuild-plugin-alias');
 
 // pages/functions/buildWorker.ts
 init_import_meta_url();
@@ -136324,7 +136325,14 @@ function buildWorker({
             }
           });
         }
-      }
+      },
+      alias({
+        'through': require.resolve('no-op'),
+        'html-tokenize': require.resolve('no-op'),
+        'multipipe': require.resolve('no-op'),
+        '@emotion/react': require.resolve('@emotion/react'),
+        '@emotion/cache': require.resolve('@emotion/cache'),
+      })
     ]
   });
 }
  1. Extend postinstall script to run npx patch-package
    "postinstall": "remix setup cloudflare-pages && npx patch-package",

@Hamatek
Copy link

Hamatek commented Feb 14, 2022

@chasoft @pavi2410 Hi, this is a repository of samples for running Remix and emotion with cloudflare workers. Please refer to this sample to get by until this issue is resolved. https://github.com/aiji42/remix-emotion-on-cloudflare#conform-to-emotion

I hope this is helpful to you.

Thank you @aiji42 for making and sharing this

@pavi2410
Copy link

pavi2410 commented Feb 14, 2022

Thanks @aiji42 @dan-cooke

However, I went with this patch as this was simple and doesn't change code much (I was afraid of the breaking changes that we may not notice).

diff --git a/node_modules/@emotion/cache/package.json b/node_modules/@emotion/cache/package.json
index 437f0bf..c74881a 100644
--- a/node_modules/@emotion/cache/package.json
+++ b/node_modules/@emotion/cache/package.json
@@ -4,10 +4,6 @@
   "description": "emotion's cache",
   "main": "dist/emotion-cache.cjs.js",
   "module": "dist/emotion-cache.esm.js",
-  "browser": {
-    "./dist/emotion-cache.cjs.js": "./dist/emotion-cache.browser.cjs.js",
-    "./dist/emotion-cache.esm.js": "./dist/emotion-cache.browser.esm.js"
-  },
   "types": "types/index.d.ts",
   "license": "MIT",
   "repository": "https://github.com/emotion-js/emotion/tree/main/packages/cache",

@chasoft
Copy link

chasoft commented Feb 16, 2022

Temporary patch to get remix + Cloudflare pages + emotion playing nice

Using @aiji42 fanastic solution for getting Cloudflare Workers + emotion.

I have extended it for wrangler to get emotion working with Cloudflare Pages

Heres how:

  1. Patch remix-run
    patches/@remix-run+dev+1.1.3.patch
diff --git a/node_modules/@remix-run/dev/compiler.js b/node_modules/@remix-run/dev/compiler.js
index 1a6cabc..3cf652f 100644
--- a/node_modules/@remix-run/dev/compiler.js
+++ b/node_modules/@remix-run/dev/compiler.js
@@ -297,6 +297,7 @@ async function createBrowserBuild(config, options) {
     platform: "browser",
     format: "esm",
     external: externals,
+    jsxFactory: "jsx",
     inject: [reactShim],
     loader: loaders.loaders,
     bundle: true,
@@ -329,6 +330,7 @@ async function createServerBuild(config, options) {
     format: config.serverModuleFormat,
     mainFields: config.serverModuleFormat === "esm" ? ["module", "main"] : ["main", "module"],
     target: options.target,
+    jsxFactory: "jsx",
     inject: [reactShim],
     loader: loaders.loaders,
     bundle: true,
diff --git a/node_modules/@remix-run/dev/compiler/shims/react.ts b/node_modules/@remix-run/dev/compiler/shims/react.ts
index eb0f102..b86e5da 100644
--- a/node_modules/@remix-run/dev/compiler/shims/react.ts
+++ b/node_modules/@remix-run/dev/compiler/shims/react.ts
@@ -1,2 +1,3 @@
+import { jsx } from "@emotion/react";
 import * as React from "react";
-export { React };
+export { jsx, React };
  1. Patch wrangler
    patches/wrangler+0.0.0-78acd24
diff --git a/node_modules/wrangler/wrangler-dist/cli.js b/node_modules/wrangler/wrangler-dist/cli.js
index a4a2148..f297c4f 100644
--- a/node_modules/wrangler/wrangler-dist/cli.js
+++ b/node_modules/wrangler/wrangler-dist/cli.js
@@ -136277,6 +136277,7 @@ var import_node_path14 = require("node:path");
 var import_node_url8 = require("node:url");
 var import_chokidar2 = __toESM(require_chokidar());
 var import_mime = __toESM(require_mime2());
+var alias = require('esbuild-plugin-alias');
 
 // pages/functions/buildWorker.ts
 init_import_meta_url();
@@ -136324,7 +136325,14 @@ function buildWorker({
             }
           });
         }
-      }
+      },
+      alias({
+        'through': require.resolve('no-op'),
+        'html-tokenize': require.resolve('no-op'),
+        'multipipe': require.resolve('no-op'),
+        '@emotion/react': require.resolve('@emotion/react'),
+        '@emotion/cache': require.resolve('@emotion/cache'),
+      })
     ]
   });
 }
  1. Extend postinstall script to run npx patch-package
    "postinstall": "remix setup cloudflare-pages && npx patch-package",

it works in dev env, and can be deploy to Cloudflare Pages...

21:29:13.758 | Executing user command: npm run build
21:29:14.196 | patch-package 6.4.7
21:29:14.197 | Applying patches...
21:29:14.202 | @remix-run/dev@1.1.3 ✔
21:29:14.265 | wrangler@0.0.0-536c7e5 ✔
21:29:14.532 |  
21:29:14.532 | > build
21:29:14.532 | > cross-env NODE_ENV=production remix build
21:29:14.532 |  
21:29:14.807 | Building Remix app in production mode...
21:29:15.360 | Built in 553ms
21:29:15.374 | Finished
21:29:16.045 | Compiled Worker successfully.
21:29:16.058 | Validating asset output directory
21:29:16.457 | Deploying your site to Cloudflare's global network...
21:29:23.242 | Success: Your site was deployed!

but i facing new runtime error Unexpected Server Error

image

Do I miss anything? How about your experience?

@Shaquu
Copy link

Shaquu commented Mar 10, 2022

Hi, I have the same issue.
Tried all above and no success.

To @aiji42 @dan-cooke @pavi2410, can you please share more? Possibly it is dependent on some other files.

@aiji42
Copy link

aiji42 commented Mar 13, 2022

@Shaquu
The latest version of Remix has changed the server-side build process, so it is no longer possible to plug in esbuild custom scripts. Therefore, the method I presented previously does not solve the problem.
Here is how to make emotion compliant with the latest Remix.

@sinitsa
Copy link

sinitsa commented Mar 13, 2022

It's works for me only partially .... It's fix all these errors but another one happened -

[mf:err] ReferenceError: process is not defined
at /Users/havok/Work/lawsvc/packages/ccremix/dist/worker.mjs:54:97064
at /Users/havok/Work/lawsvc/packages/ccremix/dist/worker.mjs:54:97081

as i see its call to process.argv - but i cannot find any source of it!! who put it into worker??? how to fix it????

@ItsWendell
Copy link
Contributor

ItsWendell commented Jun 30, 2022

This is also super relevant for the Next.js Edge Runtime now (which is essentially built Cloudflare Worker): #2777, #2554

@osdiab
Copy link
Contributor

osdiab commented Sep 5, 2022

@Andarist how would one use the patch above to make emotion work in this context? Thanks!

@Andarist
Copy link
Member

Andarist commented Sep 5, 2022

Please prepare a runnable example of the problem with all required steps to setup everything. I will try to find the time to look into this if such is provided

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

Successfully merging a pull request may close this issue.