Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

babel-preset-css-prop does not work with Storybook #1306

Closed
LukeAskew opened this issue Apr 8, 2019 · 9 comments
Closed

babel-preset-css-prop does not work with Storybook #1306

LukeAskew opened this issue Apr 8, 2019 · 9 comments

Comments

@LukeAskew
Copy link

LukeAskew commented Apr 8, 2019

  • emotion version: 10.0.9
  • react version: 16.8.3
  • storybook version 5.0.6

Relevant code:

// babel.config.js
module.exports = {
  presets: [
    'react-app',
    '@emotion/babel-preset-css-prop',
  ],
  plugins: [
    'emotion',
  ],
};
// Button.jsx
import React from 'react';
import { css } from '@emotion/core';

const Button = props => (
  <button
    css={css`
      background-color: blue;

      &:hover {
        background-color: lightblue;
      }
    `}
  >
    {'Hello'}
  </button>
);

export default Button;

What you did:

Bootstrap a new Storybook instance:

npx -p @storybook/cli sb init --type react

What happened:

Output is <button css="[object Object]">Hello</button>

Problem description:

The css prop is not transformed. It does, however, work when using /** @jsx jsx */ pragma.

Per https://storybook.js.org/docs/configurations/custom-babel-config/ Storybook uses the app's babel config so the note about custom configs should not apply.

@gregberge
Copy link

The problem is that React presets is applied whatever we do.

A temporary workaround:

// .storybook/webpack.config.js
module.exports = ({ config }) => {
  // Remove react preset to make emotion work
  config.module.rules[0].use[0].options.presets.splice(1, 1)
  return config
}

The best would be to create a stronger function to find the "react" preset and remove it. I don't have time right now 😅

@damusnet
Copy link

Hey @neoziro, thanks a lot for explaining what's going on! FWIW I think your one-liner is perfectly well suited for the job, but just for the sake of over-engineering, here is a more complex approach 😂:

// .storybook/webpack.config.js
module.exports = ({ config }) => {
  const rules = config.module.rules;

  // Find the rule handling .jsx
  const javaScriptRuleIndex = rules.findIndex(rule => rule.test.test('.jsx'));

  const javaScriptRules = rules[javaScriptRuleIndex];
  const javaScriptRulePresets = javaScriptRules.use[0].options.presets;

  // Find the react preset
  const reactPresetIndex = javaScriptRulePresets.findIndex(preset => {
    if (typeof preset !== 'string') return false;
    return preset.match('preset-react');
  });

  // Remove the react preset
  javaScriptRulePresets.splice(reactPresetIndex, reactPresetIndex);

  return config;
};

@LukeAskew
Copy link
Author

LukeAskew commented Apr 25, 2019

Played around a bit with these solutions and realized that Storybook only supports loading .storybook/.babelrc and not babel.config.js.

It only loads from .storybook (not root, where most babel configs are located), and only supports .babelrc.

If you drop a .babelrc file in .storybook/ then it works.

🤦‍♂️

@damusnet
Copy link

🤦‍♂️ indeed, but good to know!

That would be an issue with Storybook then. They seem to have several conflicting open issues around .babelrc config files, but it's weird that the one behavior that is explicitly documented would not work.

Thanks for looking into this!

@duncanleung
Copy link

In my project I was able to get Storybook to recognize css-prop (without using the jsx pragma) by adding this config to /.storybook/webpack.config.js.

Line 17 - Line 19:

  config.module.rules[0].use[0].options.presets = [
    require.resolve('@babel/preset-react'),
    require.resolve('@babel/preset-env'),
    // Emotion preset must run BEFORE reacts preset to properly convert css-prop.
    // Babel preset-ordering runs reversed (from last to first). Emotion has to be after React preset.
    require.resolve('@emotion/babel-preset-css-prop'),
  ];

Also, I am including the @emotion/babel-preset-css-prop for .ts and .tsx files

Line 41 - Line 43:

  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    loader: require.resolve('babel-loader'),
    options: {
      presets: [
        ['react-app', { flow: false, typescript: true }],
        // Emotion preset must run BEFORE reacts preset to properly convert css-prop.
        // Babel preset-ordering runs reversed (from last to first). Emotion has to be after React preset.
        require.resolve('@emotion/babel-preset-css-prop'),
      ],
      // other plugins here...
    },
  });

I created a template to share my project config that uses Gatsby + TypeScript + Emotion + Storybook + React Intl + SVGR + Jest:
https://github.com/duncanleung/gatsby-typescript-emotion-storybook

Here's a link to my webpack.config.js that enables @emotion/babel-preset-css-prop:

@tszekely
Copy link

Thanks @duncanleung , the adding the second code config to my webpackFinal config in Storybook main.js worked for me!

@iamyoki
Copy link

iamyoki commented Sep 16, 2021

.storybook/main.js

module.exports = {
  ...,
  babel: async (options) => ({
    ...options,
    presets: [...options.presets, '@emotion/babel-preset-css-prop'],
  }),
}

https://storybook.js.org/docs/react/configure/babel#gatsby-focus-wrapper

@hugotox
Copy link

hugotox commented Apr 30, 2022

Thanks @iamyoki your snippet worked for me! (SB 6.4.19, emotion 11.0.9, react 17.0.2, typescript 4.6.3)

@okinawaa
Copy link

@iamyoki this safe my life thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants