storybook: Storybook broken when no React import with new JSX transform from react > 16.14.0

Describe the bug React 16.14.0 introduced the new JSX transform, which means you don’t have to import React when when you use JSX anymore. Sadly, I am not able to remove any import from the components/stories used in storybook. Did I miss something ? 🤔

To Reproduce Steps to reproduce the behavior:

  1. Create a new React app npx create-react-app my-app && cd my-app
  2. Check that it’s on React > 16.14 (should be)
  3. Add storybook npx sb init
  4. Run storybook npm run storybook
  5. Remove the import React from 'react' from the .stories.js or .js file of one component and go to the story of this component (you might need to disable the react/react-in-jsx-scope eslint rule)
  6. It breaks 💥 React is not defined

Expected behavior A beautiful and shiny story ✨

Screenshots image

System

Environment Info:

  System:
    OS: macOS 10.15.6
    CPU: (8) x64 Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
  Binaries:
    Node: 14.13.0 - ~/.nvm/versions/node/v14.13.0/bin/node
    Yarn: 1.22.4 - ~/.yarn/bin/yarn
    npm: 6.14.8 - ~/.nvm/versions/node/v14.13.0/bin/npm
  Browsers:
    Chrome: 86.0.4240.111
    Safari: 13.1.2
  npmPackages:
    @storybook/addon-actions: ^6.0.26 => 6.0.26
    @storybook/addon-essentials: ^6.0.26 => 6.0.26
    @storybook/addon-links: ^6.0.26 => 6.0.26
    @storybook/node-logger: ^6.0.26 => 6.0.26
    @storybook/preset-create-react-app: ^3.1.4 => 3.1.4
    @storybook/react: ^6.0.26 => 6.0.26

I also tried with storybook 6.1.0-alpha.28, same results

About this issue

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

Most upvoted comments

Problem is with @storybook/react. It adds the @babel/preset-react preset without the requisite runtime: 'automatic' option set.

This worked for me:

// main.js
module.exports = {
  // ...
  babel: async (options) => ({
    ...options,
    presets: [
      ...options.presets,
      [
	'@babel/preset-react', {
	  runtime: 'automatic',
	},
        'preset-react-jsx-transform' // Can name this anything, just an arbitrary alias to avoid duplicate presets'
      ],
    ],
  }),
};

Hi @shilman, unfortunately this is still an issue for Storybook Manager (using Storybook v7). If React is not explicitly imported when creating a custom panel, the whole app breaks.

For any sorry soul who wandered here to fix that pesky ModuleNotFoundError: Module not found: Error: Can't resolve 'react/jsx-runtime' error, in my case I was too unfamiliar with the storybook configuration that I didn’t notice that it existed in a different spot, away from the root of the project where all the other webpack configs laid. So, heading to stories/config/webpack.config.js I finally found the config and added the alias:

  config.resolve.alias = {
    // react: require.resolve('react'),
    'react/jsx-runtime': require.resolve('react/jsx-runtime'),
    'react-dom': require.resolve('react-dom'),
    'react-hot-loader': require.resolve('react-hot-loader'),
    'styled-components': require.resolve('styled-components'),
  }

Which actually required me to comment out the react alias. I’m not quite sure why, but it seems to have conflicted with the jsx runtime. Interesting behavior, indeed. Hopefully it now works.

@sigginjals Yeah. I needed to add runtime: "automatic" to React’s preset option in the manager’s webpack config:

modul.exports = {
  ...
  managerWebpack: (c) =>
     setReactRuntimeAutomatic(c),
};
  
const modifyConfigModuleRules = (fn) => (config) => {
  return {
    ...config,
    module: {
      ...config.module,
      rules: fn(config.module.rules),
    },
  };
};

const setReactRuntimeAutomatic = modifyConfigModuleRules((rules) => {
  return rules.reduce((acc, next) => {
    if (
      isNonNullObjectWithField(next, "use") &&
      isNonNullArray(next.use) &&
      next.use[0] &&
      isNonNullObjectWithField(next.use[0], "options") &&
      isNonNullObjectWithField(next.use[0].options, "presets")
    ) {
      const presets = next.use[0].options.presets;
      next.use[0].options.presets = presets.reduce((pAcc, pNext) => {
        if (
          typeof pNext === "string" &&
          pNext.includes("manager-webpack5") &&
          pNext.includes("preset-react")
        ) {
          pAcc.push([pNext, { runtime: "automatic" }]);
        } else {
          pAcc.push(pNext);
        }
        return pAcc;
      }, []);
    }
    acc.push(next);
    return acc;
  }, []);
});

Jeepers creepers!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.1.0-alpha.30 containing PR #12899 that references this issue. Upgrade today to the @next NPM tag to try it out!

npx sb upgrade --prerelease

Closing this issue. Please re-open if you think there’s still more to do.

This doesn’t seems to work with Yarn 2. I am not getting the runtime: ‘automatic’, even with React 17 and react/jsx-runtime being present and that is probably because of the paths used may not be working with Yarn (Yarn 2 does not store files in node_modules but zipped in its .yarn/cache instead).

Upgrading to latest alpha fixed my issue. Will now patiently wait until the fix gets merged into the stable release.

Thanks!

NOTE: this is hopefully fixed in 6.1 ☝️ . We need to get it back into the stable release, but are having problems with repros in CI. In the meantime if people can upgrade to 6.1 to test it out, please give it a try and report back:

npx sb upgrade --prerelease

If it doesn’t work right away, try removing & regenerating lockfiles.

Matthew,

In regards to a computer/ laptop that’s not going to be an option mine recently broke, and on anyone who else is involved could be storybooks.

But I look forward to our call, and the savings plan is right, just don’t understand why I have so many accounts open

Richard Voyles

Richard Voyles

On Oct 23, 2020, at 11:10 AM, RookY2K notifications@github.com wrote:

Problem is with @storybook/react. It adds the @babel/preset-react preset without the requisite runtime: ‘automatic’ option set.

This means you cannot just add the @babel/preset-react to the babel property in your main.js.

A hacky workaround that worked for me:

// main.js module.exports = { // … babel: async (options) => { const reactPresetIndex = options.presets.findIndex((preset) => preset.includes(‘preset-react’)); const presetsWithoutReact = [ …options.presets.slice(0, reactPresetIndex), …options.presets.slice(reactPresetIndex + 1), ];

return {
  ...options,
  presets: [
    [
'@babel/preset-react', {
  runtime: 'automatic',
},

], …presetsWithoutReact ], }; }, }; — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.