gatsby: React 17 new JSX Transform: ReferenceError: React is not defined

Description

Gatsby 2.28.1 will throw a ReferenceError: React is not defined if React is not imported on top of the file, but the new JSX Transform (built-in in Gatsby since 2.24) supports files with JSX without a React Import.

Steps to reproduce

I couldn’t reproduce this in CodeSandbox but you should easily reproduce this by rendering a component that does not import React.

Expected result

Should not throw the error and allow components without a React import to work normally

Actual result

What happened. It happens in both development and build mode The output JS file does not have any React reference:

__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(__react_refresh_utils__) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExplorerTemplate", function() { return ExplorerTemplate; });
__webpack_require__.$Refresh$.runtime = __webpack_require__(/*! ./node_modules/react-refresh/runtime.js */ "./node_modules/react-refresh/runtime.js");
__webpack_require__.$Refresh$.setup(module.i);

var _jsxFileName = "/home/bartmr/Documents/unnamed-too/client-side/web-app/src/components/templates/explorer/explorer-template.tsx";
function ExplorerTemplate() {
  return /*#__PURE__*/React.createElement("div", {
    __self: this,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 7,
      columnNumber: 5
    }
  });
}
_c = ExplorerTemplate;

var _c;

__webpack_require__.$Refresh$.register(_c, "ExplorerTemplate");

const currentExports = __react_refresh_utils__.getModuleExports(module.i);
__react_refresh_utils__.registerExportsForReactRefresh(currentExports, module.i);

if (true) {
  const isHotUpdate = !!module.hot.data;
  const prevExports = isHotUpdate ? module.hot.data.prevExports : null;

  if (__react_refresh_utils__.isReactRefreshBoundary(currentExports)) {
    module.hot.dispose(
      /**
       * A callback to performs a full refresh if React has unrecoverable errors,
       * and also caches the to-be-disposed module.
       * @param {*} data A hot module data object from Webpack HMR.
       * @returns {void}
       */
      function hotDisposeCallback(data) {
        // We have to mutate the data object to get data registered and cached
        data.prevExports = currentExports;
      }
    );
    module.hot.accept(
      /**
       * An error handler to allow self-recovering behaviours.
       * @param {Error} error An error occurred during evaluation of a module.
       * @returns {void}
       */
      function hotErrorHandler(error) {
        if (
          false
        ) {}

        if (typeof __react_refresh_test__ !== 'undefined' && __react_refresh_test__) {
          if (window.onHotAcceptError) {
            window.onHotAcceptError(error.message);
          }
        }

        __webpack_require__.c[module.i].hot.accept(hotErrorHandler);
      }
    );

    if (isHotUpdate) {
      if (
        __react_refresh_utils__.isReactRefreshBoundary(prevExports) &&
        __react_refresh_utils__.shouldInvalidateReactRefreshBoundary(prevExports, currentExports)
      ) {
        module.hot.invalidate();
      } else {
        __react_refresh_utils__.enqueueUpdate(
          /**
           * A function to dismiss the error overlay after performing React refresh.
           * @returns {void}
           */
          function updateCallback() {
            if (
              false
            ) {}
          }
        );
      }
    }
  } else {
    if (isHotUpdate && __react_refresh_utils__.isReactRefreshBoundary(prevExports)) {
      module.hot.invalidate();
    }
  }
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js */ "./node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js")))//# sourceURL=[module]
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvY29tcG9uZW50cy90ZW1wbGF0ZXMvZXhwbG9yZXIvZXhwbG9yZXItdGVtcGxhdGUudHN4LmpzIiwic291cmNlcyI6WyIvaG9tZS9iYXJ0bXIvRG9jdW1lbnRzL3VubmFtZWQtdG9vL2NsaWVudC1zaWRlL3dlYi1hcHAvc3JjL2NvbXBvbmVudHMvdGVtcGxhdGVzL2V4cGxvcmVyL2V4cGxvcmVyLXRlbXBsYXRlLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBQaGFzZXJQYWdlIH0gZnJvbSAnc3JjL2NvbXBvbmVudHMvcm91dGluZy9waGFzZXItcGFnZS9waGFzZXItcGFnZSc7XG5cblxuXG5leHBvcnQgZnVuY3Rpb24gRXhwbG9yZXJUZW1wbGF0ZSgpIHtcbiAgcmV0dXJuIChcbiAgICA8ZGl2PjwvZGl2PlxuICApO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFFQTtBQUpBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBIiwic291cmNlUm9vdCI6IiJ9

Environment

It happens in both development and build mode It also happens in NodeJS 12

