React Storybook not displaying SVG icons - reactjs

I am not able to see the SVG icons in Storybook. I am new to front-end development so not sure what I am doing wrong. I referred to this article https://medium.com/#derek_19900/config-storybook-4-to-use-svgr-webpack-plugin-22cb1152f004. Here is file webpack.config.js
const path = require('path');
const rootDir = path.resolve(__dirname, '../src');
const pathToInlineSvg = path.resolve(__dirname, '../src/assets/images/icons');
module.exports = ({ config, mode }) => {
const fileLoaderRule = config.module.rules.find(rule => rule.test.test('.svg'));
fileLoaderRule.exclude = pathToInlineSvg;
config.module.rules = config.module.rules.map(rule => {
if (rule.exclude && rule.test.test('styles.scss')) {
rule.use = rule.use.map(use => {
if (use && use.loader && use.loader.indexOf('sass-loader') !== -1) {
use.options.data = `
#import "#/assets/styles/theme.scss";
#import "#/assets/styles/fonts.scss";
`;
}
return use;
});
}
return rule;
});
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.module.rules.push({
test: /\.(jsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: ["#babel/preset-env", "#salesforce/babel-preset-design-system-react"],
},
});
config.module.rules.push({
test: /\.svg$/,
include: pathToInlineSvg,
use: [{loader: '#svgr/webpack',
options: {
icon: true,
},
}
],
});
config.resolve.extensions.push('.ts', '.tsx', '.svg');
config.resolve.alias['#'] = rootDir;
return config;
};

SVGs are not loading into Storybook in your setup because Storybook’s default webpack config already has a .svg loader, and is using file-loader.
See Line 65 - Line 68 of Storybook base-webpack.config.js
If you want to use #svgr/webpack loader, you need to write a custom webpack config so that the #svgr/webpack loader rule is before the file-loader.
This webpack config rule adds the #svgr/webpack loader before any other asset loaders:
// Add SVGR Loader
// ========================================================
// Remove svg rules from existing webpack rule
const assetRule = config.module.rules.find(({ test }) => test.test('.svg'));
const assetLoader = {
loader: assetRule.loader,
options: assetRule.options || assetRule.query,
};
config.module.rules.unshift({
test: /\.svg$/,
use: ['#svgr/webpack', assetLoader],
});
You can see a complete webpack.config.js in this Gatsby starter (Gatsby + TypeScript + Emotion + Storybook)

Use storybook-preset-inline-svg.
Storybook has loaders configured that conflict with what you define in your custom Webpack configuration, so if you do not override those then your custom rules will not work.
Here's a basic way to override some of the default SVG loaders (adjust to your needs):
config.module.rules = [
...config.module.rules.map(rule => {
if (/svg/.test(rule.test)) {
// Silence the Storybook loaders for SVG files
return { ...rule, exclude: /\.svg$/i }
}
return rule
}),
// Add your custom SVG loader
{
test: /\.svg$/i,
use: ['whatever-loader-you-want']
}
]
Depending on your setup you may want to look into the Storybook preset API for Webpack to override loaders for the manager entries too.

In the newest storybook here's the solution:
Set your script on package.json to
"scripts": {
"storybook": "start-storybook -p 6006 --no-dll -s ./public",
}

Related

webpack config for nx14 react project

in documentation nx suggest to use merge option to rewrite the default webpack config
https://nx.dev/guides/customize-webpack
so, i put my custom webpack.config.js file in a project.json file
webpack.config.js file:
const { merge } = require('webpack-merge');
module.exports = (config, context) => {
return merge(config, {
module: {
rules: [
{
test: /\.sass$/i,
use: [
'style-loader',
'css-loader',
'sass-loader'
],
},
],
}
});
};
all i am trying to do is just make to read my .sass files as .module.sass
but as result i have many errors

Module parse failed: Unexpected character '#' (1:0) with Storybook 6.1.11, Webpack 5.11.0, React 17.0.1

