11

I am trying to use esbuild with external react.

here is my esbuild command in my package.json file

  "scripts": {
    "esbuild": "esbuild ./src/index.js --bundle --outfile=dist/esmain.js --loader:.js=jsx --external:react-dom --external:react "
  }

when running the command, I get no errors:

npm run esbuild

> @1.0.0 esbuild C:\prog
> esbuild ./src/index.js --bundle --outfile=dist/esmain.js --loader:.js=jsx --external:react-dom --external:react


  dist\esmain.js  32.7kb

Done in 13ms

The problem is that when I run the program in the browser (chrome), I get this error in the console

Uncaught Error: Dynamic require of "react" is not supported
    at __require (esmain.js:12)
    at esmain.js:27
    at esmain.js:899

Any ideas how to fix this?

yigal
  • 3,923
  • 8
  • 37
  • 59
  • Did you ever figure out a solution to this? I'm having a similar issue with importing babylonjs, where I'm trying to use external in my bundle so I can just use the cdn version of babylonjs in a script tag but getting similar error – Homan Dec 07 '21 at 08:15
  • Are you using TypeScript? It might be the one transforming imports to require – Eric Burel Jan 21 '22 at 10:23
  • See https://github.com/evanw/esbuild/issues/1944 – Eric Burel Jan 21 '22 at 10:26

4 Answers4

10

Problem

When you get this error, it means you have require("react") somewhere in your esm build result.

Solution

  1. Search for require("react") in your build directory e.g. your-package/dist
  2. Check which dependency has caused this. For me, one of them was @emotion/styled
var require_emotion_styled_base_cjs_prod = __commonJS({
  "../../node_modules/@emotion/styled/base/dist/emotion-styled-base.cjs.prod.js"(exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var _extends3 = require_extends();
    var React27 = __require("react");
  1. Fix it by either
  • Adding the package to the external option of esbuild in your tsup.config.ts to exclude it from your build.

https://esbuild.github.io/api/#external

tsup.config.ts:

import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  dts: true,
  format: ['esm', 'cjs'],
  outExtension({ format }) {
    return {
      js: `.${format}.js`,
    };
  },

  // Add this
  esbuildOptions(options) {
    options.external = ['@emotion/*'];
  },
});
  • Or, by installing the dependency. In my case, after adding the @emotion/styled to my dependencies, there were no require("react") in my build results anymore.
Sinapcs
  • 2,495
  • 1
  • 20
  • 23
  • 1
    Thank you it helped me a lot "Check which dependency has caused this. For me, one of them was @emotion/styled". So for me it was @mui/icons-material. Note that you can simply use "external" prop in tsup config instead of "esbuildOptions" ```external: ['react', 'react-dom', '@mui/icons-material']``` – Konrad Grzyb Jan 06 '23 at 00:52
  • 1
    My imported package is in dependencies, but still have problem with dynamic require in myfile.mjs ( – CodeBy Jun 15 '23 at 17:49
5

If what you were tryinig to do was to access react and react-dom from global window scope like window.React and window.ReactDOM, then this is NOT what esbuil external option does.

According to documentation:

Instead of being bundled, the import will be preserved (using require for the iife and cjs formats and using import for the esm format) and will be evaluated at run time instead.

On top of that, I assume, esbuild adds some check whether the require is supported in the target environment, which in the browser it is not by default. Hence the error.

You would need the esbuild-plugin-external-global and configure the plugin as such:

esbuild.build({
  ...
  plugins: [
    externalGlobalPlugin({
      'react': 'window.React',
      'react-dom': 'window.ReactDOM',
    })
  ]
  ...
});

At this point you might need a build script instead of callin esbuild with options via command line.

zithir
  • 650
  • 1
  • 7
  • 14
-1

What i think from the error is.There is somewhere in the code you have imported react like this which is actually a commonjs convention mostly used in Nodejs but not supported by Browsers

const react = require('react');

So just do a code search within your code editor against require('react') and replace it with the import statement. Hope it will work for you

  • 1
    It's not necessarily in the user's code, it most probably comes from the bundler loading CJS for externals or smth like that – Eric Burel Jan 21 '22 at 10:57
-4

What are you trying to achieve by marking react as external? Based on what I read in the doc, the only use-case I can think of is a website that has the react common js loaded & you want to reuse this code in your script. But then my question was - why have 2 apps on the same page, and on top of that build differently.

No idea if this will help, but I wrote an article about building create-react-app generated with esbuild - building react code seemed to go pretty smooth, especially comparing to some other frameworks.

Marcin Wosinek
  • 793
  • 3
  • 8
  • I want to have smaller javascript package so it i downloaded faster to the user machine. the react part should already be there. smaller package might looks less complicated to my fellow developers – yigal Jul 22 '21 at 21:22
  • ok, sounds like something you can achieve with splitting: https://esbuild.github.io/api/#splitting – Marcin Wosinek Jul 23 '21 at 05:02