System: OS: Linux 4.15 Ubuntu 18.04.5 LTS (Bionic Beaver) CPU: (4) x64 Intel® Core™ i7-7500U CPU @ 2.70GHz Shell: 4.4.20 - /bin/bash Binaries: Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node npm: 6.9.0 - ~/.nvm/versions/node/v10.16.0/bin/npm Languages: Python: 2.7.17 - /usr/bin/python Browsers: Chrome: 87.0.4280.88 npmPackages: gatsby: ^2.28.1 => 2.28.1 gatsby-image: ^2.7.0 => 2.7.0 gatsby-plugin-manifest: ^2.8.0 => 2.8.0 gatsby-plugin-offline: ^3.6.0 => 3.6.0 gatsby-plugin-react-helmet: ^3.6.0 => 3.6.0 gatsby-plugin-robots-txt: ^1.5.3 => 1.5.3 gatsby-plugin-sass: ^2.7.0 => 2.7.0 gatsby-plugin-sharp: ^2.10.1 => 2.10.1 gatsby-plugin-sitemap: ^2.8.0 => 2.8.0 gatsby-plugin-svgr: 2.0.2 => 2.0.2 gatsby-plugin-webpack-bundle-analyser-v2: ^1.1.18 => 1.1.18 gatsby-source-filesystem: ^2.7.0 => 2.7.0 gatsby-transformer-sharp: ^2.8.0 => 2.8.0 npmGlobalPackages: gatsby-cli: 2.7.49

Possible solution:

I was able to go around this bug by adding this to gatsby-node.js:

exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPlugin({
    name: '@babel/plugin-transform-react-jsx',
    options: {
      runtime: 'automatic',
    },
  });
};

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 15
  • Comments: 28 (5 by maintainers)

Most upvoted comments

Thanks @Bartmr for the work around. It worked perfectly! 😊

In gatsby-node.js:

exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPlugin({
    name: '@babel/plugin-transform-react-jsx',
    options: {
      runtime: 'automatic',
    },
  });
};

@steverandy @dvakatsiienko Gatsby 3 supports the new React JSX transform but it is disabled by default (#27615), you need to enable it in your .babelrc config like this:

{
  "presets": [
    [
      "babel-preset-gatsby",
      {
        "reactRuntime": "automatic"
      }
    ]
  ]
}

More info: https://www.gatsbyjs.com/docs/reference/release-notes/v3.0/#react-17

Working off @mohatt 's solution, adding this to gatsby-node.js worked for me (I do not have a .babelrc or any other custom babel config in my project). I am on gatsby 3.10.1. I am not encountering any eslint errors.

/* gatsby-node.js */
exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPreset({
    name: 'babel-preset-gatsby',
    options: {
      reactRuntime: 'automatic',
    },
  });
  // ...
}

I managed to solve the React is undefined SSR error, using the gatsby-node.js solution

exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPreset({
    name: 'babel-preset-gatsby',
    options: {
      reactRuntime: 'automatic',
    },
  })
}

However I can’t get Emotion 10 or 11 to work with the css property.

Seeing this in dev tools you have tried to stringify object returned from css function...

Which indicates the the css prop from Emotion is not properly preset in Babel.

I’m using the gatsby-plugin-emotion plugin in gatsby-config.js which used to be fine for everthing, before trying to migrate to the new way to parse JSX.

Setup

    "react": "^17.0.2",
    "gatsby": "3.7.2",
    "typescript": "^4.3.3",
    "gatsby-plugin-emotion": "^6.12.0",
    "@emotion/react": "^11.4.1",
    "@emotion/styled": "^11.3.0",
    "@emotion/babel-plugin": "^11.3.0",
    "@emotion/eslint-plugin": "^11.2.0",

I’ve tried the .babelrc solution suggested above, but that didn’t help me with the React is undefinederror.

EDIT

I finally managed to solve this, by removing gatsby-plugin-emotion from gatsby-config.js and having this in a .babelrc file.

{
  "presets": [
    [
      "@babel/preset-react",
      { "runtime": "automatic", "importSource": "@emotion/react" }
    ]
  ],
  "plugins": ["@emotion"]
}

@ibqn @codejet those are just eslint errors due to the rule react/react-in-jsx-scope being set to error. The default eslint config that comes with gatsby doesn’t know about the custom babel config in your .babelrc so you will need to use a custom eslint config that disables the following rules:

{
  // ...
  "rules": {
    // ...
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}

@codejet btw you don’t have to install babel-preset-gatsby package since it comes preinstalled with gatsby

See: https://www.gatsbyjs.com/docs/how-to/custom-configuration/eslint/ https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#eslint

@mohatt Thank you very much!

@Bartmr have you enabled react-refresh? The biggest architecture issue we’re having right now with having a flag for it, plugins like mdx, emotion still need to have the proper /** @jsxImportSource @emotion/react */