You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Not compatible with Edge runtime -- throws Module not found: Can't resolve 'os' due to clean-css:
⨯ ../../node_modules/.pnpm/clean-css@5.3.2/node_modules/clean-css/lib/options/format.js:1:22
Module not found: Can't resolve 'os'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
../../node_modules/.pnpm/clean-css@5.3.2/node_modules/clean-css/lib/clean.js
../../node_modules/.pnpm/clean-css@5.3.2/node_modules/clean-css/index.js
../../node_modules/.pnpm/rehype-minify-css-style@4.0.0/node_modules/rehype-minify-css-style/lib/index.js
../../node_modules/.pnpm/rehype-minify-css-style@4.0.0/node_modules/rehype-minify-css-style/index.js
../../node_modules/.pnpm/rehype-preset-minify@7.0.0/node_modules/rehype-preset-minify/index.js
../../node_modules/.pnpm/@jsx-email+render@3.0.1/node_modules/@jsx-email/render/dist/index.mjs
Modification Proposal
I don't know much about what jsx-email is using clean-css for but perhaps there's an alternate library that could be used instead which is compatible with the Edge runtime and only uses web-compatible APIs?
Yeah you'll probably want to take into consideration node polyfills or browserify polyfills for edge environments. We do the same for the preview app as a precaution
I may be wrong here (I'm no expert on the edge runtime) but I don't think there's any straightforward way to add polyfills to an edge runtime environment, at least for next.js. Obviously you could add a build step that transpiles and bundles the code before sending it to the runtime, and there's a webpack bundle step somewhere under the hood in the next build which you may be able to hook into, but it doesn't look documented, stable, or intended for use for something like this.
../../node_modules/.pnpm/uglify-js@3.17.4/node_modules/uglify-js/lib/ast.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Import trace for requested module:
../../node_modules/.pnpm/uglify-js@3.17.4/node_modules/uglify-js/lib/ast.js
../../node_modules/.pnpm/uglify-js@3.17.4/node_modules/uglify-js/tools/node.js
../../node_modules/.pnpm/rehype-minify-event-handler@4.0.0/node_modules/rehype-minify-event-handler/lib/index.js
../../node_modules/.pnpm/rehype-minify-event-handler@4.0.0/node_modules/rehype-minify-event-handler/index.js
../../node_modules/.pnpm/rehype-preset-minify@7.0.0/node_modules/rehype-preset-minify/index.js
../../node_modules/.pnpm/@jsx-email+render@3.0.1/node_modules/@jsx-email/render/dist/index.mjs
./src/auth.ts
This one's a bigger issue as even with polyfills there wouldn't be a way to make eval work.
As far as I can tell, rehype is pretty solidly not edge runtime friendly.
For added context, I'm not even looking to enable the edge runtime in my next.js app -- I'm just looking to use jsx-email to generate login verification emails from next-auth. Since the next-auth config is a common config used in all next-auth functions, and in particular it gets imported into the next.js middleware to generate the authorization middleware, and since next.js middleware must run on the edge runtime, anything imported by the next-auth config must also be compatible with the edge-runtime. In other words, as long as this is an issue, jsx-email can't be used to generate auth emails with next-auth, without doing something screwy like async importing jsx-email in the email generation function (but still avoiding the edge runtime for anything other than middleware).
You could argue that next-auth's config mechanism really should allow splitting things up so we're not pulling deps into environments where they're unused, and I'd agree with you. But fixing this would be awesome regardless because it would be a shame to not be able to use jsx-email in edge environments.
@wooorm worth taking a look here. while rehype wasn't intended to be used on the edge, the prevalence of edge workers (e.g. Cloudflare) is starting to grow and this is probably going to become more of a frequently issue. at the moment it looks like clean-css and uglify are the culprits. investigating terser might be a better path forward there.
@cprussin I'll look into swapping out rehype-minify-* and adding terser back in. wanted to keep all of the actions in the rehype family, but that looks like a new can of worms (no pun intended). if you're up for joining the discord, I'm posted updates there around the move to a single package and the release candidates for those. we're currently at jsx-email@1.0.0-rc3 with rc4 set to drop later today hopefully. Any changes to render will probably go into that, so it's worth giving a shot.
fwiw clean-css is not browser compatible out of the box. it requires extra steps which include running browserify over it. so it's not a good match for us.
@shellscape yeah I'm happy to hop on the discord. I'm also more than happy to contribute some PRs in the appropriate places to help move this along, but I'm not familiar with rehype beyond what I've seen here so at the very least I'd need pointers on where the appropriate place to fix is.
I reached out to the clean-css author and heard back. He's open to a quick fix for the os require, so hopefully we can tick that one off without much fuss. That leaves swapping out uglifyjs
awesome, thanks @shellscape . The soonest I'll get time to hack on this would be this weekend, I'll try to get a PR up to swap out terser for uglifyjs then.
Dynamic require of os in clean-css is just tip of the iceberg. The clean-css/clean-css#1262 still doesn't allow to use clean-css in the edge runtime as far as it contains a lot of fs, path, http, https and url imports. While any of that import is not dynamic this package cannot be used in the edge runtime.
You either need to pick less platform dependent css minifier or put enormous work on making clean-css edge compatible.
Remember that when you are trying to run an application on edge runtime you always see only one dependency that ruins everything. So you mast one-by-one comment/remove each of them to get the whole list what breaks the edge runtime.
Coming from react-email, I'm using cloudflare pages with next-on-pages for my nextjs app, react-email/tailwind package are too large until can't deploy it in cloudflare pages.
So I switch to jsx-email, after amending the code to fit jsx-email, I hit a lot of errors from clean-css:
Module not found: Can't resolve 'fs'
Module not found: Can't resolve 'path'
the v2.0.0 PR is up and gets us closer to where we want to be for edge compat #206
this will let you optionally include the minify plugin. i'm planning a cloudflare integration test following this release (thanks to our friends at SST) which will help guarantee edge compat moving forward.
@JonasDoesThings Cloudflare has greatly improved their node support in wrangler since this issue was opened and jsx-email works within a worker now. I just haven't had time to publish the recipe for a sample setup, so the issue remains open.
Unfortunately that doesn't help the bundle size issue afaict, which is a major concern for latency on workers.
A lite-build that excludes Code (and the dependencies which Code depends on) would be great from that perspective. I'm not sure why the tree shaking doesn't work in workers for it.
@shellscape thx for the quick reply. Maybe the issue is on my end then, but I'm using next 15.1.6 and jsx-email 2.7.0, and getting the following error when trying to use the library (in next dev):
⨯ Error: A Node.js API is used (process.cwd) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
at [project]/node_modules/.pnpm/jsx-email@2.7.0_@jsx-email+plugin-inline@1.0.1_@jsx-email+plugin-minify@1.0.2_@jsx-email+plug_kolylnfkf574iorcipai62x6sm/node_modules/jsx-email/dist/esm/index.js [middleware] (ecmascript) <module evaluation> (.next/server/edge/chunks/dc8e0_jsx-email_dist_esm_652db9._.js:2507:371)
at [project]/src/server/email/index.ts [middleware] (ecmascript) (src/server/email/index.ts:8:0)
at [project]/src/server/auth/index.ts [middleware] (ecmascript) (src/server/auth/index.ts:10:0)
at [project]/src/middleware.ts [middleware] (ecmascript) (src/middleware.ts:2:0)
at <unknown> (edge-wrapper.js:2:6)
6 | });
7 |
> 8 | import {render} from 'jsx-email';
9 | import {SESv2Client, SendEmailCommand} from '@aws-sdk/client-sesv2';
10 | import {type FC, type ReactElement} from 'react';
Ahh I think, it's caused by me importing my sendEmail function (that imports jsx-email's render fn) in my auth.ts file, which is also imported in my middleware to check the user's authentication status.
The middleware has even less nodejs APIs available, so maybe I could split that up, or only dynamically import jsx-email when needed - when it's not running in the middleware.
@JonasDoesThings that does give me an idea though. I can probably make shiki an optional peer dependency. we are already dynamically importing that and I can wrap it in a catch to print a message if the dependency is not installed, and that should get around bundlers which have poor tree shaking. I'll see about adding that this week.
Activity
cprussin commentedon Nov 23, 2023
For what it's worth it does look like clean-css claims to be web-compatible but I don't see how the offending line (https://github.com/clean-css/clean-css/blob/cdd782ba30b84f33b7396b7128c094e7ff1cf4ba/lib/options/format.js#L1) could possibly be web compatible without bundling it with a polyfill.
shellscape commentedon Nov 23, 2023
Yeah you'll probably want to take into consideration node polyfills or browserify polyfills for edge environments. We do the same for the preview app as a precaution
jsx-email/packages/cli/app/vite.config.ts
Line 46 in 3012648
Let us know what you end up using and we'll add it to the docs
cprussin commentedon Nov 24, 2023
I may be wrong here (I'm no expert on the edge runtime) but I don't think there's any straightforward way to add polyfills to an edge runtime environment, at least for next.js. Obviously you could add a build step that transpiles and bundles the code before sending it to the runtime, and there's a webpack bundle step somewhere under the hood in the next build which you may be able to hook into, but it doesn't look documented, stable, or intended for use for something like this.
cprussin commentedon Nov 25, 2023
For what it's worth I also get the following:
This one's a bigger issue as even with polyfills there wouldn't be a way to make eval work.
As far as I can tell, rehype is pretty solidly not edge runtime friendly.
For added context, I'm not even looking to enable the edge runtime in my next.js app -- I'm just looking to use jsx-email to generate login verification emails from next-auth. Since the next-auth config is a common config used in all next-auth functions, and in particular it gets imported into the next.js middleware to generate the authorization middleware, and since next.js middleware must run on the edge runtime, anything imported by the next-auth config must also be compatible with the edge-runtime. In other words, as long as this is an issue, jsx-email can't be used to generate auth emails with next-auth, without doing something screwy like async importing jsx-email in the email generation function (but still avoiding the edge runtime for anything other than middleware).
You could argue that next-auth's config mechanism really should allow splitting things up so we're not pulling deps into environments where they're unused, and I'd agree with you. But fixing this would be awesome regardless because it would be a shame to not be able to use jsx-email in edge environments.
shellscape commentedon Nov 25, 2023
Thanks for the continued investigation. This is all.really helpful.
shellscape commentedon Nov 25, 2023
@wooorm worth taking a look here. while rehype wasn't intended to be used on the edge, the prevalence of edge workers (e.g. Cloudflare) is starting to grow and this is probably going to become more of a frequently issue. at the moment it looks like clean-css and uglify are the culprits. investigating terser might be a better path forward there.
@cprussin I'll look into swapping out
rehype-minify-*and adding terser back in. wanted to keep all of the actions in the rehype family, but that looks like a new can of worms (no pun intended). if you're up for joining the discord, I'm posted updates there around the move to a single package and the release candidates for those. we're currently atjsx-email@1.0.0-rc3withrc4set to drop later today hopefully. Any changes to render will probably go into that, so it's worth giving a shot.fwiw clean-css is not browser compatible out of the box. it requires extra steps which include running browserify over it. so it's not a good match for us.
Side update: Looks like html-minifier-terser also uses clean-css https://github.com/terser/html-minifier-terser/blob/c4a7ae0bd08b1a438d9ca12a229b4cbe93fc016a/package.json#L78
wooorm commentedon Nov 25, 2023
I’m very open to switching to postcss/terser. Only thing I worried about before is that it shouldn’t be a humongous code increase.
cprussin commentedon Nov 25, 2023
@shellscape yeah I'm happy to hop on the discord. I'm also more than happy to contribute some PRs in the appropriate places to help move this along, but I'm not familiar with rehype beyond what I've seen here so at the very least I'd need pointers on where the appropriate place to fix is.
shellscape commentedon Nov 25, 2023
On the rehype side, anywhere uglifyjs is used, terser could be plugged in. Where clean-css is used, https://github.com/cssnano/cssnano could be used. It looks like the only place in the rehype ecosystem those are used is in https://github.com/rehypejs/rehype-minify.
I've also opened this issue as a fallback terser/html-minifier-terser#174
shellscape commentedon Nov 28, 2023
I reached out to the clean-css author and heard back. He's open to a quick fix for the
osrequire, so hopefully we can tick that one off without much fuss. That leaves swapping outuglifyjsshellscape commentedon Nov 30, 2023
jsx-email v1.0.1 is out. still waiting on the publish for clean-css, but I'm being patient there.
cprussin commentedon Nov 30, 2023
awesome, thanks @shellscape . The soonest I'll get time to hack on this would be this weekend, I'll try to get a PR up to swap out terser for uglifyjs then.
msereniti commentedon Dec 1, 2023
Dynamic require of
osin clean-css is just tip of the iceberg. The clean-css/clean-css#1262 still doesn't allow to use clean-css in the edge runtime as far as it contains a lot offs,path,http,httpsandurlimports. While any of that import is not dynamic this package cannot be used in the edge runtime.You either need to pick less platform dependent css minifier or put enormous work on making clean-css edge compatible.
msereniti commentedon Dec 1, 2023
Also, I must add that to make the library work on edge runtime alongside the incompatible dependencies of
rehype-preset-minifyyou need to deal withshikijihttps://github.com/shellscape/jsx-email/blob/b8b44ff7472f13698f2674d53892402f6f6269a7/packages/jsx-email/src/components/code.tsx#L3C1-L3C1. It's also doesn't work on edge runtime.Remember that when you are trying to run an application on edge runtime you always see only one dependency that ruins everything. So you mast one-by-one comment/remove each of them to get the whole list what breaks the edge runtime.
wooorm commentedon Dec 1, 2023
starry-nightshould work everywhere, and be similar enough to shikiji38 remaining items
sisheng1998 commentedon Jul 10, 2024
Coming from react-email, I'm using cloudflare pages with next-on-pages for my nextjs app, react-email/tailwind package are too large until can't deploy it in cloudflare pages.
So I switch to jsx-email, after amending the code to fit jsx-email, I hit a lot of errors from clean-css:
Module not found: Can't resolve 'fs'
Module not found: Can't resolve 'path'
Any idea on how to fix this?
shellscape commentedon Jul 15, 2024
@sisheng1998 this entire issue is about getting the package to work correctly on the edge. I suggest you read the entire thread.
shellscape commentedon Sep 14, 2024
the v2.0.0 PR is up and gets us closer to where we want to be for edge compat #206
this will let you optionally include the minify plugin. i'm planning a cloudflare integration test following this release (thanks to our friends at SST) which will help guarantee edge compat moving forward.
shellscape commentedon Oct 4, 2024
v2 release will happen around 1PM ET tomorrow. A Cloudflare recipe and direct support will be my top priority afterwards.
shellscape commentedon Oct 16, 2024
v2 is out the door and we've got the major version bumps behind us. This is now first up on my priority list.
shellscape commentedon Oct 16, 2024
Seems that Cloudflare has added a lot more compatibility for Workers: https://blog.cloudflare.com/more-npm-packages-on-cloudflare-workers-combining-polyfills-and-native-code/. Will be testing this out pronto.
JonasDoesThings commentedon Feb 2, 2025
Hi, is there a current workaround or working up-to-date patch available?
shellscape commentedon Feb 2, 2025
@JonasDoesThings Cloudflare has greatly improved their node support in wrangler since this issue was opened and jsx-email works within a worker now. I just haven't had time to publish the recipe for a sample setup, so the issue remains open.
johnpyp commentedon Feb 2, 2025
Unfortunately that doesn't help the bundle size issue afaict, which is a major concern for latency on workers.
A lite-build that excludes Code (and the dependencies which Code depends on) would be great from that perspective. I'm not sure why the tree shaking doesn't work in workers for it.
JonasDoesThings commentedon Feb 2, 2025
@shellscape thx for the quick reply. Maybe the issue is on my end then, but I'm using next 15.1.6 and jsx-email 2.7.0, and getting the following error when trying to use the library (in
next dev):Do you have an idea?
johnpyp commentedon Feb 2, 2025
The Vercel edge runtime is a whole other ballgame too, which looks to be what you're running into.
JonasDoesThings commentedon Feb 2, 2025
Ahh I think, it's caused by me importing my sendEmail function (that imports jsx-email's render fn) in my auth.ts file, which is also imported in my middleware to check the user's authentication status.
The middleware has even less nodejs APIs available, so maybe I could split that up, or only dynamically import jsx-email when needed - when it's not running in the middleware.
So probably my fault, and not jsx-email's 😅
shellscape commentedon Feb 2, 2025
@JonasDoesThings that does give me an idea though. I can probably make shiki an optional peer dependency. we are already dynamically importing that and I can wrap it in a catch to print a message if the dependency is not installed, and that should get around bundlers which have poor tree shaking. I'll see about adding that this week.
techo207 commentedon May 28, 2026
any idea how to render an email using storybook
shellscape commentedon May 28, 2026
@techo207 this issue is about edge runtimes, not storybook. you should open a new discussion in Q&A or stop by the discord and ask howtos.