Trying to setup a react-app with all latest versions.
Github Repo Link
Trying to run storybook with sass file imported will result in below error. Trying to run without importing the styles, storybook works.
The same code works correctly when its run as npm start run with no warnings and errors.
I have configured css modules using #dr.pogodin/babel-plugin-react-css-modules with sass, webpack 5, react 17 and with latest packages.
ERROR in ./src/assets/stylesheets/app.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 "./base.scss";
| #import "./generics/font.scss";
| #import "./generics/spacing.scss";
# ./stories/index.js 5:0-44 8:2-10:4 8:58-10:3 9:4-49
# ./src/components/atoms/button/stories.js
babel.config.js
module.exports = {
presets: ["#babel/preset-env", "#babel/preset-react"],
plugins: [
[
"#dr.pogodin/babel-plugin-react-css-modules",
{
webpackHotModuleReloading: true,
autoResolveMultipleImports: true,
filetypes: {
".scss": {
syntax: "postcss-scss",
},
},
generateScopedName: "[name]__[local]___[hash:base64:5]",
},
],
],
};
webpack.config.js for css (partial code inlcuded)
{
test: /\.(css|sass|scss)$/,
exclude: /node_modules/,
use: [
isDev ? "style-loader" : MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: {
auto: (resourcePath) =>
resourcePath.indexOf("assets/stylesheets") === -1,
localIdentName:"[name]__[local]___[hash:base64:5]",
},
sourceMap: true,
},
},
"sass-loader",
],
}
storybook/webpack.config.js file
const custom = require('../webpack.config.js');
module.exports = {
// stories: ['../src/components/**/*.stories.js'],
webpackFinal: (config) => {
return {
...config,
module: {
rules: custom.module.rules,
},
resolve: {
...config.resolve,
...custom.resolve,
}
};
},
};
I don't know what you have done with your configuration but you would define the config things inside .storybook/main.js. And for global style css is supposed to be included in preview.js file.
In short, you have to do the few things:
Remove your .storybook/config.js and add .storybook/main.js with following content:
const custom = require('../webpack.config.js');
module.exports = {
stories: [
'../src/**/stories.js', // The name should have a prefix for component name like `button.stories.js` instead of `stories.js` like you've done. As you renamed, you can remove this pattern
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
webpackFinal: (config) => {
return {
...config,
module: {
rules: custom.module.rules,
},
resolve: {
...config.resolve,
...custom.resolve,
}
};
},
};
Create the .storybook/preview.js to import your global style:
import "../src/assets/stylesheets/app.scss";
Some people have been running into problems a some scss preset when using Storybook 6.2.0 with Webpack 5. Instead of using a preset, I recommend configuring the Webpack config in main.js as mentioned above. Here's the relevant portion of a working Storybook Webpack config for Sass:
module: {
...config.module,
rules: [
...config.module.rules,
{
test: /\.(scss)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: function () {
return [require('precss'), require('autoprefixer')];
},
},
},
},
{
loader: require.resolve('sass-loader'),
options: {
implementation: require('sass'),
},
},
],
},
],
},
I've written more about getting Storybook off the ground with Webpack 5 (and modifying the Storybook Webpack config) over here.
Another reason this might happen: if you are adding new components to your app and the path defined for your sass-loader does not match anymore.
E.g. if you have this in your .storybook/main.js:
webpackFinal: async config => {
// Add SASS support
// https://storybook.js.org/docs/configurations/custom-webpack-config/#examples
config.module.rules.push({
test: /\.scss$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
compileType: "icss",
},
},
},
"sass-loader",
],
include: path.resolve(__dirname, "../"),
})
Update or completely remove the include path.

Why does my SASS style only apply partially?

