Skip to content

Instantly share code, notes, and snippets.

@samvv
Created November 7, 2023 11:49
Show Gist options
  • Save samvv/2c51f6d82c64cf2a90606f25a968f3ba to your computer and use it in GitHub Desktop.
Save samvv/2c51f6d82c64cf2a90606f25a968f3ba to your computer and use it in GitHub Desktop.
Configure Storybook to use Emotion
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