egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
9.17k stars 220 forks source link

React is not defined / JSX runtime not automatically injected #792

Open leonard-henriquez opened 1 year ago

leonard-henriquez commented 1 year ago

I wanted to switch from SWC to TSup to reduce the complexity of my configuration.

From what I've read in ESbuild documentation and TSup changelog, I expected TSup to automatically pickup my JSX config from tsconfig.json settings.

However, when I tried to install TSup, I got the error React is not defined (see the configuration below). Besides, when I look at the generated file, I notice that React.createElement is used while React is never defined.

Capture d’écran 2022-12-04 à 23 54 08

Configuration:

// tsconfig.json
{
  "extends": "tsconfig-base",
  "compilerOptions": {
    "incremental": false,
    "baseUrl": ".",
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react",
    "lib": ["ES2017", "DOM"],
  },
  "include": ["src", "global.d.ts"],
  "exclude": ["node_modules", "dist"]
}

// tsup.config.js
import { defineConfig } from 'tsup';
import path from 'path';

export default defineConfig({
  tsconfig: path.resolve(__dirname, './tsconfig.json'),
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],
  clean: true,
  external: ['react', 'react-dom', '@emotion/react', '@emotion/styled'],
});

// package.json
{
  "name": "my-package",
  "dependencies": {
    "react": "^18.2.0",
    // ...others deps
  },
  "devDependencies": {
    "@emotion/react": "^11.10.0",
    "@emotion/styled": "^11.10.0",
    "tsup": "6.5.0",
    "typescript": "^4.9.3",
    // ...others deps
  },
  "peerDependencies": {
    "@emotion/react": "^11.10.0",
    "@emotion/styled": "^11.10.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    // ...others deps
  }
}

Related issues:

PS: I succeeded to make it work by injecting React as mentioned in the related issues but the solution is not

// tsup.config.js
export default defineConfig({
  // other props
  inject: [path.resolve(__dirname, './react-shim.js')],
});

// react-shim.js
import React from 'react';
export { React };

Upvote & Fund

Fund with Polar

leonard-henriquez commented 1 year ago

After hours (and hours) of debugging, I finally understood that if we use emitDecoratorMetadata: true in our tsconfig.json SWC is used instead of esbuild. In this case it seems that some configuration options from the tsconfig.json are not picked up (such as compilerOptions.jsx). .swcrc files do not seem to be used either.

@egoist , do you know how can I specify a JSX runtime if I have emitDecoratorMetadata set to true ?

PS: It is written somewhere in the documentation (in the troubleshooting section) but the fact that changing emitDecoratorMetadata to true has the side effect of changing the build system is quite surprising. I think I would be more appropriate to have an actual TSup setting to choose which build system we want (with only SWC being available if you want to use emitDecoratorMetadata)

haydenbleasel commented 1 year ago

Not sure if this helps at all, but I had a similar issue with a Design System that's bundled with tsup.

The consumer was throwing the error ReferenceError: React is not defined and sure enough, the compiled DS code had React.createElement with no React definition.

I changed compilerOptions.jsx in tsconfig.json to "react-jsx" as that property allegedly remaps all React.createElement calls to _jsx calls.

Seems to work now. Will let you know if something blows up later unintentionally 😅

frandiox commented 1 year ago

We got the same error in shopify/hydrogen. We were compiling with compilerOptions.jsx: preserve (tsconfig here) just fine using tsup@6.5 (example). However, after updating to tsup@7.2.0, it started ignoring "preserve" and compile JSX to React.createElement without importing React in the files (example).

Changing the tsconfig to use compilerOptions.jsx: react-jsx fixes the issue for us.

L-Blondy commented 4 months ago

Adding "react-jsx" to the compiler options adds "react/jsx-runtime" as a hard dependency to your bundle.

I solved it using "preserve" in the compilerOptions + adding import React from 'react' to my files

bertho-zero commented 3 days ago

To build js you don't have tsconfig.json and you have to add this to tsup.config.js to not get the error "React is not defined":

  esbuildOptions(options) {
    options.jsx = 'automatic';
  },