I'm creating a react component library. Styling needs to be isolated, apart from some global variables. My styling is not applying everywhere, only on some pages. Why is this and how can I fix it?
My webpack.config.js:
const webpack = require('webpack');
const path = require('path');
module.exports = async ({ config, mode }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
localIdentName:
'[name]-[local]-[hash:base64:3]',
},
import: true,
importLoaders: true,
}
},
{
loader: 'sass-loader',
},
{
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve(__dirname, '../src/styles/variables/_variables.scss'),
path.resolve(__dirname, '../src/styles/variables/_header.scss'),
path.resolve(__dirname, '../src/styles/variables/_footer.scss')
]
}
}
],
});
return config;
};
For example: I have a module "Checkbox". The story for the module is below. The first story is styled, the second story is not.
stories.add('Empty', () => (
<Checkbox />
));
stories.add('With Label', () => (
<Checkbox classes={propsClasses} field={'Field'} label={'Label'} />
));
EDIT:
With the webpack.config.js below, all the styles load. But then ALL the styles load on EVERY page. Which makes for duplicate style and no longer an isolated component.
const webpack = require('webpack');
const path = require('path');
module.exports = async ({ config, mode }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
localIdentName: '[local]',
},
import: true,
importLoaders: true,
}
},
{
loader: 'sass-loader',
},
{
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve(__dirname, '../src/styles/variables/_variables.scss'),
path.resolve(__dirname, '../src/styles/variables/_header.scss'),
path.resolve(__dirname, '../src/styles/variables/_footer.scss')
]
}
}
],
});
return config;
};
Webpack bundles CSS files when they are required, the same way it bundles JS files when they are required. When using sass-loader, css-loader, and style-loader, the require will pass the Sass source code through those loaders and the result is JS code that will insert the transpiled CSS into a <style> element on the page at runtime. That JS code is what gets added to the bundle webpack creates.
I'm not familiar with sass-resources-loader, but per its README, This loader will #import your SASS resources into every required SASS module -- this is likely why you're seeing all of your styles imported for each module...?
To isolate your styles on a per-component basis, you probably want a .scss file for each component that contains styles for that component, and to require() that .scss file in its JS module. Because webpack processes each Sass file independently, as it's required, each component's Sass file will need to import any variables/mixins it needs. (It sounds like sass-resources-loader is trying to handle that for you, but not giving the desired results?)
How are you loading your Sass files currently?

Upgrading From Create-React-App to Next.js - CSS stylesheets are not working

Recently we found out that we have to use SSR for Our React Project.
I have checked with every method that I know and almost tested all methods that I've found on medium and other sites. And after a lot of work, I decided that we have to migrate to Next JS.
While the process of migrating everything is fine, but for the style sheets.
In the old version of our app, we used webpack to bundle our styles with the project and everything was fine.
This is the webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const port = process.env.PORT || 3000;
const extractSCSS = new ExtractTextPlugin('./[name].css');
// const UglifyJS = require('uglifyjs-webpack-plugin');
module.exports = {
mode: 'development',
output: {
filename: 'bundle.[hash].js',
publicPath: '/'
},
devtool: 'source-map',
module: {
rules: [
// First Rule
{
test: /\.(js)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
// Second Rule
{
test: /\.scss$/,
use: ['css-hot-loader'].concat(extractSCSS.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader?sourceMap',
options: { alias: { '../img': '../public/img' }, sourceMap: true }
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}))
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
favicon: 'public/favicon.ico'
}),
extractSCSS,
],
devServer: {
host: 'localhost',
port: port,
historyApiFallback: true,
open: true
}
};
and after I migrated the app, my next.config.js looks like this:
// next.config.js
const withSass = require('#zeit/next-sass')
const withCSS = require('#zeit/next-css')
module.exports = withCSS( withSass(
{
webpack(config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
},
)
return config
},
}
))
The problem is that everything renders correctly but there are no stylesheets in it and it doesn't contain any style. Is there anybody who could help me to solve this problem?
For just using CSS from node_modules you don't need this fancy config.
3 simple steps:
Install next-css plugin:
npm install --save #zeit/next-css
Create in your root directory next.config.js with the following content:
// next.config.js
const withCSS = require('#zeit/next-css')
module.exports = withCSS({
cssLoaderOptions: {
url: false
}
})
Now you should be able to import styleshets from node_modules like this:
import 'bootstrap-css-only/css/bootstrap.min.css';
Note: Using Next v 8+
Background:
I spent a few hours trying to simply import a CSS installed as a node_module and the various solutions are mostly hacky workarounds, but as shown above, there is a simple solution.
It was provided by one of the core team members: https://spectrum.chat/next-js/general/ignoring-folders-files-specifically-fonts~4f68cfd5-d576-46b8-adc8-86e9d7ea0b1f
This is not a real answer but CSS in Next.js is just SUCKS! I find myself constantly struggle to make it work so what I decided is to follow their docs and simply use:
const App = () => {
return (
{style}
<div/>
);
}
let style = (<style jsx>
{`
.someClass {}
`}
</style> )
export default App;
This way you can have CSS as you might have in regular HTML without any external imports
source
You don't need both withCSS & withSass plugins.
If you are using Sass the withSass plugin will compile it to CSS.
Just make sure you add the path to the CSS file in your _document.js file inside the Head component like this:
<Head>
<link rel="stylesheet" href="/_next/static/style.css" />
</Head>
For importing css you can use Head component of the nextJS.
import Head from 'next/head';
<Head>
<link rel="stylesheet" href="path of the css" />
</Head>

