Describe the bug
The webpack config created by storybook overrides the version of @emotion/styled used by my project, which in turn causes the theme object used by styled components to be incorrect.
I suspect this is unintentional, since Storybook shouldn't require Emotion inside the preview frame.
To Reproduce
The simplest way to see the problem is add this to your storybook config:
_.storybook/main.js_
exports.webpackFinal = (config) => {
console.log(config.resolve.alias)
return config
}
During startup, you will see that there are aliases defined for various Emotion-related libs.
To better understand why this is a problem, you need a project that uses Emotion 11 and a styled component. Consider the following example.
_.storybook/preview.tsx_:
import {ThemeContext} from '@emotion/react'
export const decorators = [
(Story) => (
<ThemeContext.Provider theme={{colors: {red: '#ff0000'}}}>
<Story />
</ThemeContext.Provider>
)
]
_components/RedBox.tsx_
import styled from '@emotion/styled' // storybook will alias this to Emotion v10
import {useTheme} from '@emotion/react' // this library only exists in Emotion v11
// This will work
const RedBoxWorking = ({children}) => {
const theme = useTheme()
return <div css={{color: theme.colors.red}}
}
// This won't work, it's using a different version of emotion and reading the default context value (an empty object by default)
const RedBoxBroken = styled.div(theme => ({ color: theme.colors.red }))
If necessary I will create a repo containing the above bits, but since I believe this is just an oversight I haven't yet.
Expected behavior
Storybook does not interfere with the versions of libraries used by my project.
System:
Environment Info:
System:
OS: macOS 10.15.6
CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
Binaries:
Node: 13.10.1 - /usr/local/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.13.7 - /usr/local/bin/npm
Browsers:
Chrome: 84.0.4147.135
Firefox: 79.0
Safari: 13.1.2
Additional context
It seems likely that some of the comments about Emotion 11 on issue #10231 were actually seeing this issue.
It seems that there are number of other bits of config that may cause @emotion/styled to be resolved incorrectly. So far I've tried:
resolve.aliases with omit(config.resolve.alias, key => /emotion/.test(key))storybook --no-dllconfig.resolve.plugins (no idea what it was)@emotion/styled v11.Even after doing all of these things, my component code seems to be importing v10 of @emotion/styled.
However, at least one user on the Emotion Slack has reported that they are using Emotion 11 and Storybook 6 together with no problems, so I'm hoping that I can get some advice from them and pinpoint what's different about my setup.
Edit: they were actually using Emotion 10
As an extra step of debugging, I've put this into my preview.tsx:
import styledPkg from '@emotion/styled/package.json'
console.log('@emotion/styled version:', styledPkg.version)
And the output: @emotion/styled version: 10.0.27
We are facing the same issue and it prevents us from updating or even trying emotion@11.
The issue is caused by a hard dependency of @storybook/theming and @emotion/styled-base in various @storybook/* packages.
I have finally come up with a working config! It's not pretty, but it's working for styled, useTheme and the css prop.
My _.storybook/main.js_ now looks like this:
const { DllReferencePlugin } = require('webpack')
exports.stories = ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)']
exports.addons = ['@storybook/addon-links', '@storybook/addon-essentials']
// Our webpack config, used to replace module.rules as described in https://storybook.js.org/docs/react/configure/webpack#using-your-existing-config
const webpackConfig = require('../webpack.config.js')
exports.webpackFinal = async (their, { configType }) => {
const our = webpackConfig({ production: configType === 'PRODUCTION' })
return {
...their,
resolve: {
...their.resolve,
alias: emotionless(their.resolve.alias),
},
module: {
...their.module,
rules: our.module.rules
},
plugins: their.plugins.map(plugin => {
// clone the config of the DllReferencePlugin and remove references to emotion libs
if (plugin instanceof DllReferencePlugin) {
const { name, content } = require(plugin.options.manifest)
return new DllReferencePlugin({
context: plugin.options.context,
name,
content: emotionless(content)
})
} else {
return plugin
}
})
}
}
// make a shallow copy of an object, rejecting keys that match /emotion/
function emotionless(object, predicate) {
let result = {}
for (key in object) {
if (!/emotion/.test(key)) {
result[key] = object[key]
}
}
return result
}
IMPORTANT NOTE
Removing the aliases and DLL references is not enough on it's own, you also need to replace the default babel config. Otherwise it will use an emotion 10 version of babel-plugin-emotion (my emotion 11 project is using @emotion/babel-preset-css-prop). In the above config this was accomplished by replacing config.module.rules, but you can also do it by adding a .babelrc in the appropriate location as explained here: https://storybook.js.org/docs/react/configure/babel
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
Dear stalebot. We understand that you are not smart enough to understand the impact this issue has.
I wanted to inform you that this issue prevents several users/organizations from updating core-dependencies in their projects.
:trollface:
@pixelass we'll try to remove the need for webpack DLLs in 6.1. in the meantime if you any PRs to address this issue I'd be happy to review.
Most helpful comment
@pixelass we'll try to remove the need for webpack DLLs in 6.1. in the meantime if you any PRs to address this issue I'd be happy to review.