Thx for your config, my storybook finally works ok.
I am not sure, if it will be helpfull, but I will share my config.
So the main aim for me was, storybook + react + typescript + less + normal component styles import + classnames.
My files structure and content:

package.json
{
"name": "storybook",
"version": "0.1.0",
"private": true,
"dependencies": {
"@storybook/addon-postcss": "^2.0.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.45",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"classnames": "^2.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"styled-components": "^5.3.5",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook -s public"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"overrides": [
{
"files": [
"**/*.stories.*"
],
"rules": {
"import/no-anonymous-default-export": "off"
}
}
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@storybook/addon-actions": "^6.5.9",
"@storybook/addon-essentials": "^6.5.9",
"@storybook/addon-interactions": "^6.5.9",
"@storybook/addon-links": "^6.5.9",
"@storybook/builder-webpack5": "^6.5.9",
"@storybook/manager-webpack5": "^6.5.9",
"@storybook/node-logger": "^6.5.9",
"@storybook/preset-create-react-app": "^4.1.2",
"@storybook/react": "^6.5.9",
"@storybook/testing-library": "^0.0.13",
"autoprefixer": "^10.4.7",
"babel-plugin-named-exports-order": "^0.0.2",
"css-loader": "^6.7.1",
"less": "^4.1.3",
"less-loader": "^11.0.0",
"postcss-loader": "^7.0.1",
"prop-types": "^15.8.1",
"storybook-addon-designs": "^6.3.1",
"storybook-addon-pseudo-states": "^1.15.1",
"style-loader": "^3.3.1",
"stylelint": "^14.9.1",
"stylelint-config-standard": "^26.0.0",
"webpack": "^5.73.0"
}
}
main.js
const path = require('path');
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"storybook-addon-designs",
"storybook-addon-pseudo-states",
{
"name": "@storybook/preset-create-react-app",
"options": {
"craOverrides": {
"fileLoaderExcludes": ["less"]
}
}
}
],
"framework": "@storybook/react",
"core": {
"builder": "@storybook/builder-webpack5"
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// Make whatever fine-grained changes you need
config.module.rules.push({
test: /\.less$/,
include: path.resolve(__dirname, '../'),
sideEffects: true,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
modules: {
auto: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
},
importLoaders: 2,
}
},
'less-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: [
require('stylelint')(),
require('autoprefixer')()
]
}
}
}
]
});
// Return the altered config
return config;
},
}
Button.stories.tsx
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Button } from './Button';
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
title: 'Example/Button',
component: Button,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: {
},
} as ComponentMeta<typeof Button>;
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args
Primary.args = {
label: 'Button',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Button',
};
Button.tsx
import React from 'react';
// import './button.css';
import classnames from 'classnames/bind';
import styles from './ButtonStyles.less'
// import './ButtonStyles.css';
interface ButtonProps {
type?: 'primary' | 'secondary' | 'cta' | 'secondaryOnlyText' | 'distractive' | 'social';
/**
* How large should the button be?
*/
size?: 'small' | 'medium' | 'primary' | 'large';
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick?: () => void;
}
/**
* Primary UI component for user interaction
*/
const cx = classnames.bind(styles);
export const Button = ({
type = 'primary',
size = 'medium',
label,
...props
}: ButtonProps) => {
const buttonStyles = cx({
storybookButton: true
})
return (
<button
type="button"
// className="storybookButton"
className={buttonStyles}
{...props}
>
{label}
</button>
);
};
ButtonStyles.less
.storybookButton {
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 700;
border: 0;
border-radius: 3em;
cursor: pointer;
display: inline-block;
line-height: 1;
background-color: yellow;
color: red;
}
.storybook-button--primary {
color: white;
background-color: #1ea7fd;
}
.storybook-button--secondary {
color: #333;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}
.storybook-button--small {
font-size: 12px;
padding: 10px 16px;
}
.storybook-button--medium {
font-size: 14px;
padding: 11px 20px;
}
.storybook-button--large {
font-size: 16px;
padding: 12px 24px;
}