Storybook Global Scss variables

CLI Tool: Storybook
Framework: Vue/ Nuxt
Issue: I'm trying to pull in global SCSS variables to Storybook Stories so they run the components the same way as they do in Nuxt, I've tried the custom webpack config with sass-resources-loader but had no luck, just wanted to check if anyone else has already solved this problem
It seems to be an issue with Storybook handling multiple rules.
I solved it by a work around.
You can read the blog i wrote for detailed explaination here.
Below is my webpack config - main.js :
webpackFinal: async (config, { configType }) => {
config.module.rules.map((rule) => {
if (rule.oneOf) {
rule.oneOf = rule.oneOf.slice().map((subRule) => {
if (subRule.test instanceof RegExp && subRule.test.test('.scss')) {
return {
...subRule,
use: [
...subRule.use,
{
loader: require.resolve('sass-resources-loader'),
options: {
resources: [
path.resolve(__dirname, '../src/styles/_common.scss')
]
}
}
],
}
}
return subRule;
});
}
return rule;
});
return config;
},
Hope this helps someone!
I encountered the issue where global SASS variables were causing Storybook for Vue to fail.
For me, creating a webpack.config.js file in the .storybook folder with the below configuration solved my problem:
module.exports = (storybookBaseConfig, configType, defaultConfig) => {
defaultConfig.module.rules.push(
{
resourceQuery: /module/,
use: [
{
loader: 'vue-style-loader',
options: {
sourceMap: false,
shadowMode: false
}
},
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 2,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: false
}
},
{
loader: 'sass-loader',
options: {
sourceMap: false,
indentedSyntax: true,
data: '#import "#/sass/_variables.scss";'
}
}
]
}
);
return defaultConfig;
};
Note the line data: '#import "#/sass/_variables.scss";' needs to match the file path for the SASS file with variables in your project.
This section of config was retrieved from Vue CLI 3 by running vue inspect > output.js and then copying the config for the rule test: /\.sass$/.
You need to add the scss rule in your .storybook/webpack.config.js for storybook to parse scss.
const path = require('path');
const scss = {
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
],
};
module.exports = (storybookBaseConfig, configType, defaultConfig) => {
defaultConfig.module.rules.push(scss);
return defaultConfig;
};
You may also need to install the appropriate loaders:
yarn add -D vue-style-loader sass-loader css-loader
For anybody who can actually get Storybook to read SCSS files but can't get it to read the global variables file, do this in your custom webpack config:
module: {
rules: [
// Apply loader
{
test: /\.scss$/,
loaders: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
prependData: '#import "path/to/global.scss";',
},
},
],
},
],
}
If your components do not get styles applied when run in the Storybook component explorer UI, just import SASS styles in your main Storybook config/storybook/config.js (in previous versions was by default at storybook/config.js) like so:
// Import Styles
import '../../src/assets/styles/index.scss';
Usually you'd have your styles and plugins imported in your src/main.js / src/main.ts but you also need to do this in Storybook config, as when running Storybook it's not running the whole Vue app but just those individual components.

Resources