Emotion: Storybook CSS Prop Parsing

Created on 21 May 2019  路  8Comments  路  Source: emotion-js/emotion

It looks like my storybook instance is not parsing the styles I have given it from emotion. See screenshot below. Does anyone know how to fix this?
Screen Shot 2019-05-21 at 3 32 04 PM

Most helpful comment

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:

All 8 comments

Thanks @acnebs for the link, I'll close this as dupe.

@FezVrasta what did you do to actually fix this. Nothing in that other thread was working for me.

I'm using Gatsby.js and Emotion.js and this is my storybook webpack config. So far everything is working except the CSS Prop.

module.exports = ({ config }) => {
  // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/];

  // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
  config.module.rules[0].use[0].loader = require.resolve('babel-loader');

  // use @babel/preset-react for JSX and env (instead of staged presets)
  config.module.rules[0].use[0].options.presets = [
    require.resolve('@babel/preset-react'),
    require.resolve('@babel/preset-env'),
  ];

  // use @babel/plugin-proposal-class-properties for class arrow functions
  config.module.rules[0].use[0].options.plugins = [
    require.resolve('@babel/plugin-proposal-class-properties'),
  ];

  // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
  config.resolve.mainFields = ['browser', 'module', 'main'];

  return config;
};

@fexVrasta here's a working config based off the Gatsby example for configuring storybook.

module.exports = ({ config }) => {
  // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
  // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
  config.module.rules[0].use[0].loader = require.resolve("babel-loader")
  // use @babel/preset-react for JSX and env (instead of staged presets)
  config.module.rules[0].use[0].options.presets = [
    require.resolve("@babel/preset-react"),
    require.resolve("@babel/preset-env")
  ]
  config.module.rules[0].use[0].options.plugins = [
    // use @babel/plugin-proposal-class-properties for class arrow functions
    require.resolve("@babel/plugin-proposal-class-properties"),
    // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
    require.resolve("babel-plugin-remove-graphql-queries"),
  ]
  // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
  config.resolve.mainFields = ["browser", "module", "main"]

  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    loader: require.resolve('babel-loader'),
    options: {
      presets: [['react-app', { flow: false, typescript: true }], "@emotion/babel-preset-css-prop"],
      plugins: [
        require.resolve('@babel/plugin-proposal-class-properties'),
        // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
        require.resolve('babel-plugin-remove-graphql-queries'),
      ],
    },
  });
  config.resolve.extensions.push('.ts', '.tsx');

  return config
}

Main difference from the example is that the @emotion/babel-preset-css-prop preset has been added.

@njdancer thanks, works for me!

A simpler solution for those not using Typescript is to simply require the babel-preset-css-prop package:

 require.resolve("@emotion/babel-preset-css-prop")

This is what it looks like in the default Storybook Webpack config (from the Gatsby docs):

module.exports = ({ config }) => {
  config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
  config.module.rules[0].use[0].loader = require.resolve("babel-loader")
  config.module.rules[0].use[0].options.presets = [
    require.resolve("@babel/preset-react"),
    require.resolve("@babel/preset-env"),
    require.resolve("@emotion/babel-preset-css-prop"), // <= add this preset
  ]
  config.module.rules[0].use[0].options.plugins = [
    require.resolve("@babel/plugin-proposal-class-properties"),
    require.resolve("babel-plugin-remove-graphql-queries"),
  ]
  config.resolve.mainFields = ["browser", "module", "main"]
  return config
}
// default comments removed for readability

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:

FWIW I've got this working with a pretty minimal .storybook/.babelrc file:

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

Makes both TS and css prop work without more directly customizing webpack, assuming that is all you need to do.

Was this page helpful?
0 / 5 - 0 ratings