Created
November 7, 2023 11:49
-
-
Save samvv/2c51f6d82c64cf2a90606f25a968f3ba to your computer and use it in GitHub Desktop.
Configure Storybook to use Emotion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require('path'); | |
function toArray(value) { | |
return Array.isArray(value) ? value : [ value ]; | |
} | |
const babelLoaderModulePath = require.resolve('babel-loader'); | |
const emotionBabelPluginModulePath = require.resolve('@emotion/babel-plugin'); | |
const babelPresetReactModulePath = require.resolve('@babel/preset-react'); | |
function findBabelConfig(webpackConfig) { | |
for (const ruleConfig of webpackConfig.module.rules) { | |
if (ruleConfig.use !== undefined) { | |
const useConfigList = toArray(ruleConfig.use); | |
for (const useConfig of useConfigList) { | |
if (useConfig.loader === babelLoaderModulePath) { | |
if (useConfig.options === undefined) { | |
useConfig.options = {}; | |
} | |
return useConfig.options; | |
} | |
} | |
} | |
} | |
return null; | |
} | |
function updateBabelPresets(babelConfig, proc) { | |
for (let i = 0; i < babelConfig.presets.length; i++) { | |
let preset = babelConfig.presets[i]; | |
if (!Array.isArray(preset)) { | |
preset = [ preset, {} ]; | |
} | |
const [ name, options ] = preset; | |
if (proc(options, name) === true) { | |
babelConfig.presets[i] = [ name, options ]; | |
} | |
} | |
} | |
function patchBabelForEmotion(config) { | |
const babelConfig = findBabelConfig(config); | |
if (babelConfig === null) { | |
console.error(`Could not find the Babel configuration inside the Webpack config while it should be there.`); | |
console.error(`This is probably a bug in @samvv/storybook-preset-emotion.`); | |
console.error(`Continuing with Emotion preset disabled.`); | |
return; | |
} | |
// Emotion's plugin must run early so that it can detect the JSX tags | |
// Last is first so we use push | |
babelConfig.plugins.push(emotionBabelPluginModulePath); | |
updateBabelPresets(babelConfig, (options, name) => { | |
// Update '@babel/preset-react' to use Emotion | |
if (name === babelPresetReactModulePath) { | |
options.runtime = 'automatic'; | |
options.importSource = '@emotion/react'; | |
return true; | |
} | |
}) | |
} | |
module.exports = { | |
"stories": [ | |
"../src/**/*.mdx", | |
"../src/**/*.stories.@(js|jsx|ts|tsx)" | |
], | |
"addons": [ | |
"@storybook/addon-links", | |
"@storybook/addon-essentials", | |
"@storybook/addon-interactions" | |
], | |
"framework": { | |
"name": "@storybook/react-webpack5", | |
"options": {} | |
}, | |
"docs": { | |
"autodocs": "tag" | |
}, | |
"webpackFinal": async (config) => { | |
patchBabelForEmotion(config); | |
return config; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment