Skip to content

Flag: "React is not defined" in production builds with tsup + emitDecoratorMetadata #3177

@sfbaker7

Description

@sfbaker7

What versions are you using? (if relevant)

@react-email/components@1.0.11, react-email@5.2.10, etc.

Describe the Bug

Not a react-email bug, just a gotcha that might be worth a docs mention since it affects an unrelated tsconfig flag.

What I encountered:
(tsup bug)
With emitDecoratorMetadata: true, tsup silently routes all .tsx files through SWC instead of esbuild. SWC defaults to React.createElement, ignoring both your tsconfig's jsx: "react-jsx" and any esbuildOptions you set. Combined with external: ["react"] (per react-email's recommendation), you get an error like:

ReferenceError: React is not defined
    at MyEmail (file:///app/backend/dist/index.js:28090:3)
    at sendMyEmail (file:///app/backend/dist/index.js:28548:36)
    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
    at async emailResolver.sendEmail 
(file:///app/backend/dist/index.js:28371:5)

Who's affected

Anyone using react-email with tsup whose tsconfig includes emitDecoratorMetadata: true (E.g. if you use TypeORM, type-graphql, NestJS)

What is affected (leave empty if unsure)

No response

Link to the code that reproduces this issue

N/A

To Reproduce

tsconfig.json:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "jsx": "react-jsx"
  }
}

tsup.config.ts:

import { defineConfig } from "tsup";

export default defineConfig({
  entry: ["src/index.ts"],
  format: "esm",
  external: ["react"],
  esbuildOptions(options) {
    options.jsx = "automatic";
    options.jsxImportSource = "react";
  },
});

emails/Foo.tsx:

import { Container, Text } from "@react-email/components";

export default function FooEmail({ name }: { name: string }) {
  return (
    <Container>
      <Text>Hello {name}</Text>
    </Container>
  );

Expected Behavior

Bundle output contains React.createElement() with no React import.

Workarounds

export default defineConfig({
  // ...
  swc: {
    jsc: {
      transform: {
        react: {
          runtime: "automatic",
          importSource: "react",
        },
      },
    },
  },
});

What's your node version? (if relevant)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions