From da485a00771271eaed1880c4dd797ae13ceab9eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:30:18 -0300 Subject: [PATCH 01/15] fix(deps): update socket.io packages to v4.7.5 (#1553) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: gabriel miranda --- .changeset/dry-humans-return.md | 5 +++++ packages/react-email/package.json | 4 ++-- pnpm-lock.yaml | 25 +++++++++++++++---------- 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 .changeset/dry-humans-return.md diff --git a/.changeset/dry-humans-return.md b/.changeset/dry-humans-return.md new file mode 100644 index 0000000000..668fe399f7 --- /dev/null +++ b/.changeset/dry-humans-return.md @@ -0,0 +1,5 @@ +--- +"react-email": patch +--- + +update socket.io/socket.io-client to 4.7.5 diff --git a/packages/react-email/package.json b/packages/react-email/package.json index 58ffeeae54..70f00528e8 100644 --- a/packages/react-email/package.json +++ b/packages/react-email/package.json @@ -59,8 +59,8 @@ "prism-react-renderer": "2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "socket.io": "4.7.3", - "socket.io-client": "4.7.3", + "socket.io": "4.7.5", + "socket.io-client": "4.7.5", "sonner": "1.3.1", "source-map-js": "1.0.2", "stacktrace-parser": "0.1.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc0b6443f5..04129944b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -773,11 +773,11 @@ importers: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) socket.io: - specifier: 4.7.3 - version: 4.7.3 + specifier: 4.7.5 + version: 4.7.5 socket.io-client: - specifier: 4.7.3 - version: 4.7.3 + specifier: 4.7.5 + version: 4.7.5 sonner: specifier: 1.3.1 version: 1.3.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -1737,6 +1737,7 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -1744,6 +1745,7 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -4036,6 +4038,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -4197,6 +4200,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -5357,6 +5361,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true ripemd160@2.0.2: @@ -5497,16 +5502,16 @@ packages: socket.io-adapter@2.5.4: resolution: {integrity: sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==} - socket.io-client@4.7.3: - resolution: {integrity: sha512-nU+ywttCyBitXIl9Xe0RSEfek4LneYkJxCeNnKCuhwoH4jGXO1ipIUw/VA/+Vvv2G1MTym11fzFC0SxkrcfXDw==} + socket.io-client@4.7.5: + resolution: {integrity: sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==} engines: {node: '>=10.0.0'} socket.io-parser@4.2.4: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} - socket.io@4.7.3: - resolution: {integrity: sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==} + socket.io@4.7.5: + resolution: {integrity: sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==} engines: {node: '>=10.2.0'} sonner@1.3.1: @@ -11458,7 +11463,7 @@ snapshots: - supports-color - utf-8-validate - socket.io-client@4.7.3: + socket.io-client@4.7.5: dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.4 @@ -11476,7 +11481,7 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io@4.7.3: + socket.io@4.7.5: dependencies: accepts: 1.3.8 base64id: 2.0.0 From eb125a1aca5a2d46b6f418c2983f814423d82c54 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Tue, 23 Jul 2024 16:40:24 -0300 Subject: [PATCH 02/15] chore: Add direct support for React 19 (#1474) --- .changeset/fast-countries-marry.md | 27 + .github/workflows/tests.yml | 3 + apps/demo/package.json | 10 +- apps/web/package.json | 8 +- apps/web/src/components/heading.tsx | 48 +- apps/web/src/components/text.tsx | 49 +- benchmarks/tailwind-component/package.json | 2 +- examples/aws-ses/package.json | 2 +- examples/mailersend/package.json | 2 +- examples/nodemailer/package.json | 2 +- examples/plunk/package.json | 2 +- examples/postmark/package.json | 2 +- examples/resend/package.json | 8 +- examples/scaleway/next/package.json | 8 +- examples/scaleway/node/package.json | 2 +- examples/sendgrid/package.json | 2 +- package.json | 8 +- packages/body/package.json | 2 +- packages/button/package.json | 2 +- packages/code-block/package.json | 2 +- packages/code-inline/package.json | 2 +- packages/column/package.json | 2 +- packages/components/package.json | 2 +- packages/container/package.json | 2 +- packages/create-email/template/package.json | 6 +- packages/font/package.json | 2 +- packages/head/package.json | 2 +- packages/heading/package.json | 2 +- packages/hr/package.json | 2 +- packages/html/package.json | 2 +- packages/html/src/html.spec.tsx | 2 +- packages/img/package.json | 2 +- packages/img/src/img.spec.tsx | 2 +- packages/link/package.json | 2 +- packages/markdown/package.json | 2 +- packages/preview/package.json | 2 +- packages/react-email/package.json | 10 +- .../src/actions/render-email-by-path.tsx | 19 +- .../react-email/src/cli/commands/build.ts | 12 +- .../react-email/src/cli/commands/export.ts | 17 +- .../testing/__snapshots__/export.spec.ts.snap | 4 +- .../testing/emails/vercel-invite-user.tsx | 158 -- .../src/cli/commands/testing/export.spec.ts | 7 +- .../get-email-component.spec.ts.snap | 2 +- .../utils/esbuild/escape-string-for-regex.ts | 3 + .../renderring-utilities-exporter.ts} | 13 +- .../src/utils/get-email-component.spec.ts | 8 +- .../src/utils/get-email-component.ts | 23 +- .../src/utils/improve-error-with-sourcemap.ts | 4 +- .../src/utils/static-node-modules-for-vm.ts | 161 +- .../src/utils/testing/email-template.tsx | 9 - packages/render/package.json | 4 +- .../src/browser/render-async-web.spec.tsx | 4 +- .../src/node/render-async-edge.spec.tsx | 4 +- .../src/node/render-async-node.spec.tsx | 4 +- packages/render/src/shared/render.spec.tsx | 2 +- packages/row/package.json | 2 +- packages/section/package.json | 2 +- packages/tailwind/package.json | 5 +- .../src/utils/quick-safe-render-to-string.ts | 19 +- packages/text/package.json | 2 +- pnpm-lock.yaml | 1556 ++++++++++------- 62 files changed, 1193 insertions(+), 1088 deletions(-) create mode 100644 .changeset/fast-countries-marry.md delete mode 100644 packages/react-email/src/cli/commands/testing/emails/vercel-invite-user.tsx create mode 100644 packages/react-email/src/utils/esbuild/escape-string-for-regex.ts rename packages/react-email/src/utils/{render-resolver-esbuild-plugin.ts => esbuild/renderring-utilities-exporter.ts} (84%) delete mode 100644 packages/react-email/src/utils/testing/email-template.tsx diff --git a/.changeset/fast-countries-marry.md b/.changeset/fast-countries-marry.md new file mode 100644 index 0000000000..000ad57186 --- /dev/null +++ b/.changeset/fast-countries-marry.md @@ -0,0 +1,27 @@ +--- +"create-email": patch +"@react-email/code-inline": patch +"react-email": patch +"@react-email/code-block": patch +"@react-email/components": patch +"@react-email/container": patch +"@react-email/markdown": patch +"@react-email/tailwind": patch +"@react-email/heading": patch +"@react-email/preview": patch +"@react-email/section": patch +"@react-email/button": patch +"@react-email/column": patch +"@react-email/render": patch +"@react-email/body": patch +"@react-email/font": patch +"@react-email/head": patch +"@react-email/html": patch +"@react-email/link": patch +"@react-email/text": patch +"@react-email/img": patch +"@react-email/row": patch +"@react-email/hr": patch +--- + +Updated peer dependencies to allow for React 19 release candidated and React 19 itself diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9fcd57563f..4b7039a638 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -120,6 +120,9 @@ jobs: if (version.startsWith("workspace:")) { return true; } + if (version.startsWith("npm:")) { + return true; + } return /^\d+\.\d+\.\d+$|^[a-z]+:[a-z]+@\d+$/.test(version); } diff --git a/apps/demo/package.json b/apps/demo/package.json index 3fe69aa6da..86b464ebf0 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -10,14 +10,14 @@ }, "dependencies": { "@react-email/components": "workspace:*", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "19.0.0-rc.0", + "react-dom": "19.0.0-rc.0", "react-email": "workspace:*" }, "devDependencies": { - "next": "14.1.4", - "@types/react": "18.2.47", - "@types/react-dom": "18.2.18", + "next": "14.2.3", + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc", "tsx": "4.9.0" } } diff --git a/apps/web/package.json b/apps/web/package.json index 37253767f9..14fedf7508 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,15 +10,15 @@ }, "dependencies": { "@radix-ui/colors": "1.0.1", - "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-slot": "1.1.0", "@sindresorhus/is": "6.1.0", "@supabase/supabase-js": "2.39.3", "@vercel/analytics": "1.0.1", "classnames": "2.3.2", - "next": "14.2.3", + "next": "15.0.0-canary.27", "prism-react-renderer": "2.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "19.0.0-rc.0", + "react-dom": "19.0.0-rc.0", "resend": "3.2.0" }, "devDependencies": { diff --git a/apps/web/src/components/heading.tsx b/apps/web/src/components/heading.tsx index 358611decc..a0a70ba6eb 100644 --- a/apps/web/src/components/heading.tsx +++ b/apps/web/src/components/heading.tsx @@ -26,35 +26,27 @@ interface HeadingOwnProps { type HeadingProps = As<"h1", "h2", "h3", "h4", "h5", "h6"> & HeadingOwnProps; -export const Heading = React.forwardRef< - HTMLHeadingElement, - Readonly ->( - ( - { - as: Tag = "h1", - size = "3", +export const Heading = ({ + as: Tag = "h1", + size = "3", + className, + color = "white", + children, + weight = "bold", + ...props +}: HeadingProps) => ( + ( - - {children} - - ), + getSizesClassNames(size), + getColorClassNames(color), + getWeightClassNames(weight), + )} + {...props} + ref={props.ref as React.Ref} + > + {children} + ); const getSizesClassNames = (size: HeadingSize | undefined) => { diff --git a/apps/web/src/components/text.tsx b/apps/web/src/components/text.tsx index 580156ccfe..ce0d914a4b 100644 --- a/apps/web/src/components/text.tsx +++ b/apps/web/src/components/text.tsx @@ -18,34 +18,29 @@ interface TextOwnProps { type TextProps = As<"span", "div", "p"> & TextOwnProps; -export const Text = React.forwardRef>( - ( - { - as: Tag = "span", - size = "2", - color = "gray", - transform, - weight = "normal", +export const Text = ({ + as: Tag = "span", + size = "2", + color = "gray", + transform, + weight = "normal", + className, + children, + ...props +}: TextProps) => ( + ( - - {children} - - ), + transform, + getSizesClassNames(size), + getColorClassNames(color), + getWeightClassNames(weight), + )} + {...props} + ref={props.ref as React.Ref} + > + {children} + ); const getSizesClassNames = (size: TextSize | undefined) => { diff --git a/benchmarks/tailwind-component/package.json b/benchmarks/tailwind-component/package.json index bdb8241c8f..bc6ea03b1b 100644 --- a/benchmarks/tailwind-component/package.json +++ b/benchmarks/tailwind-component/package.json @@ -23,7 +23,7 @@ "@react-email/components": "workspace:*", "@react-email/render": "workspace:*", "@react-email/tailwind": "workspace:*", - "react": "^18.2.0", + "react": "19.0.0-rc.0", "tailwind-0.0.12": "npm:@react-email/tailwind@0.0.12", "tailwind-0.0.15": "npm:@react-email/tailwind@0.0.15", "tinybench": "2.5.1" diff --git a/examples/aws-ses/package.json b/examples/aws-ses/package.json index ddda955061..00f75d9aa5 100644 --- a/examples/aws-ses/package.json +++ b/examples/aws-ses/package.json @@ -18,7 +18,7 @@ "dependencies": { "@aws-sdk/client-ses": "3.341.0", "@react-email/components": "*", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/mailersend/package.json b/examples/mailersend/package.json index 404a3bd091..3a177160f0 100644 --- a/examples/mailersend/package.json +++ b/examples/mailersend/package.json @@ -18,7 +18,7 @@ "dependencies": { "@react-email/components": "*", "mailersend": "^2.0.0", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/nodemailer/package.json b/examples/nodemailer/package.json index 339d698b51..f55ad16d41 100644 --- a/examples/nodemailer/package.json +++ b/examples/nodemailer/package.json @@ -18,7 +18,7 @@ "dependencies": { "@react-email/components": "*", "nodemailer": "6.9.9", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/plunk/package.json b/examples/plunk/package.json index 02e5bf3585..147b816f3e 100644 --- a/examples/plunk/package.json +++ b/examples/plunk/package.json @@ -18,7 +18,7 @@ "dependencies": { "@plunk/node": "1.1.1", "@react-email/components": "*", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/postmark/package.json b/examples/postmark/package.json index f9c65abbf1..ab392b58b9 100644 --- a/examples/postmark/package.json +++ b/examples/postmark/package.json @@ -18,7 +18,7 @@ "dependencies": { "@react-email/components": "*", "postmark": "3.0.14", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/resend/package.json b/examples/resend/package.json index 8ba6aa0605..b290f16579 100644 --- a/examples/resend/package.json +++ b/examples/resend/package.json @@ -11,14 +11,14 @@ }, "dependencies": { "next": "13.5.6", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "19.0.0-rc.0", + "react-dom": "19.0.0-rc.0", "resend": "^3.2.0" }, "devDependencies": { "@types/node": "^20.2.5", - "@types/react": "18.2.23", - "@types/react-dom": "18.2.8", + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc", "typescript": "^5.1.3" } } diff --git a/examples/scaleway/next/package.json b/examples/scaleway/next/package.json index f1ed0a7d2f..e09201a103 100644 --- a/examples/scaleway/next/package.json +++ b/examples/scaleway/next/package.json @@ -13,13 +13,13 @@ "@react-email/render": "*", "@scaleway/sdk": "1.5.0", "next": "13.5.6", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": "19.0.0-rc.0", + "react-dom": "19.0.0-rc.0" }, "devDependencies": { "@types/node": "18.14.6", - "@types/react": "18.2.23", - "@types/react-dom": "18.2.8", + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc", "typescript": "4.9.5" } } diff --git a/examples/scaleway/node/package.json b/examples/scaleway/node/package.json index 77e744e5ca..5bd1b4de29 100644 --- a/examples/scaleway/node/package.json +++ b/examples/scaleway/node/package.json @@ -19,7 +19,7 @@ "dependencies": { "@scaleway/sdk": "1.4.0", "@react-email/components": "*", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/examples/sendgrid/package.json b/examples/sendgrid/package.json index b1c6563b46..e64efe44ae 100644 --- a/examples/sendgrid/package.json +++ b/examples/sendgrid/package.json @@ -18,7 +18,7 @@ "dependencies": { "@sendgrid/mail": "7.7.0", "@react-email/components": "*", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { "tsup": "6.2.3", diff --git a/package.json b/package.json index 67b0548baa..d71f196bc9 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "devDependencies": { "@changesets/cli": "2.27.1", "@types/node": "18.18.0", - "@types/react": "18.2.47", - "@types/react-dom": "18.2.14", + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "eslint": "8.50.0", "happy-dom": "12.2.2", "prettier": "3.0.3", @@ -29,6 +29,10 @@ }, "packageManager": "pnpm@9.1.2", "pnpm": { + "overrides": { + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1" + }, "patchedDependencies": { "postcss-css-variables@0.19.0": "patches/postcss-css-variables@0.19.0.patch", "process@0.11.10": "patches/process@0.11.10.patch", diff --git a/packages/body/package.json b/packages/body/package.json index c1f42b4ca5..9dce2d406b 100644 --- a/packages/body/package.json +++ b/packages/body/package.json @@ -31,7 +31,7 @@ "test": "vitest run" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/core": "7.23.9", diff --git a/packages/button/package.json b/packages/button/package.json index f5ed88f7e6..430cbe4a23 100644 --- a/packages/button/package.json +++ b/packages/button/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/code-block/package.json b/packages/code-block/package.json index 73bf42e840..29d9c9b272 100644 --- a/packages/code-block/package.json +++ b/packages/code-block/package.json @@ -41,7 +41,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/code-inline/package.json b/packages/code-inline/package.json index f9eeb6cf6a..2379756de3 100644 --- a/packages/code-inline/package.json +++ b/packages/code-inline/package.json @@ -35,7 +35,7 @@ "access": "public" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/column/package.json b/packages/column/package.json index eba8f9881e..06c8740192 100644 --- a/packages/column/package.json +++ b/packages/column/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/components/package.json b/packages/components/package.json index fafe71919e..5a0a8d5ab6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -63,7 +63,7 @@ "@react-email/text": "workspace:0.0.9" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/container/package.json b/packages/container/package.json index 54e62c4045..f8147fd026 100644 --- a/packages/container/package.json +++ b/packages/container/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/create-email/template/package.json b/packages/create-email/template/package.json index 04e83ea197..7cb678aa56 100644 --- a/packages/create-email/template/package.json +++ b/packages/create-email/template/package.json @@ -10,10 +10,10 @@ "dependencies": { "@react-email/components": "workspace:0.0.22", "react-email": "workspace:2.1.6", - "react": "^18.2.0" + "react": "19.0.0-rc.0" }, "devDependencies": { - "@types/react": "18.2.33", - "@types/react-dom": "18.2.14" + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc" } } diff --git a/packages/font/package.json b/packages/font/package.json index 2ceae18092..68a732f144 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -31,7 +31,7 @@ "test": "vitest run" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/head/package.json b/packages/head/package.json index 4021e7a9d3..fc102ed853 100644 --- a/packages/head/package.json +++ b/packages/head/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/heading/package.json b/packages/heading/package.json index 668ab9203c..d1af2b8c0c 100644 --- a/packages/heading/package.json +++ b/packages/heading/package.json @@ -46,7 +46,7 @@ "@radix-ui/react-slot": "1.1.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/hr/package.json b/packages/hr/package.json index d79aee120d..4d43d570f1 100644 --- a/packages/hr/package.json +++ b/packages/hr/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/html/package.json b/packages/html/package.json index 3648d9b9de..76b3382177 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/html/src/html.spec.tsx b/packages/html/src/html.spec.tsx index 45d3450337..aff70aed56 100644 --- a/packages/html/src/html.spec.tsx +++ b/packages/html/src/html.spec.tsx @@ -18,7 +18,7 @@ describe(" component", () => { it("renders correctly", () => { const actualOutput = render(); expect(actualOutput).toMatchInlineSnapshot( - '""', + '""', ); }); }); diff --git a/packages/img/package.json b/packages/img/package.json index 4644bd9507..a604478d17 100644 --- a/packages/img/package.json +++ b/packages/img/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/img/src/img.spec.tsx b/packages/img/src/img.spec.tsx index 097c10b2ae..c726816a65 100644 --- a/packages/img/src/img.spec.tsx +++ b/packages/img/src/img.spec.tsx @@ -24,7 +24,7 @@ describe(" component", () => { Cat, ); expect(actualOutput).toMatchInlineSnapshot( - '"\\"Cat\\""', + '"\\"Cat\\""', ); }); }); diff --git a/packages/link/package.json b/packages/link/package.json index d120332252..3731f9daf5 100644 --- a/packages/link/package.json +++ b/packages/link/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/markdown/package.json b/packages/markdown/package.json index a1595f8b10..8149681cae 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -47,7 +47,7 @@ }, "license": "MIT", "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/preview/package.json b/packages/preview/package.json index b03ae9c886..71c7331d5e 100644 --- a/packages/preview/package.json +++ b/packages/preview/package.json @@ -43,7 +43,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/react-email/package.json b/packages/react-email/package.json index 70f00528e8..7fb4c59942 100644 --- a/packages/react-email/package.json +++ b/packages/react-email/package.json @@ -36,7 +36,7 @@ "@radix-ui/react-toggle-group": "1.1.0", "@radix-ui/react-tooltip": "1.1.1", "@swc/core": "1.3.101", - "@types/react": "18.2.47", + "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/webpack": "5.28.5", "autoprefixer": "10.4.14", @@ -48,17 +48,17 @@ "esbuild": "0.19.11", "eslint-config-prettier": "9.0.0", "eslint-config-turbo": "1.10.12", - "framer-motion": "10.17.4", + "framer-motion": "12.0.0-alpha.0", "glob": "10.3.4", "log-symbols": "4.1.0", "mime-types": "2.1.35", - "next": "14.1.4", + "next": "14.2.3", "normalize-path": "3.0.0", "ora": "5.4.1", "postcss": "8.4.38", "prism-react-renderer": "2.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "18.3.1", + "react-dom": "18.3.1", "socket.io": "4.7.5", "socket.io-client": "4.7.5", "sonner": "1.3.1", diff --git a/packages/react-email/src/actions/render-email-by-path.tsx b/packages/react-email/src/actions/render-email-by-path.tsx index c20d2503b0..488f4acf9b 100644 --- a/packages/react-email/src/actions/render-email-by-path.tsx +++ b/packages/react-email/src/actions/render-email-by-path.tsx @@ -27,6 +27,7 @@ export const renderEmailByPath = async ( const { emailComponent: Email, + createElement, renderAsync, sourceMapToOriginalFile, } = result; @@ -34,12 +35,18 @@ export const renderEmailByPath = async ( const previewProps = Email.PreviewProps || {}; const EmailComponent = Email as React.FC; try { - const markup = await renderAsync(, { - pretty: true, - }); - const plainText = await renderAsync(, { - plainText: true, - }); + const markup = await renderAsync( + createElement(EmailComponent, previewProps), + { + pretty: true, + }, + ); + const plainText = await renderAsync( + createElement(EmailComponent, previewProps), + { + plainText: true, + }, + ); const reactMarkup = await fs.promises.readFile(emailPath, 'utf-8'); diff --git a/packages/react-email/src/cli/commands/build.ts b/packages/react-email/src/cli/commands/build.ts index c063b5fe85..df021fc0ba 100644 --- a/packages/react-email/src/cli/commands/build.ts +++ b/packages/react-email/src/cli/commands/build.ts @@ -184,10 +184,14 @@ const npmInstall = async ( packageManager: string, ) => { return new Promise(async (resolve, reject) => { - const childProc = spawn(packageManager, ['install', '--silent'], { - cwd: builtPreviewAppPath, - shell: true, - }); + const childProc = spawn( + packageManager, + ['install', '--silent', '--force'], + { + cwd: builtPreviewAppPath, + shell: true, + }, + ); childProc.stdout.pipe(process.stdout); childProc.stderr.pipe(process.stderr); childProc.on('close', (code) => { diff --git a/packages/react-email/src/cli/commands/export.ts b/packages/react-email/src/cli/commands/export.ts index c76f2127e7..2e54181805 100644 --- a/packages/react-email/src/cli/commands/export.ts +++ b/packages/react-email/src/cli/commands/export.ts @@ -1,5 +1,6 @@ import fs, { unlinkSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import type React from 'react'; import { glob } from 'glob'; import { BuildFailure, build } from 'esbuild'; import ora from 'ora'; @@ -12,8 +13,7 @@ import { EmailsDirectory, getEmailsDirectoryMetadata, } from '../../actions/get-emails-directory-metadata'; -import { renderResolver } from '../../utils/render-resolver-esbuild-plugin'; -import { createElement } from 'react'; +import { renderingUtilitiesExporter } from '../../utils/esbuild/renderring-utilities-exporter'; const getEmailTemplatesFromDirectory = (emailDirectory: EmailsDirectory) => { const templatePaths = [] as string[]; @@ -73,7 +73,7 @@ export const exportTemplates = async ( await build({ bundle: true, entryPoints: allTemplates, - plugins: [renderResolver(allTemplates)], + plugins: [renderingUtilitiesExporter(allTemplates)], platform: 'node', format: 'cjs', loader: { '.js': 'jsx' }, @@ -118,9 +118,16 @@ export const exportTemplates = async ( spinner.render(); } delete require.cache[template]; - const emailModule = require(template); + const emailModule = require(template) as { + default: React.FC; + renderAsync: ( + element: React.ReactElement, + options: Record, + ) => Promise; + reactEmailCreateReactElement: typeof React.createElement; + }; const rendered = await emailModule.renderAsync( - createElement(emailModule.default, {}), + emailModule.reactEmailCreateReactElement(emailModule.default, {}), options, ); const htmlPath = template.replace( diff --git a/packages/react-email/src/cli/commands/testing/__snapshots__/export.spec.ts.snap b/packages/react-email/src/cli/commands/testing/__snapshots__/export.spec.ts.snap index 497cbf8b79..5c007389ea 100644 --- a/packages/react-email/src/cli/commands/testing/__snapshots__/export.spec.ts.snap +++ b/packages/react-email/src/cli/commands/testing/__snapshots__/export.spec.ts.snap @@ -5,10 +5,12 @@ exports[`email export 1`] = ` + + -
Banana boy
 ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏
+
Join undefined on Vercel
 ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏
diff --git a/packages/react-email/src/cli/commands/testing/emails/vercel-invite-user.tsx b/packages/react-email/src/cli/commands/testing/emails/vercel-invite-user.tsx deleted file mode 100644 index 8f2d377983..0000000000 --- a/packages/react-email/src/cli/commands/testing/emails/vercel-invite-user.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { - Body, - Button, - Container, - Column, - Head, - Heading, - Hr, - Html, - Img, - Link, - Preview, - Row, - Section, - Text, - Tailwind, -} from '@react-email/components'; -import * as React from 'react'; - -interface VercelInviteUserEmailProps { - username?: string; - userImage?: string; - invitedByUsername?: string; - invitedByEmail?: string; - teamName?: string; - teamImage?: string; - inviteLink?: string; - inviteFromIp?: string; - inviteFromLocation?: string; -} - -const baseUrl = process.env.VERCEL_URL - ? `https://${process.env.VERCEL_URL}` - : ''; - -export const VercelInviteUserEmail = ({ - username, - userImage, - invitedByUsername, - invitedByEmail, - teamName, - teamImage, - inviteLink, - inviteFromIp, - inviteFromLocation, -}: VercelInviteUserEmailProps) => { - const previewText = `Join ${invitedByUsername} on Vercel`; - const [myState, setMyState] = React.useState(previewText); - if (myState === previewText) { - setMyState('Banana boy'); - } - - return ( - - - {myState} - - - -
- Vercel -
- - Join {teamName} on Vercel - - - Hello {username}, - - - {invitedByUsername} ( - - {invitedByEmail} - - ) has invited you to the {teamName} team on{' '} - Vercel. - -
- - - - - - invited you to - - - - - -
-
- -
- - or copy and paste this URL into your browser:{' '} - - {inviteLink} - - -
- - This invitation was intended for{' '} - {username}. This invite was - sent from {inviteFromIp}{' '} - located in{' '} - {inviteFromLocation}. If you - were not expecting this invitation, you can ignore this email. If - you are concerned about your account's safety, please reply to - this email to get in touch with us. - -
- -
- - ); -}; - -VercelInviteUserEmail.PreviewProps = { - username: 'alanturing', - userImage: `${baseUrl}/static/vercel-user.png`, - invitedByUsername: 'Alan', - invitedByEmail: 'alan.turing@example.com', - teamName: 'Enigma', - teamImage: `${baseUrl}/static/vercel-team.png`, - inviteLink: 'https://vercel.com/teams/invite/foo', - inviteFromIp: '204.13.186.218', - inviteFromLocation: 'São Paulo, Brazil', -} as VercelInviteUserEmailProps; - -export default VercelInviteUserEmail; diff --git a/packages/react-email/src/cli/commands/testing/export.spec.ts b/packages/react-email/src/cli/commands/testing/export.spec.ts index 0dd61ce8f9..3fce5612d0 100644 --- a/packages/react-email/src/cli/commands/testing/export.spec.ts +++ b/packages/react-email/src/cli/commands/testing/export.spec.ts @@ -3,7 +3,10 @@ import fs from 'node:fs'; import { exportTemplates } from '../export'; test('email export', async () => { - const pathToEmailsDirectory = path.resolve(__dirname, './emails'); + const pathToEmailsDirectory = path.resolve( + __dirname, + '../../../../../../apps/demo/emails', + ); const pathToDumpMarkup = path.resolve(__dirname, './out'); await exportTemplates(pathToDumpMarkup, pathToEmailsDirectory, { pretty: true, @@ -13,7 +16,7 @@ test('email export', async () => { expect(fs.existsSync(pathToDumpMarkup)).toBe(true); expect( await fs.promises.readFile( - path.resolve(pathToDumpMarkup, './vercel-invite-user.html'), + path.resolve(pathToDumpMarkup, './notifications/vercel-invite-user.html'), 'utf8', ), ).toMatchSnapshot(); diff --git a/packages/react-email/src/utils/__snapshots__/get-email-component.spec.ts.snap b/packages/react-email/src/utils/__snapshots__/get-email-component.spec.ts.snap index d9b7e8aaa1..1f1a003f34 100644 --- a/packages/react-email/src/utils/__snapshots__/get-email-component.spec.ts.snap +++ b/packages/react-email/src/utils/__snapshots__/get-email-component.spec.ts.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`getEmailComponent() with a demo email template 1`] = `"
Hello Gabriel!
"`; +exports[`getEmailComponent() with a demo email template 1`] = `"
Join Alan on Vercel
 ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏
Vercel

Join Enigma on Vercel

Hello alanturing,

Alan (alan.turing@example.com) has invited you to the Enigma team on Vercel.

invited you to
Join the team

or copy and paste this URL into your browser: https://vercel.com/teams/invite/foo


This invitation was intended for alanturing. This invite was sent from 204.13.186.218 located in São Paulo, Brazil. If you were not expecting this invitation, you can ignore this email. If you are concerned about your account's safety, please reply to this email to get in touch with us.

"`; diff --git a/packages/react-email/src/utils/esbuild/escape-string-for-regex.ts b/packages/react-email/src/utils/esbuild/escape-string-for-regex.ts new file mode 100644 index 0000000000..71d343cd9a --- /dev/null +++ b/packages/react-email/src/utils/esbuild/escape-string-for-regex.ts @@ -0,0 +1,3 @@ +export function escapeStringForRegex(string: string) { + return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'); +} diff --git a/packages/react-email/src/utils/render-resolver-esbuild-plugin.ts b/packages/react-email/src/utils/esbuild/renderring-utilities-exporter.ts similarity index 84% rename from packages/react-email/src/utils/render-resolver-esbuild-plugin.ts rename to packages/react-email/src/utils/esbuild/renderring-utilities-exporter.ts index 00fd2fad80..f2f8a6ee86 100644 --- a/packages/react-email/src/utils/render-resolver-esbuild-plugin.ts +++ b/packages/react-email/src/utils/esbuild/renderring-utilities-exporter.ts @@ -1,21 +1,21 @@ import path from 'node:path'; import { promises as fs } from 'node:fs'; import type { Loader, PluginBuild, ResolveOptions } from 'esbuild'; - -function escapeStringForRegex(string: string) { - return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'); -} +import { escapeStringForRegex } from './escape-string-for-regex'; /** * Made to export the `renderAsync` function out of the user's email template * so that issues like https://github.com/resend/react-email/issues/649 don't * happen. * + * This also exports the `createElement` from the user's React version as well + * to avoid mismatches. + * * This avoids multiple versions of React being involved, i.e., the version * in the CLI vs. the version the user has on their emails. */ -export const renderResolver = (emailTemplates: string[]) => ({ - name: 'render-resolver', +export const renderingUtilitiesExporter = (emailTemplates: string[]) => ({ + name: 'rendering-utilities-exporter', setup: (b: PluginBuild) => { b.onLoad( { @@ -29,6 +29,7 @@ export const renderResolver = (emailTemplates: string[]) => ({ return { contents: `${await fs.readFile(pathToFile, 'utf8')}; export { renderAsync } from 'react-email-module-that-will-export-render' + export { createElement as reactEmailCreateReactElement } from 'react'; `, loader: path.extname(pathToFile).slice(1) as Loader, }; diff --git a/packages/react-email/src/utils/get-email-component.spec.ts b/packages/react-email/src/utils/get-email-component.spec.ts index 50bf56e990..6de8cbedf8 100644 --- a/packages/react-email/src/utils/get-email-component.spec.ts +++ b/packages/react-email/src/utils/get-email-component.spec.ts @@ -1,10 +1,12 @@ import path from 'node:path'; -import * as React from 'react'; import { getEmailComponent } from './get-email-component'; test('getEmailComponent() with a demo email template', async () => { const result = await getEmailComponent( - path.resolve(__dirname, './testing/email-template.tsx'), + path.resolve( + __dirname, + '../../../../apps/demo/emails/notifications/vercel-invite-user.tsx', + ), ); if ('error' in result) { @@ -15,7 +17,7 @@ test('getEmailComponent() with a demo email template', async () => { expect(result.sourceMapToOriginalFile).toBeTruthy(); const emailHtml = await result.renderAsync( - React.createElement( + result.createElement( result.emailComponent, result.emailComponent.PreviewProps, ), diff --git a/packages/react-email/src/utils/get-email-component.ts b/packages/react-email/src/utils/get-email-component.ts index ba25d783b9..9558704084 100644 --- a/packages/react-email/src/utils/get-email-component.ts +++ b/packages/react-email/src/utils/get-email-component.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import path from 'node:path'; import vm from 'node:vm'; +import type React from 'react'; import { type RawSourceMap } from 'source-map-js'; import { type OutputFile, build, type BuildFailure } from 'esbuild'; import type { renderAsync } from '@react-email/render'; @@ -8,7 +9,7 @@ import type { EmailTemplate as EmailComponent } from './types/email-template'; import type { ErrorObject } from './types/error-object'; import { improveErrorWithSourceMap } from './improve-error-with-sourcemap'; import { staticNodeModulesForVM } from './static-node-modules-for-vm'; -import { renderResolver } from './render-resolver-esbuild-plugin'; +import { renderingUtilitiesExporter } from './esbuild/renderring-utilities-exporter'; export const getEmailComponent = async ( emailPath: string, @@ -16,6 +17,8 @@ export const getEmailComponent = async ( | { emailComponent: EmailComponent; + createElement: typeof React.createElement; + renderAsync: typeof renderAsync; sourceMapToOriginalFile: RawSourceMap; @@ -27,7 +30,7 @@ export const getEmailComponent = async ( const buildData = await build({ bundle: true, entryPoints: [emailPath], - plugins: [renderResolver([emailPath])], + plugins: [renderingUtilitiesExporter([emailPath])], platform: 'node', write: false, @@ -74,18 +77,24 @@ export const getEmailComponent = async ( exports: { default: undefined as unknown, renderAsync: undefined as unknown, + reactEmailCreateReactElement: undefined as unknown, }, }, __filename: emailPath, __dirname: path.dirname(emailPath), - require: (module: string) => { - if (module in staticNodeModulesForVM) { + require: (specifiedModule: string) => { + let m = specifiedModule; + if (specifiedModule.startsWith('node:')) { + m = m.split(':')[1]!; + } + + if (m in staticNodeModulesForVM) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return staticNodeModulesForVM[module]; + return staticNodeModulesForVM[m]; } // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-useless-template-literals - return require(`${module}`) as unknown; + return require(`${specifiedModule}`) as unknown; // this stupid string templating was necessary to not have // webpack warnings like: // @@ -130,6 +139,8 @@ export const getEmailComponent = async ( return { emailComponent: fakeContext.module.exports.default as EmailComponent, renderAsync: fakeContext.module.exports.renderAsync as typeof renderAsync, + createElement: fakeContext.module.exports + .reactEmailCreateReactElement as typeof React.createElement, sourceMapToOriginalFile: sourceMapToEmail, }; diff --git a/packages/react-email/src/utils/improve-error-with-sourcemap.ts b/packages/react-email/src/utils/improve-error-with-sourcemap.ts index ec892ae982..c074b5cae6 100644 --- a/packages/react-email/src/utils/improve-error-with-sourcemap.ts +++ b/packages/react-email/src/utils/improve-error-with-sourcemap.ts @@ -47,7 +47,9 @@ export const improveErrorWithSourceMap = ( newStackLines.push( getStackLineFromMethodNameAndSource( stackFrame.methodName, - positionWithError.source, + // This can actually be null + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + positionWithError.source ?? stackFrame.file, positionWithError.line, positionWithError.column, ), diff --git a/packages/react-email/src/utils/static-node-modules-for-vm.ts b/packages/react-email/src/utils/static-node-modules-for-vm.ts index f6351afb40..5fec44d426 100644 --- a/packages/react-email/src/utils/static-node-modules-for-vm.ts +++ b/packages/react-email/src/utils/static-node-modules-for-vm.ts @@ -1,32 +1,43 @@ -import zlib from 'node:zlib'; -import vm from 'node:vm'; -import v8 from 'node:v8'; -import util from 'node:util'; -import url from 'node:url'; -import tty from 'node:tty'; -import tls from 'node:tls'; -import timers from 'node:timers'; -import stringDecoder from 'node:string_decoder'; -import stream from 'node:stream'; -import readline from 'node:readline'; -import querystring from 'node:querystring'; -import punycode from 'node:punycode'; -import path from 'node:path'; -import os from 'node:os'; -import net from 'node:net'; -import https from 'node:https'; -import http from 'node:http'; -import fs from 'node:fs'; -import events from 'node:events'; -import domain from 'node:domain'; -import dns from 'node:dns'; -import dgram from 'node:dgram'; -import crypto from 'node:crypto'; -import cluster from 'node:cluster'; -import childProcess from 'node:child_process'; -import buffer from 'node:buffer'; import assert from 'node:assert'; import asyncHooks from 'node:async_hooks'; +import buffer from 'node:buffer'; +import childProcess from 'node:child_process'; +import cluster from 'node:cluster'; +import console from 'node:console'; +import constants from 'node:constants'; +import crypto from 'node:crypto'; +import dgram from 'node:dgram'; +import diagnosticsChannel from 'node:diagnostics_channel'; +import dns from 'node:dns'; +import domain from 'node:domain'; +import events from 'node:events'; +import fs from 'node:fs'; +import fsPromises from 'node:fs/promises'; +import http from 'node:http'; +import http2 from 'node:http2'; +import https from 'node:https'; +import inspector from 'node:inspector'; +import module from 'node:module'; +import net from 'node:net'; +import os from 'node:os'; +import path from 'node:path'; +import perfHooks from 'node:perf_hooks'; +import process from 'node:process'; +import punycode from 'node:punycode'; +import querystring from 'node:querystring'; +import readline from 'node:readline'; +import repl from 'node:repl'; +import stream from 'node:stream'; +import stringDecoder from 'node:string_decoder'; +import timers from 'node:timers'; +import tls from 'node:tls'; +import tty from 'node:tty'; +import url from 'node:url'; +import util from 'node:util'; +import v8 from 'node:v8'; +import vm from 'node:vm'; +import workerThreads from 'node:worker_threads'; +import zlib from 'node:zlib'; /** * A map of the name of the modules (including `node:` prefixed ones) @@ -34,64 +45,44 @@ import asyncHooks from 'node:async_hooks'; * will not be resolved properly */ export const staticNodeModulesForVM = { - zlib, - 'node:zlib': zlib, - vm, - 'node:vm': vm, - v8, - 'node:v8': v8, - util, - 'node:util': util, - url, - 'node:url': url, - tty, - 'node:tty': tty, - tls, - 'node:tls': tls, - timers, - 'node:timers': timers, - 'string_decoder': stringDecoder, - 'node:string_decoder': stringDecoder, - stream, - 'node:stream': stream, - readline, - 'node:readline': readline, - querystring, - 'node:querystring': querystring, - punycode, - 'node:punycode': punycode, - path, - 'node:path': path, - os, - 'node:os': os, - net, - 'node:net': net, - https, - 'node:https': https, - http, - 'node:http': http, - fs, - 'node:fs': fs, - 'fs/promises': fs.promises, - 'node:fs/promises': fs.promises, - events, - 'node:events': events, - domain, - 'node:domain': domain, - dns, - 'node:dns': dns, - dgram, - 'node:dgram': dgram, - crypto, - 'node:crypto': crypto, - cluster, - 'node:cluster': cluster, - 'child_process': childProcess, - 'node:child_process': childProcess, - buffer, - 'node:buffer': buffer, assert, - 'node:assert': assert, 'async_hooks': asyncHooks, - 'node:async_hooks': asyncHooks, + buffer, + 'child_process': childProcess, + cluster, + console, + constants, + crypto, + dgram, + 'diagnostics_channel': diagnosticsChannel, + dns, + domain, + events, + fs, + 'fs/promises': fsPromises, + http, + http2, + https, + inspector, + module, + net, + os, + path, + 'perf_hooks': perfHooks, + process, + punycode, + querystring, + readline, + repl, + stream, + 'string_decoder': stringDecoder, + timers, + tls, + tty, + url, + util, + v8, + vm, + 'worker_threads': workerThreads, + zlib, }; diff --git a/packages/react-email/src/utils/testing/email-template.tsx b/packages/react-email/src/utils/testing/email-template.tsx deleted file mode 100644 index 9c9ecfd106..0000000000 --- a/packages/react-email/src/utils/testing/email-template.tsx +++ /dev/null @@ -1,9 +0,0 @@ -const TestingEmailTemplate = (props: { name: string }) => { - return
Hello {props.name}!
; -}; - -TestingEmailTemplate.PreviewProps = { - name: 'Gabriel', -}; - -export default TestingEmailTemplate; diff --git a/packages/render/package.json b/packages/render/package.json index 335984499c..cb401df971 100644 --- a/packages/render/package.json +++ b/packages/render/package.json @@ -90,8 +90,8 @@ "react-promise-suspense": "0.3.4" }, "peerDependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": "^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" }, "devDependencies": { "@babel/preset-react": "7.23.3", diff --git a/packages/render/src/browser/render-async-web.spec.tsx b/packages/render/src/browser/render-async-web.spec.tsx index 12341afe10..489269f8d9 100644 --- a/packages/render/src/browser/render-async-web.spec.tsx +++ b/packages/render/src/browser/render-async-web.spec.tsx @@ -53,7 +53,7 @@ describe("renderAsync on the browser environment", () => { const actualOutput = await renderAsync(