Add wrapper class to less files using webpack - reactjs

I am using webpack v5.74.0.
I want to add a custom class to all CSS rules at build time using webpack. Example for reference
.input-text {color: red}
should become
.container .input-text {color: red}
Custom wrapper class needs to be added inside less files. Not able to find any loader in webpack to prefix this container class.
Please suggest.

try the below code in your webpack config to add a wrapper class for all classes present in your project.
module: {
rules: [
{
test: /\.(css|less)$/i,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: {
"postcss-increase-specificity": {
stackableRoot: `.container`,
repeat: 1,
},
},
},
},
},
{
loader: "less-loader",
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
],
}

Related

ReactJS custom webpack config, trying to hash css class names while using both css-loader and sass-loader

My .css or .scss files won't load at all.
What I'm trying to achieve is to hash my class names using css-loader option localIdentName.
I'm working on ReactJS with custom webpack config. This is one of my rules inside webpack.config.js:
{
test: /(\.css|\.scss|\.sass)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: "[path][name]__[local]--[hash:base64:5]",
}
},
},
{
loader: 'sass-loader',
options: {
},
},
],
},

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.

Is there a way to limit classname length with NPM CSS Loader/Style Loader in react?

I configured on my React webpack CSS Loader and Style Loader to obfuscate classNames when a CSS module is loaded.
Although the generated obfuscated className seems too long, I'd like to know if there is a parameter or something I can change on my configuration (webpack) to limit the className size.
ClassName example: _2BzySvHGRXbDRB3RRdNEOO
Webpack code:
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localsConvention: 'dashes'
}
}
]
}
You can use localIdentName to manipulate the CSS fields.
e.g.
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
mode: 'local',
exportGlobals: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
context: path.resolve(__dirname, 'src'),
hashPrefix: 'my-custom-hash',
},
},
},
This may not work depending on your webpack version:
What worked for the user:
ref:https://github.com/rails/webpacker/issues/2197
{ test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader',
options: {
modules: true,
importLoaders: 2,
localsConvention: 'dashes',
modules: { localIdentName: '[hash:base64:5]',
},
}
}
]
},
if you remove the hash from the end, or just use the hash, you'll significantly reduce the class name length. or you can write a custom function in its place to reduce it.
ref: https://github.com/webpack-contrib/css-loader#localidentname
ref: Modify output of localIdentName / getLocalIdent

tailwind css with css modules in next.js

How to config next.js to support Simultaneous tailwind css with css modules?
I want tailwindcss wrap whole project:
// /tailwind.scss
:global {
#import "tailwindcss/base";
#import "tailwindcss/components";
#import "tailwindcss/utilities";
}
// /test-module.css
.example {
font-size: 36px;
}
// /pages/_app.jsx
import '../talwind.scss';
...
And in a sample component:
// /components/my-component.jsx
import css from '../test-module.css';
const Test = () => (
<div className={`bg-red-500` ${css.example}}>Test Tailwind with CSS</div>
);
A solution is split webpack style loader. A loader for global css another for css modules loader so webpack loader is looks like below:
{
test: /\.s?[ac]ss$/,
exclude: /\.global.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: !isProduction,
reloadAll: true,
},
},
// 'css-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]',
},
},
},
'postcss-loader',
{ loader: 'sass-loader', options: { sourceMap: true } },
],
},
{
test: /\.global.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: !isProduction,
reloadAll: true,
},
},
'css-loader',
'postcss-loader',
],
},
I had the same problem, I did the following and it worked:
const Test = () => (
<div className={["bg-red-500", css.example].join(" ")}>
Test Tailwind with CSS
</div>
);
You need to write classname like this
const App = () => {
<h1 className={[style[`bg-teal-600`], style.holi].join(' ')}>Holi</h1>;
};

How to configure webpack to find images in scss via this way: url(a.png) instead of url(../../image/a.png)

I am using typescript, webpack, sass in my project. now I set background-imgae in scss using this way: url(../../assets/image/a.png),
however it is really ugly, I want to import image like this: url(a.png), what should I do ?
I have used url-loader, file-loader, resolve-url-loader to solve the problem, actually, I am just a entry level of webpack. I am really confused now. Here is my code
in wepack :
{
test: /\.scss|css$/i,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1
}
},
{
loader: require.resolve("sass-loader")
},
{
loader: require.resolve("resolve-url-loader")
},
AntdScssThemePlugin.themify({
loader: "sass-loader",
options: {
sourceMap: true
}
}),
{
loader: require.resolve("postcss-loader"),
options: {
ident: "postcss",
plugins: () => [
require("postcss-flexbugs-fixes"),
autoprefixer({
browsers: [
">1%",
"last 4 versions",
"Firefox ESR",
"not ie < 9"
],
flexbox: "no-2009"
}),
postcssAspectRatioMini({}),
postcssPxToViewport({
viewportWidth: 375, // (Number) The width of the viewport.
viewportHeight: 1334, // (Number) The height of the viewport.
unitPrecision: 3, // (Number) The decimal numbers to allow the REM units to grow to.
viewportUnit: "vw", // (String) Expected units.
selectorBlackList: [".ignore", ".hairlines"], // (Array) The selectors to ignore and leave as px.
minPixelValue: 1, // (Number) Set the minimum pixel value to replace.
mediaQuery: false // (Boolean) Allow px to be converted in media queries.
}),
postcssWriteSvg({
utf8: false
}),
postcssCssnext({}),
postcssViewportUnits({}),
cssnano({
preset: "advanced",
autoprefixer: false,
"postcss-zindex": false
})
]
}
}
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
"file-loader?hash=sha512&digest=hex&name=[hash].[ext]",
{
loader: "image-webpack-loader",
query: {
mozjpeg: {
progressive: true
},
gifsicle: {
interlaced: false
},
optipng: {
optimizationLevel: 4
},
pngquant: {
quality: "75-90",
speed: 3
}
}
},
]
},
In index.scss
background: url("../../assets/images/sprite_languages.png")
and I really want to use this way:
background: url("sprite_languages.png")
What could I do? Thank you very much
You could do this in webpack config:
resolve: {
alias: {
'#assets': path.resolve(__dirname, './src/assets'),
},
},
And then in scss:
background: url("~#assets/images/sprite_languages.png");

Resources