emotion version: 10.0.9react version: 16.8.3storybook version 5.0.6Relevant 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.
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 😅
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;
};
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.
🤦♂️
🤦♂️ 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!
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:
Thanks @duncanleung , the adding the second code config to my webpackFinal config in Storybook main.js worked for me!
Most helpful comment
Played around a bit with these solutions and realized that Storybook only supports loading
.storybook/.babelrcand notbabel.config.js.It only loads from
.storybook(not root, where most babel configs are located), and only supports.babelrc.If you drop a
.babelrcfile in.storybook/then it works.🤦♂️