How can I use craco to modify antd LESS variables? - reactjs

craco provides this recipe for modifying Ant Design LESS variables with create-react-app. However, I don't understand how to modify variables through this config. The variable lessRule in the linked recipe has no visible effect:
const lessRule = {
test: lessExtension,
use: [
{
loader: require.resolve("style-loader"),
},
{
loader: require.resolve("css-loader"),
},
{
loader: require.resolve("less-loader"),
options: {
modifyVars: {
"#primary-color": "#1DA57A",
"#link-color": "#1DA57A",
"#border-radius-base": "2px",
},
javascriptEnabled: true,
},
},
],
};
lessRule is pushed to oneOf but I can't research what this effectively does. What do I do in this config file to see a style change manifested in the app?

craco-antd allows this. I am confused as to what the craco recipe in the question does. I'm not sure it matters.

Related

Global scss variables with reactjs and webpack

I am working with reactjs and webpack, and i am trying to make global variables of sass so i can use them any where without import them. But i didn't succeed , i had added the file to webpack but always the same problem. Even the other solution on stackoverflow didn't work with me, can any one help please ?
here is my index.scss :
#import "../public/scss/variables";
#import "../public/scss/mixin";
here is my variables.scss file:
$blueColor: #049DD6;
$darkBlueColor: #08536A;
$garyColor: #DFEFEF;
$darkGaryColor: #D5bbDE;
$pinkColor:#F05389;
$greenColor:#1DCD5A;
$redColor:#F60ELE;
$errorColor:#AAG601;
and here is the simple login.scss where i tried to access one of my variable but it show my variable undefined:
.left-panel {
background-color: $blueColor;
}
Thank you for your help
You need to do the import using the extension:
#import "../public/scss/variables.scss";
Check if your loader options in your webpack module rules are correct.
{
test: [/\.scss$/, /\.css/],
loader: ExtractTextPlugin.extract(
Object.assign(
{
fallback: {
loader: require.resolve('style-loader')
},
use: [
{
loader: require.resolve('css-loader')
},
{
loader: require.resolve('sass-loader'),
},
{
loader: require.resolve('json-sass-mixin-loader')
},
{
loader: require.resolve('sass-resources-loader'),
options: {
resources: [
'path/to/mixins/*.scss',
'path/to/variables.scss']
}
},
{
loader: require.resolve('postcss-loader')
},
],
},
)
),
}
Try to use an absolute path for the options.resources array. Example:
resources: [
path.resolve(__dirname, './src/styles/variables.scss')
]
or
resources: [
'./src/styles/variables.scss'
]
Both should work

Customize Antd in ejected CRA

I've got a fresh CRA made, and I am using the Ant Design library.
Looking at the instructions, it's not 100% clear to me what exactly I need to do, however from what I can gather, since I have ejected my app, I can modify my webpack.config.js file and be done with it.
Unfortunately, it seems the changes I have made are not being reflected
I have added the below into my rules array
{
test: /\.less$/,
use: [{
loader: require.resolve('style-loader'),
}, {
loader: require.resolve('css-loader'), // translates CSS into CommonJS
}, {
loader: require.resolve('less-loader'), // compiles Less to CSS
options: {
modifyVars: {
'primary-color': '#1DA57A',
'link-color': '#1DA57A',
'border-radius-base': '2px',
},
javascriptEnabled: true,
},
}],
},
Does anyone know how I can get this working please?
Instead of ejecting. You can use customize-cra package to override default settings. Ant design has already added the docs on the usage for create react app. Please check this link.
Hope this helps!

Unable to skip 3rd party library CSS from CSS-Module transformation

I am trying CSS Modules for the first time with React and Webpack and I came across at least three ways to achieve it:
css-loader
react-css-modules
babel-plugin-react-css-modules
I went with babel-plugin-react-css-modules in order to balance code simplicity and performance and everything seems to be working fine except for one thing: my 3rd party libraries (Bootstrap and Font Awesome) are also included in CSS Modules transformation.
<NavLink to="/about" styleName="navigation-button"></NavLink>
The above assigns a properly transformed className to the NavLink. However, a span inside needs to refer to global styles in order to render an icon.
<span className="fa fa-info" />
The above span is not assigned a transformed className which is expected, but my bundled stylesheet does not have these CSS classes as they are being transformed into something else, to simulate local scope.
Below is the content in my .babelrc file to activate babel-plugin-react-css-modules:
{
"presets": ["env", "react"],
"plugins": [
["react-css-modules", {
"generateScopedName": "[name]__[local]___[hash:base64:5]",
"filetypes": {
".less": {
"syntax": "postcss-less"
}
}
}]
]
}
In my Webpack configuration, below is the section to configure css-loader for transforms:
{
test: /\.(less|css)$/,
exclude: /node_modules/,
use: extractCSS.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
minimize: true,
modules: true,
sourceMap: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
loader: 'less-loader'
}
]
})
}
As far as I have read, the above rule should exclude the library stylesheets and I also tried adding another rule specifically for the excluded stylesheets, however that did not seem to work, as I guess as those stylesheets were still transformed with the original rule.
In order to import CSS from the two libraries, I have the below two lines in my parent stylesheet that declares some global styles:
#import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css';
#import '../../../node_modules/font-awesome/css/font-awesome.min.css';
I find these two approaches below might be helpful:
https://stackoverflow.com/a/52294675
https://github.com/css-modules/css-modules/pull/65#issuecomment-412050034
In short, there seems to be no options to ignore/exclude certain paths from being modularized by the css-modules webpack plugin so far. Ideally it should be supported by the plugin, but here're some approaches you can try out:
use two webpack rules to utilise the webpack rule exclusion/inclusion:
module.exports = {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path]__[local]___[hash:base64:5]',
},
},
],
},
{
test: /\.css$/,
include: /node_modules/,
use: ['style-loader', 'css-loader']
}
]
}
...or, inject into webpack's getLocalIdent from the second answer above to manually exclude certain paths.
const getLocalIdent = require('css-loader/lib/getLocalIdent');
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (loaderContext, localIdentName, localName, options) => {
return loaderContext.resourcePath.includes('semantic-ui-css') ?
localName :
getLocalIdent(loaderContext, localIdentName, localName, options);
}
}
}
For me using :global worked :
.my-component {
:global {
.external-ui-component {
padding: 16px;
// Some other styling adjustments here
}
...
}
}
Ps: for doing it with webpack config, please see another answer.
source
Updated solution from playing771
{
loader: 'css-loader',
options: {
modules: {
auto: (resourcePath) => !resourcePath.includes('node_modules'),
localIdentName: '[name]__[local]__[hash:base64:5]',
},
},
},

