Storybook custom webpack loading empty scss objects - css

I added a custom webpack.config.js file to my .storybook project so that I can import .scss files. This is what I added, straight from the storybook docs.
const path = require('path');
// Export a function. Accept the base config as the only param.
module.exports = (storybookBaseConfig, 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
storybookBaseConfig.module.rules.push({
test: /\.scss$/,
loaders: ["style-loader", "css-loader", "sass-loader"],
include: path.resolve(__dirname, '../src')
});
// Return the altered config
return storybookBaseConfig;
};
Here's my story:
import React from 'react';
import { storiesOf } from '#storybook/react'; // eslint-disable-line import/no-extraneous-dependencies
import { action } from '#storybook/addon-actions'; // eslint-disable-line import/no-extraneous-dependencies
import { linkTo } from '#storybook/addon-links'; // eslint-disable-line import/no-extraneous-dependencies
import Button from './'
import ButtonStyles from './index.scss'
import ButtonCompareTrayStyles from './compare-tray.scss'
import ButtonCompareRemminderStyles from './compare-reminder.scss'
console.log({ButtonStyles, ButtonCompareTrayStyles, ButtonCompareRemminderStyles})
storiesOf('Button', module)
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>)
.add('with default styles', () => <Button styles={ButtonStyles} onClick={action('clicked')}>Hello World</Button>)
.add('with CompareTray styles', () => <Button styles={ButtonCompareTrayStyles} onClick={action('clicked')}>Hello World</Button>)
.add('with CompareRemminder styles', () => <Button styles={ButtonCompareRemminderStyles} onClick={action('clicked')}>Hello World</Button>)
When I log some Button styles, it appears that each one of these objects is empty.
Why are these objects empty? How can I get scss working with storybook?

For everyone who has the same problems, I added the package #storybook/preset-scss and configured it the following way:
module.exports = {
"stories": [
"../src/**/*.stories.*",
"../src/**/*.story.*"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-actions",
"#storybook/addon-essentials",
"#storybook/addon-knobs",
{
name: '#storybook/preset-scss',
options: {
cssLoaderOptions: {
modules: true
}
}
},
]
}
That's it.

Related

How to add vue plugins to Vite?

when i was using webpack instead of vite i used to write this code in app.js
// for File uploads
import vueFilePond from "vue-filepond";
import "filepond/dist/filepond.min.css";
// image preview in file pond
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
import FilePondPluginFilePoster from "filepond-plugin-file-poster";
import "filepond-plugin-file-poster/dist/filepond-plugin-file-poster.css";
// file size validations
import FilePondPluginFileValidateSize from "filepond-plugin-file-validate-size";
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
const FilePond = vueFilePond(
FilePondPluginImagePreview,
FilePondPluginFilePoster,
FilePondPluginFileValidateSize,
FilePondPluginFileValidateType
);
but now with Vite this is not working.
i tried adding
export default defineConfig({
plugins: [
laravel({
input: [
'resources/js/app.js',
'resources/css/app.css',
],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
vueFilePond *****************************this************
],
resolve: {
alias: {
'$': 'jQuery',
},
},
});
this is not working. Please help!
So this worked for me!
// for File uploads
import vueFilePond from "vue-filepond";
import "filepond/dist/filepond.min.css";
// image preview in file pond
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
import FilePondPluginFilePoster from "filepond-plugin-file-poster";
import "filepond-plugin-file-poster/dist/filepond-plugin-file-poster.css";
// file size validations
import FilePondPluginFileValidateSize from "filepond-plugin-file-validate-size";
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
const FilePond = vueFilePond(
FilePondPluginImagePreview,
FilePondPluginFilePoster,
FilePondPluginFileValidateSize,
FilePondPluginFileValidateType
);
Vue.use(AnyComponent) ; THis was not working in my case
So i tried adding component in below code. this worked for me.
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(ZiggyVue, Ziggy)
**.mixin({ components: { FilePond } })**
.mount(el);
},
});

how to setup antd less support with nextjs 12

