Cannot use @react-email/components with Cloudflare
Describe the Bug
I keep getting error with Publish to Cloudflare Pages with Github Actions when using the @react-email/components.
Which package is affected (leave empty if unsure)
@react-email/components
Link to the code that reproduces this issue
no link
To Reproduce
Run cloudflare/pages-action@v1
npm warn exec The following package was not found and will be installed: [email protected]
npm warn deprecated [email protected]: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
npm warn deprecated [email protected]: Please use @jridgewell/sourcemap-codec instead
Delegating to locally-installed [email protected] over global [email protected]...
Run `npx wrangler pages publish ./build/client --project-name=web-starter-cloudflare --branch=main` to use the local version directly.
â–² [WARNING] `wrangler pages publish` is deprecated and will be removed in the next major version.
Please use `wrangler pages deploy` instead, which accepts exactly the same arguments.
✨ Compiled Worker successfully
Uploading... (9/9)
✨ Success! Uploaded 0 files (9 already uploaded) (0.30 sec)
✨ Uploading _headers
✨ Uploading Functions bundle
✨ Uploading _routes.json
🌎 Deploying...
✘ [ERROR] Deployment failed!
Failed to publish your Function. Got error: Error: Script startup exceeded CPU time limit.
🪵 Logs were written to "/home/runner/.config/.wrangler/logs/wrangler-2024-06-16_03-00-22_546.log"
npm notice
npm notice New minor version of npm available! [10](https://github.com/colesanderson/web-starter-cloudflare/actions/runs/9532835999/job/26275393016#step:6:11).7.0 -> 10.8.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.1
npm notice To update run: npm install -g [email protected]
npm notice
EXIT WHEN NOT EXPECTED
SHELLAC COMMAND FAILED!
Executing: npx wrangler@2 pages publish "./build/client" --project-name="web-starter-cloudflare" --branch="main" in /home/runner/work/web-starter-cloudflare/web-starter-cloudflare
STDOUT:
Delegating to locally-installed [email protected] over global [email protected]...
Run `npx wrangler pages publish ./build/client --project-name=web-starter-cloudflare --branch=main` to use the local version directly.
✨ Compiled Worker successfully
Uploading... (9/9)
✨ Success! Uploaded 0 files (9 already uploaded) (0.30 sec)
✨ Uploading _headers
✨ Uploading Functions bundle
✨ Uploading _routes.json
🌎 Deploying...
STDERR:
npm warn exec The following package was not found and will be installed: [email protected]
npm warn deprecated [email protected]: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
npm warn deprecated [email protected]: Please use @jridgewell/sourcemap-codec instead
â–² [WARNING] `wrangler pages publish` is deprecated and will be removed in the next major version.
Please use `wrangler pages deploy` instead, which accepts exactly the same arguments.
✘ [ERROR] Deployment failed!
Failed to publish your Function. Got error: Error: Script startup exceeded CPU time limit.
🪵 Logs were written to "/home/runner/.config/.wrangler/logs/wrangler-2024-06-[16](https://github.com/colesanderson/web-starter-cloudflare/actions/runs/9532835999/job/26275393016#step:6:17)_03-00-22_546.log"
npm notice
npm notice New minor version of npm available! 10.7.0 -> 10.8.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.1
npm notice To update run: npm install -g [email protected]
npm notice
node:internal/process/promises:279
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#<Object>".] {
code: 'ERR_UNHANDLED_REJECTION'
}
Code
import { json } from "@remix-run/cloudflare";
import { Resend } from "resend";
import { render } from "@react-email/render";
import { Button } from "@react-email/components";
export async function action(args: ActionFunctionArgs) {
const { request, context } = args;
const { env } = context.cloudflare;
const resend = new Resend(env.RESEND_EMAIL);
const Foo = () => (
<Button href="https://example.com" style={{ color: "#61dafb" }}>
Click me
</Button>
);
const emailHtml = render(<Foo />);
try {
// Sending an email using the Resend API
const { error } = await resend.emails.send({
from: `Person <${defaultEmail}>`,
reply_to: email,
to: [defaultEmail],
subject: "Form Submission",
html: emailHtml,
// render: <Foo /> // tried this too
});
if (error) {
throw new Error("Failed to send email");
}
return json({ success: true, message: "Email sent successfully!" });
} catch (error) {
return json({ error: (error as Error).message }, 400);
}
}
export default function Contact() {
return <Contact />;
}
Expected Behavior
Expecting for deploy to work or output more helpful error?
What's your node version? (if relevant)
v20.10.0
Please, make a proper minimal reproduction here. This might be caused by various things and to properly narrow down what is wrong, I wanted something that I could quickly use to reproduce your issue.
Hey @gabrielmfern
- npm create cloudflare@latest my-remix-app -- --framework=remix
- Install resend, @react-email/render, @react-email/components
- Create a simple component using @react-email/components, can copy from https://demo.react.email/preview/notifications/vercel-invite-user?view=source
- Deploy to cloudflare
- Getting deploy error
What version of render are you on?
the newest version of render, I also tried with
resend.emails.send({
react: <ContactEmail name={name} email={email} message={message} />,
});
and
const emailHtml = ReactDOMServer.renderToString(<ContactEmail name={name} email={email} phone={phone} message={message} />);
const { error } = await resend.emails.send({
html: emailHtml,
});
Got a reproduction going, and it seems like installing the individual packages makes the error go away. Not sure exactly what might be causing this, if it's the exports that components does, or if it's because of Tailwind itself being so large at the moment.
Does not seem related to resend at all as well, as I could reproduce with just an action that renders the email template.
This seems to be caused by Tailwind by trying to import the components individually until it errors on deploy. Pretty sure this is equivalent to #1101 and should be fixed by #1383.
Any ETA for #1383 to complete? I'm also facing the same issue with Cloudflare pages, it is related to the Tailwind package too large. The size of the script already exceeded 3 MB and can't deploy it to Cloudflare pages.
Having the same problem here when deploying to Cloudflare Pages:
Error: Script startup exceeded CPU time limit.
I believe some work is being done in the global scope and I'm not sure what justifies that.
For those looking for a fix, I'd suggest lazy importing every component.
const Body = lazy(async () => {
return { default: (await import("@react-email/components")).Body };
});
This way, they won't bloat the global scope, resulting in faster startup, which makes sense whether this gets fixed or not.
Importing components individually instead of via @react-email/components (including Tailwind) fixed the issue for me
import { Section } from '@react-email/section'
import { Body } from '@react-email/body'
import { Container } from '@react-email/container'
import { Img } from '@react-email/img'
import { Head } from '@react-email/head'
import { Preview } from '@react-email/preview'
import { Tailwind } from '@react-email/tailwind'
import { Html } from '@react-email/html'
import { Text } from '@react-email/text'
import { Link } from '@react-email/link'
We just merged #1383 and released it under canary, @react-email/[email protected], should fix it
@gabrielmfern the latest version again doesn't work on Cloudflare worker. any suggestion?
@vickyRathee start with making a reproduction and opening another issue, as the problem seems to be unrelated to this one
@gabrielmfern please disregard, this is resolved by installing react and using await.
"react": "^19.1.0", "react-dom": "^19.1.0",
const html = await otpEmailHtml(authUser, otp);
In past versions react and await was not needed with hono and cf workers.