Two svgo-loader conflict

I am using webpack to build svg-sprite.
But there is a problem: part of icons have multiple colors, and part — only one. They are used as is.
One color icons should change color according to :hover / :active.
And, according to this I should clean fill attributes for one color icons.
Which I can't do with multicolor ones.
I decide to separate them to different folders and create two webpack rules:
{
test: /icon\/.*\.svg$/,
loaders: [
'svg-sprite-loader',
{
loader: 'svgo-loader',
options: {
plugins: [
// ...
],
},
},
],
},
{
test: /monoicon\/.*\.svg$/,
loaders: [
'svg-sprite-loader',
{
loader: 'svgo-loader',
options: {
enforce: 'pre',
plugins: [
// ...
{ removeAttrs: { attrs: '(fill|stroke)' } },
],
},
},
],
},
And everything is fine, but it don't actually work. I am getting in the console:
…/monoicon/cross.svg
Module build failed: Error: Error in parsing SVG: Non-whitespace before first tag.
Line: 0
Column: 1
Char: i…
Digging the web I have found:
It was a problem with the way I was loading it. you need to prefix require("-!... when you're overriding other loaders...
https://github.com/jhamlet/svg-react-loader/issues/3#issuecomment-146334228
So it look like source of the problem is that I have to rules with svgo-loader. Rewrite webpack loaders rule in each svg import — kinda shitty idea. So how I may solve this in appropriate way?
Regards.
I am an idiot. Write regexp's:
/\/icon\/.*\.svg$/
/\/monoicon\/.*\.svg$/

How to ensure that hot CSS loads before JS in webpack-dev-server?

I'm using webpack-dev-server to hot load all of my assets including CSS. Currently though, my CSS loads after the JavaScript which causes my application issues in some places that depend on layout existing.
How can I ensure that the CSS loads before the JavaScript executes?
I'm thinking there must be a way to do this from module, perhaps a a callback I could hook in to? Or maybe by configuring the style-loader to have priority?
This is my index.js:
import './styles/main.scss';
import './scripts/main.js';
if (module.hot) {
module.hot.accept();
}
and this is my styles loader:
{
test: /\.(scss)$/,
loader: 'style!css?&sourceMap!postcss!resolve-url!sass?sourceMap'
},
A similar question has been asked at this style-loader Github Issue: https://github.com/webpack/style-loader/issues/121
I was having the exacly same issue, in production the css are extracted so it always work, however in development because of the style-loader "sometimes executing after the main bundle" i had issues where the main bundle would calculate the size of some nodes in the DOM which was set by the css... so it could result to wrong sizes as the main css still havent loaded... i fixed this issue by having the option singleton:true.
example:
{
test: /\.s?css$/,
loader: ExtractTextPlugin.extract({
fallback: [
{
loader: 'style-loader',
options: { singleton: true }
}
],
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: !isProduction,
sourceMap: !isProduction
}
},
{ loader: 'postcss-loader', options: { sourceMap: !isProduction, ...postcss } },
{ loader: 'resolve-url-loader', options: { sourceMap: !isProduction } },
{ loader: 'sass-loader', options: { sourceMap: true } }
]
}
)
}
Looks like there's no event, callback or any way to detect that the style has been loaded. After long hours of searching in vain, I had to do something really dirty:
function checkCSS() {
const repeat = requestAnimationFrame(checkCSS);
// CSS loaded?
if(getComputedStyle(document.body).boxSizing === 'border-box') {
routes.loadEvents() // Init JS
cancelAnimationFrame(repeat) // Cancel next frame
}
}
if (process.env.NODE_ENV !== 'production') {
checkCSS()
} else {
$(document).ready(() => {
routes.loadEvents()
})
}
Because I have * { box-sizing: border-box; } in my styles and that I'm pretty sure native CSS styles won't never look like this, I can be ~99% sure that my own CSS is loaded.
I died a little writing this. Hopefully we'll find a better way!

Resources