im trying to setup nextjs 12 with ant design antd and in next.config.js when i try to setup withAntdLess it gives type error
Type '{}' is missing the following properties from type '{ esModule: boolean; sourceMap: boolean; modules: { mode: string; }; }': esModule, sourceMap, modules
although all props are optional according to next-plugin-antd-less docs
next.config.js file:
// #ts-check
// next.config.js
const withAntdLess = require('next-plugin-antd-less');
/**
* #type {import('next').NextConfig}
**/
module.exports =withAntdLess({
cssLoaderOptions: {},
// Other Config Here...
webpack(config) {
return config;
},
reactStrictMode: true,
});
I solved it using next-with-less https://github.com/elado/next-with-less
next.config.js
const withLess = require('next-with-less');
const lessToJS = require('less-vars-to-js');
const themeVariables = lessToJS(
fs.readFileSync(
path.resolve(__dirname, './public/styles/custom.less'),
'utf8'
)
);
module.exports = withLess({
...
lessLoaderOptions: {
lessOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
localIdentName: '[path]___[local]___[hash:base64:5]',
},
},
...
})
Import your custom less file on top off the file _app.jsx
import 'public/styles/custom.less';
...
Import the default Antd less file on your custom less file: (in my case public/styles/custom.less)
#import "~antd/dist/antd.less";
....
Extra notes:
If you have an old implementation of Antd, you should remove the integration in your .babelrc
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "lib",
"style": true
}
],
If you have an old implementation of Antd, you should remove the integration in your webpack zone in your next.config.js
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/;
const origExternals = [...config.externals];
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback();
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback);
} else {
callback();
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
];
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
});
}

How to setup storybook at root level lerna monorepo

I am working on a project which is set up with lerna mono repo, we have multiple stencilJS projects for an individual component inside packages of monorepo.
My project sructure is:
I am new to the storybook, now I have to set up the storybook at the root level which all the packages storybook.
I followed an article on the internet and I have set up something which works only for a single package component, due to the current style of setup.
Due to defineCUstomElements in preview.js it is loading the first project package loader I am able to see only the first project stories. Css is not loading for second project stories.
Can someone help me to set up a storybook at the root level which works for all packages?
My example
storybook/main.js
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../packages/plugin-*/src/components/plugin-*/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-viewport',
'#storybook/addon-notes',
'#storybook/addon-docs'
]
}
storybook/preview.js
import { defineCustomElements } from '../packages/stencilProj1/loader';;
defineCustomElements();
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};
package/stencilProj1/component1.stories.ts
import readme from './readme.md'
import React from 'react';
import ComponentButton from '../../../dist/collection/components/ComponentButton /ComponentButton';
export default {
title: 'Button',
component: ComponentButton,
argTypes: {
label: { control: 'text' },
type: { type: 'select', options: ['primary'] },
disabled: { control: 'boolean' }
},
parameters: {
markdown: readme
},
};
const Template = ({ label, type, disabled = false }) => {
return <component-button type={type} disabled={disabled}>{label}</component-button>;
};
export const Primary = Template.bind({});
Primary.args = {
type: 'primary',
label: 'Primary Button',
};
After a couple of months of attempts, I finally solved this puzzle :) And want to share my solution with community
I have a lerna v4 monorepo for react v17 + mui v5 components written in typescript and flavored with storybook v6 and webpack v5
mui has its wrappers in preview.js, that's why I added the path to .storybook in babel-loader
module.exports = {
core: {
builder: "webpack5",
},
framework: "#storybook/react",
stories: ["../components/**/*.stories.#(ts|tsx)"],
addons: [
"#storybook/addon-links",
"#storybook/addon-essentials",
{
name: "#storybook/preset-create-react-app",
options: {
craOverrides: {
fileLoaderExcludes: ["less"],
},
},
},
],
webpackFinal: config => {
const {
module: {
rules: [, , , , , { oneOf }],
},
} = config;
const babelLoader = oneOf.find(({ test }) => new RegExp(test).test(".ts"));
babelLoader.include = [/components\/(.*)\/src/, /.storybook/];
babelLoader.options.sourceType = "unambiguous";
return config;
},
};
it is also worth to mention my tsconfig has these lines
"rootDirs": [
"./src",
],
Have you tried to import project 2's defineCustomElement with "as" to rename it and use it?
(something along the line of following inside preview.js)
import { defineCustomElements } from '../packages/stencilProj1/loader';
import { defineCustomElements as defineSecondProject } from '../packages/stencilProj2/loader';
defineCustomElements();
defineSecondProject();
This is very manual and even if this works, if you have many repo might not be good solution but I've done something similar to load multiple component loaders and that seem to work OK for my use case in the past.

The correct way to bundle CSS modules

I have a weird thing happening when my css modules are exported with the * as styles becomes inaccessible when I bundle my code and use it in other repo's.
The response from styles when bundled:
{default: {... my class names} }
When I change my code to import styles from '...' it works when bundled because styles is the default but fails the tests because styles does not have access to the named exports.
rollup config.js
import resolve from '#rollup/plugin-node-resolve'
import commonjs from '#rollup/plugin-commonjs'
import typescript from 'rollup-plugin-typescript2'
import { terser } from 'rollup-plugin-terser'
import postcss from 'rollup-plugin-postcss'
import postCssConfig from '#cinch-labs/postcss-config'
import pkg from './package.json'
import { designTokens, toJSON } from './src/tokens'
const extensions = ['.ts', '.tsx']
// stylelint does work but the postcss one needed to be removed
const postcssPlugins = postCssConfig(toJSON(designTokens)).filter(
({ postcssPlugin }: { postcssPlugin: string }) => postcssPlugin !== 'stylelint',
)
export default [
{
input: './src/index.ts',
output: [
{
file: pkg.main,
format: 'cjs',
},
{
file: pkg.module,
format: 'es',
},
],
plugins: [
postcss({
modules: true,
extract: false,
syntax: 'postcss-scss',
plugins: postcssPlugins,
use: ['sass'],
}),
resolve({
extensions,
}),
commonjs(),
typescript({ tsconfig: 'tsconfig.rollup.json' }),
terser(),
],
external: ['react', 'react-dom'],
},
]
test.component.tsx
import React from 'react'
import classNames from 'classnames'
// I expected the bundler to resolve this for me...
import * as styles from './text.module.scss'
import { TextProps } from './text.types'
export const Text: React.FC<TextProps> = ({
children,
fontSize = 'm',
fontWeight = 'medium',
fontStyle = 'normal',
lineHeight = 'body',
element = 'p',
className,
...props
}) => {
const HtmlEl = element
const classes = classNames(
{
[styles[`textSize${fontSize.toUpperCase()}`]]: fontSize,
[styles[`textWeight${fontWeight.toUpperCase()}`]]: fontWeight,
[styles[`textLineHeight${lineHeight.toUpperCase()}`]]: lineHeight,
[styles[`textFontStyle${fontStyle.toUpperCase()}`]]: fontStyle,
},
className,
)
// classes returns undefined when bundled because of commonjs format.
return (
<HtmlEl className={classes} {...props}>
{children}
</HtmlEl>
)
}
I know this is due to the way common JS works however I would expect for the import * as styles to work. When I change it to import styles from './text.module.scss' it works fine when bundled but does not work in tests.
Using import * as styles from './text.module.scss' you are importing the styles as a named export.
Since this also returns {default: {... my class names} }, you can use styles.default instead, or, perhaps, assign it to a new variable like
const style = styles.default
Fixing this issue was by doing import styles from 'path name' and then installing jest-css-modules to map the styles object in my test.
https://www.npmjs.com/package/jest-css-modules
for me to compile and include with rollup.js the scss into the bundle/build worked adding:
plugins: [
postcss({
modules: true,
extract: false,
syntax: 'postcss-scss',
use: ['sass'],
}),
],
Hope this will help someone else in this journey :)

Imported styles object is empty in Jest

I have a component:
import React from 'react';
import * as styles from './RedComponent.css';
class RedComponent extends React.Component {
render () {
return <div className={ styles.red }></div>;
}
}
This is the test case:
describe('Test suite', () => {
test('RedComponent tests', () => {
const wrapper = shallow(<RedComponent />);
});
console.log(wrapper.debug());
gives
<div className={[undefined]}></div>
instead of
<div className="RedComponent__red"></div>
If I console the imported styles I get
console.log(styles); // {default: {}}
This is only in Jest test cases. Style is not undefined when the app renders in browser.
My jest config:
{
"moduleFileExtensions": [
"js"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": {
"\\.(css|less)$": "identity-obj-proxy"
},
"setupFiles": [
"./test-setup.js"
],
"collectCoverageFrom": [
"src/**/*.{js}",
"!**/node_modules/**"
],
"testEnvironment": "node",
"transform": {
"^.+\\.js$": "babel-jest",
"\\.(md|ttf|txt|eot|ico|otf|svg|png|gif|woff2|woff|jpeg)$": "./file-transformer.js"
}
}
Using jest v21.2.1, identity-obj-proxy v3.0.0 and React v16.0.0.
You have to change this line
import * as styles from './RedComponent.css';
to this:
import styles from './RedComponent.css';
I assume that you are using css-loader or similar and this is just how the loader works.
Maybe worths to check the example:
https://github.com/keyanzhang/jest-css-modules-example/
I think your moduleNameMapper should be like this:
"^.+\\.(css|less)$": "identity-obj-proxy"
Create a jest/identity-obj-proxy-esm.js file with the following content:
// This works around the fact we use ES named exports for styles, e.g.:
// import * as styles from './styles.scss'.
// https://github.com/keyanzhang/identity-obj-proxy/issues/8
module.exports = new Proxy(
{},
{
get: function getter(target, key) {
if (key === '__esModule') {
// True instead of false to pretend we're an ES module.
return true;
}
return key;
},
},
);
Edit jest.config.js:
// jest.config.js
module.exports = {
...
moduleNameMapper: {
...
'\\.(css|scss)$': '<rootDir>/jest/identity-obj-proxy-esm.js',
}
};
🏆 João Vieira and https://github.com/keyz/identity-obj-proxy/issues/8#issuecomment-430241345

Resources