Closed FK78 closed 1 year ago
Hey @FK78
errors like this occur when sass files are processed twice. This means that your webpack config already has sass rules in it before you prepend your custom rules in main.js
@storybook/preset-create-react-app
uses the webpack config included in react-scripts
, so if you are using react-scripts@2.x.x
and up, your storybook will already have the scss, css modules, and postcss webpack settings that react-scripts provides.
This means that you have two options.
require('dotenv').config();
const path = require('path');
const { nodeModulesEs6IncludeRegExp } = require('../config/webpack.helpers');
const { ENVIRONMENT } = process.env;
module.exports = {
core: {
builder: "webpack5",
},
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/preset-create-react-app',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-postcss',
'@storybook/addon-a11y',
],
webpackFinal: async config => {
const newConfig = { ...config };
newConfig.module.rules[1].include = nodeModulesEs6IncludeRegExp;
// Remove existing scss rules
const newRules = newConfig.module.rules.filter(({ test }) => !test.test('test.scss'));
// Sass loader rules
newRules.unshift(
{
test: /\.scss$/,
include: path.resolve('src'),
use: [
require.resolve('style-loader'),
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
auto: true,
localIdentName: '[name]__[local]--[hash:base64:5]',
},
},
},
{
loader: 'sass-loader',
options: {
additionalData: '$use-cdn-fonts: false;'
},
},
],
},
{
test: /\.(sa|sc|c)ss$/,
include: file =>
file.includes('node_modules/custom-module),
sideEffects: true,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
type: 'asset',
},
);
// Set the config rules to our new rule set
newConfig.module.rules = newRules
// Return the altered config
return newConfig;
},
};
Additionally, you can also remove @storybook/preset-postcss
as create react app has this configured for you already.
With all of that configured you can remove the inline loaders to import your scss file in preview.js
like so:
-import '!style-loader!css-loader!sass-loader!../src/stylesheets/index.scss';
+import '../src/stylesheets/index.scss';
// process.env is populated by dotenv at the start of main.js
window.process = { env: process.env }
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
EDIT: I always mix up .match
and .test
😅
Thanks for the reply @Integrayshaun
Here is the webpack.config.js
file:
// Gather stylesheets from src
{
test: /\.(css|scss)$/,
include: paths.appSrc,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
auto: true,
localIdentName: isDev
? '[dirname]_[name]_[local]-[hash:base64:5]'
: '[shortcamelname]_[local]-[hash:base64:5]', // This saves nearly 2kB across gzipped main.js and main.css
},
},
},
'postcss-loader',
{
loader: 'sass-loader',
options: {
additionalData: `$use-cdn-fonts: ${
['prod', 'production', 'shadow'].includes(ENVIRONMENT)
? 'true'
: 'false'
};`,
},
},
],
},
// Gather scss files from within node_modules (specifically required for the custom package)
{
test: /\.(sa|sc|c)ss$/,
include: sassFile =>
sassFile.includes('node_modules/custom-package'),
sideEffects: true,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
// Images are copied or inlined based on the file size
{
test: /\.(jpg|jpeg|png|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 10kb
},
},
},
// Other assets
{
test: /\.svg$/,
type: 'asset/resource',
},
Removing the custom rules throws some new errors:
Error: => Webpack failed, learn more with --debug-webpack
ERR! Module build failed (from ./node_modules/@svgr/webpack/lib/index.js):
ERR! SyntaxError: unknown file: Namespace tags are not supported by default. React's JSX doesn't support namespace tags. You can set `throwIfNamespace: false` to bypass this warning.
Module not found: Error: Can't resolve './fonts/fonts/HeroicCondensedNumerals-Normal.woff' in '/src/stylesheets'
Fixed the above by removing an extra /fonts/
.
I tried option 2 as well, but was hit with:
TypeError: test.match is not a function
It seems that before upgrading to Node 18 the react-scripts
module was failing to load (on purpose maybe?) which meant everything worked as intended.
@FK78 Apologies, I meant test.test('test.scss')
not test.match('test.scss')
Okay, so if you have a custom webpack configuration like this you're best to merge it with Storybook's config
@Integrayshaun
test.test
throws the same error:
ERR! TypeError: test is not a function
Maybe I'm missing an import or dependency?
ah, it's likely that some of the tests are string patterns instead of regex. Try using a function in the filter like this:
const isRuleForSCSS = (rule) =>
typeof rule !== "string" &&
rule.test instanceof RegExp &&
(rule.test.test("test.scss") || rule.test.test("test.sass"));
ah, it's likely that some of the tests are string patterns instead of regex. Try using a function in the filter like this:
const isRuleForSCSS = (rule) => typeof rule !== "string" && rule.test instanceof RegExp && (rule.test.test("test.scss") || rule.test.test("test.sass"));
Where am I adding this? Could you update this example to show how its going to be used? Thank you.
Hey @Integrayshaun are you still able to help with the above?
@FK78 use the isRuleForSCSS
function to filter out scss rules
require('dotenv').config();
const path = require('path');
const { nodeModulesEs6IncludeRegExp } = require('../config/webpack.helpers');
const { ENVIRONMENT } = process.env;
const isRuleForSCSS = (rule) =>
typeof rule !== "string" &&
rule.test instanceof RegExp &&
(rule.test.test("test.scss") || rule.test.test("test.sass"));
module.exports = {
core: {
builder: "webpack5",
},
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/preset-create-react-app',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-postcss',
'@storybook/addon-a11y',
],
webpackFinal: async config => {
const newConfig = { ...config };
newConfig.module.rules[1].include = nodeModulesEs6IncludeRegExp;
// Remove existing scss rules
const newRules = newConfig.module.rules.filter(isRuleForSCSS);
// Sass loader rules
newRules.unshift(
{
test: /\.scss$/,
include: path.resolve('src'),
use: [
require.resolve('style-loader'),
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
auto: true,
localIdentName: '[name]__[local]--[hash:base64:5]',
},
},
},
{
loader: 'sass-loader',
options: {
additionalData: '$use-cdn-fonts: false;'
},
},
],
},
{
test: /\.(sa|sc|c)ss$/,
include: file =>
file.includes('node_modules/custom-module),
sideEffects: true,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
type: 'asset',
},
);
// Set the config rules to our new rule set
newConfig.module.rules = newRules
// Return the altered config
return newConfig;
},
};
@FK78 use the
isRuleForSCSS
function to filter out scss rulesrequire('dotenv').config(); const path = require('path'); const { nodeModulesEs6IncludeRegExp } = require('../config/webpack.helpers'); const { ENVIRONMENT } = process.env; const isRuleForSCSS = (rule) => typeof rule !== "string" && rule.test instanceof RegExp && (rule.test.test("test.scss") || rule.test.test("test.sass")); module.exports = { core: { builder: "webpack5", }, stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: [ '@storybook/preset-create-react-app', '@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-postcss', '@storybook/addon-a11y', ], webpackFinal: async config => { const newConfig = { ...config }; newConfig.module.rules[1].include = nodeModulesEs6IncludeRegExp; // Remove existing scss rules const newRules = newConfig.module.rules.filter(isRuleForSCSS); // Sass loader rules newRules.unshift( { test: /\.scss$/, include: path.resolve('src'), use: [ require.resolve('style-loader'), { loader: 'css-loader', options: { importLoaders: 1, modules: { auto: true, localIdentName: '[name]__[local]--[hash:base64:5]', }, }, }, { loader: 'sass-loader', options: { additionalData: '$use-cdn-fonts: false;' }, }, ], }, { test: /\.(sa|sc|c)ss$/, include: file => file.includes('node_modules/custom-module), sideEffects: true, use: ['style-loader', 'css-loader', 'sass-loader'], }, { test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/, type: 'asset', }, ); // Set the config rules to our new rule set newConfig.module.rules = newRules // Return the altered config return newConfig; }, };
Getting back this error now:
ERROR in ./src/stylesheets/index.scss 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> @import 'reset-css/reset.css';
| @import 'fonts/font-face';
|
@ ./src/index.js 14:0-34
The team has decided it was more work to maintain Storybook than the benefits it provided, therefore has been removed from our repository.
Hey there, @FK78 👋
I'm sorry to hear this! Storybook is an open-source project and I'm only able to give limited support as part of my work. I hope you can understand.
I do want to fully assure you, though, that Storybook is very much worth the time of maintenance, and that's only going to increase as we continue shipping more features for our devs.
I hope that you're able to revisit this when you have more bandwidth and solve the difficulty you're facing. Alternatively, please consider joining our community discord. There may well be community members who can offer you the support you need.
Thank you @Integrayshaun, I completely understand, I hope when we have more time we'll be able to reimplement Storybook ❤️
@FK78 Sounds good, my friend! I'll be here if you need the help 😀
Hey @FK78
errors like this occur when sass files are processed twice. This means that your webpack config already has sass rules in it before you prepend your custom rules in
main.js
@storybook/preset-create-react-app
uses the webpack config included inreact-scripts
, so if you are usingreact-scripts@2.x.x
and up, your storybook will already have the scss, css modules, and postcss webpack settings that react-scripts provides.This means that you have two options.
- Remove your custom rules in favour of react-scripts existing rules
- If you want to use your custom rules, you should filter out the existing rules with something like the following:
require('dotenv').config(); const path = require('path'); const { nodeModulesEs6IncludeRegExp } = require('../config/webpack.helpers'); const { ENVIRONMENT } = process.env; module.exports = { core: { builder: "webpack5", }, stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: [ '@storybook/preset-create-react-app', '@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-postcss', '@storybook/addon-a11y', ], webpackFinal: async config => { const newConfig = { ...config }; newConfig.module.rules[1].include = nodeModulesEs6IncludeRegExp; // Remove existing scss rules const newRules = newConfig.module.rules.filter(({ test }) => !test.test('test.scss')); // Sass loader rules newRules.unshift( { test: /\.scss$/, include: path.resolve('src'), use: [ require.resolve('style-loader'), { loader: 'css-loader', options: { importLoaders: 1, modules: { auto: true, localIdentName: '[name]__[local]--[hash:base64:5]', }, }, }, { loader: 'sass-loader', options: { additionalData: '$use-cdn-fonts: false;' }, }, ], }, { test: /\.(sa|sc|c)ss$/, include: file => file.includes('node_modules/custom-module), sideEffects: true, use: ['style-loader', 'css-loader', 'sass-loader'], }, { test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/, type: 'asset', }, ); // Set the config rules to our new rule set newConfig.module.rules = newRules // Return the altered config return newConfig; }, };
Additionally, you can also remove
@storybook/preset-postcss
as create react app has this configured for you already.With all of that configured you can remove the inline loaders to import your scss file in
preview.js
like so:-import '!style-loader!css-loader!sass-loader!../src/stylesheets/index.scss'; +import '../src/stylesheets/index.scss'; // process.env is populated by dotenv at the start of main.js window.process = { env: process.env } export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }
EDIT: I always mix up
.match
and.test
😅
Thank you i fixed with this one
config.module.rules = config.module.rules?.filter( (rule) => rule && rule.test && rule.test.toString() !== '/\\.css$/' )
Describe the bug
Currently we are using Node 14, but when upgrading to Node 18 and trying to run
npm run build-storybook
I am getting these errors:Reverting
"@storybook/preset-create-react-app"
to^3.2.0
fixes the error above, but another appears:My devDependencies:
My .storybook/main.js:
My .storybook/preview.js: