Hello,i used css module with babel-plugin-import,but it does't work.
either css module or babel-plugin-import work.
here's my config-overrides file:
const { injectBabelPlugin,getLoader } = require('react-app-rewired')
const rewireLess = require('react-app-rewire-less')
const cssLoaderMatcher = function(rule) {
return rule.loader && rule.loader.indexOf(`css-loader`) != -1;
}
module.exports = function override(config, env) {
let l = getLoader(config.module.rules,cssLoaderMatcher);
l.options = {
modules: true,
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]'
}
config = injectBabelPlugin(['import', { libraryName: 'antd', style: true }], config);
config = rewireLess(config, env, {
modifyVars: { "@primary-color": "#1DA57A" },
})
return config;
};
https://ant.design/docs/react/use-with-create-react-app
i wanna use this React Ui library with css module , how should i do it
I've done something like this to get it working in my project
const { getLoader } = require('react-app-rewired');
const cssLoaderMatcher = function (rule) {
return rule.loader && rule.loader.indexOf('css-loader') !== -1;
};
function rewireCSS(config, env) {
const cssRules = getLoader(config.module.rules, rule => rule.test && String(rule.test) === String(/\.css$/));
cssRules.test = /\.s?css$/;
const cssLoader = getLoader(config.module.rules, cssLoaderMatcher);
cssLoader.options = {
modules: true,
importLoaders: 1,
localIdentName: '[local]___[hash:base64:5]',
};
return config;
}
module.exports = rewireCSS;
and
const { getLoader } = require('react-app-rewired');
const path = require('path');
function rewireLess(config, env, options = {}) {
const lessExtension = /\.less$/;
const fileLoader = getLoader(config.module.rules, rule => rule.loader && typeof rule.loader === 'string' && rule.loader.endsWith(`file-loader${path.sep}index.js`));
fileLoader.exclude.push(lessExtension);
const lessLoader = {
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options,
},
],
};
config.module.rules.push(lessLoader);
return config;
}
module.exports = rewireLess;
@TedChenNZ Thanks !
Hello, @TedChenNZ I got empty object from less file that like import styles from './xxx.less';.
If I import less like import from './xxx.less'; and use className in jsx it worked.
@WhatAKitty https://github.com/timarney/react-app-rewired/blob/master/packages/react-app-rewire-less rule.loader.endsWith(file-loader${path.sep}index.js` in the example above has changed in latest version.
@andriijas I had changed it already.This is my code:
const cssLoaderMatcher = function (rule) {
return rule.loader && rule.loader.indexOf('css-loader') !== -1;
};
function rewireCSS(config, env) {
const cssRules = getLoader(config.module.rules, rule => rule.test && String(rule.test) === String(/\.css$/));
cssRules.test = /\.s?css$/;
const cssLoader = getLoader(config.module.rules, cssLoaderMatcher);
cssLoader.options = {
modules: true,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:5]',
};
return config;
}
function rewireLess(config, env, options = {}) {
const lessExtension = /\.less$/;
const fileLoader = getLoader(
config.module.rules,
rule =>
rule.loader &&
typeof rule.loader === 'string' &&
rule.loader.indexOf(`${path.sep}file-loader${path.sep}`) !== -1,
);
fileLoader.exclude.push(lessExtension);
const lessLoader = {
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options,
},
],
};
config.module.rules.push(lessLoader);
return config;
}
module.exports = function override(config, env) {
config = injectBabelPlugin('transform-decorators-legacy', config);
config = rewireCSS(config, env);
config = injectBabelPlugin(['import', { libraryName: 'antd', style: true }], config);
config = rewireLess(config, env, {
modifyVars: {
'@primary-color': '#1DA57A',
'@link-color': '#1DA57A',
'@border-radius-base': '2px',
'@font-size-base': '14px',
'@line-height-base': '1.2',
'@card-actions-background': '#f5f8fa',
}
});
return config;
};
But I still got empty object with import styles from 'xxx.less' in jsx file while @import in less file worked.
@WhatAKitty hmm okay. this config works for me im using antd as well.
const path = require("path");
const { compose, getLoader, injectBabelPlugin } = require("react-app-rewired");
const rewireLess = require("react-app-rewire-less");
const rewireCSSModules = (config, env) => {
const cssRules = getLoader(
config.module.rules,
rule => rule.test && String(rule.test) === String(/\.css$/),
);
const cssLoader = getLoader(
env === "production" ? cssRules.loader : config.module.rules,
rule =>
rule.loader &&
rule.loader.indexOf(`${path.sep}css-loader${path.sep}`) !== -1,
);
cssLoader.options = {
...cssLoader.options,
modules: true,
localIdentName: `${env === "production" ? "" : "[local]-"}[hash:base64:8]`,
};
return config;
};
module.exports = function override(config, env) {
config = injectBabelPlugin(
["import", { libraryName: "antd", style: true, libraryDirectory: "es" }],
config,
);
const rewires = compose(
rewireCSSModules,
rewireLess.withLoaderOptions({
modifyVars: {
"@primary-color": "#...",
"@info-color": "#..",
"@font-size-base": "14px",
},
}),
);
return rewires(config, env);
};
For it to work properly I needed separate config for production and dev/test otherwise it didnt work with npm run build and npm start. Since you are not using scss/sass you can remove cssRules.test = /\.s?css$/; safely.
Also note all styles are becoming local with modules enabled, you need to use :global for global styles
@andriijas also worked in jsx import styles from 'xxx.less' ? It's so strange.
@andriijas yeah, worked fine with your configuration, I can get value from less files. Thanks!
@WhatAKitty yes it worked but then antd styles stopped working because they are not using css modules. What you can do is to check src of https://github.com/codebandits/react-app-rewire-css-modules and see how they only add module support to *.module.css and add similar for *.module.less
@WhatAKitty what we need to do is duplicate less rules. one for node_modules without css modules, one for src/ dir with css modules enable.
roadhog comes with that automatically, might be worth checking out https://github.com/sorrycc/roadhog/blob/master/src/config/common.js
@andriijas sorry, I had no idea about how to do it. I'm a newer for webpack.
I tried it, but failed. Can you help me?
I'm going to try to get it to work later today because u want it to. Have to work on other stuff right now though @whatakitty
Sent from my iPhone
On 2 Nov 2017, at 13:26, WhatAKitty notifications@github.com wrote:
@andriijas sorry, I had no idea about how to do it. I'm a newer for webpack.
I tried it, but failed. Can you help me?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
Hello @andriijas , thanks a lot for your help, I changed some words with https://github.com/codebandits/react-app-rewire-css-modules and it worked great for me.
const cloneDeep = require('lodash.clonedeep')
const ruleChildren = (loader) => loader.use || loader.oneOf || Array.isArray(loader.loader) && loader.loader || []
const findIndexAndRules = (rulesSource, ruleMatcher) => {
let result = undefined
const rules = Array.isArray(rulesSource) ? rulesSource : ruleChildren(rulesSource)
rules.some((rule, index) => result = ruleMatcher(rule) ? {index, rules} : findIndexAndRules(ruleChildren(rule), ruleMatcher))
return result
}
const findRule = (rulesSource, ruleMatcher) => {
const {index, rules} = findIndexAndRules(rulesSource, ruleMatcher)
return rules[index]
}
const cssRuleMatcher = (rule) => rule.test && String(rule.test) === String(/\.css$/)
const createLoaderMatcher = (loader) => (rule) => rule.loader && rule.loader.indexOf(`/${loader}/`) !== -1
const cssLoaderMatcher = createLoaderMatcher('css-loader')
const postcssLoaderMatcher = createLoaderMatcher('postcss-loader')
const fileLoaderMatcher = createLoaderMatcher('file-loader')
const addAfterRule = (rulesSource, ruleMatcher, value) => {
const {index, rules} = findIndexAndRules(rulesSource, ruleMatcher)
rules.splice(index + 1, 0, value)
}
const addBeforeRule = (rulesSource, ruleMatcher, value) => {
const {index, rules} = findIndexAndRules(rulesSource, ruleMatcher)
rules.splice(index, 0, value)
}
module.exports = function (config, env, lessOptions = {}) {
const cssRule = findRule(config.module.rules, cssRuleMatcher)
const lessRule = cloneDeep(cssRule)
const cssModulesRule = cloneDeep(cssRule)
cssRule.exclude = /\.module\.css$/
const cssModulesRuleCssLoader = findRule(cssModulesRule, cssLoaderMatcher)
cssModulesRuleCssLoader.options = Object.assign({modules: true, localIdentName: '[local]___[hash:base64:5]'}, cssModulesRuleCssLoader.options)
addBeforeRule(config.module.rules, fileLoaderMatcher, cssModulesRule)
lessRule.test = /\.less$/
lessRule.exclude = /\.module\.less$/
addAfterRule(lessRule, postcssLoaderMatcher, {
'loader': require.resolve('less-loader'),
'options': lessOptions,
})
addBeforeRule(config.module.rules, fileLoaderMatcher, lessRule)
const lessModulesRule = cloneDeep(cssModulesRule)
lessModulesRule.test = /\.module\.less$/
addAfterRule(lessModulesRule, postcssLoaderMatcher, require.resolve('less-loader'))
addBeforeRule(config.module.rules, fileLoaderMatcher, lessModulesRule)
return config
}
This is my override.js:
const path = require('path');
const cloneDeep = require('lodash.clonedeep')
const { compose, getLoader, injectBabelPlugin } = require('react-app-rewired');
const rewireLessModule = require('./react-app-rewire-less-module');
module.exports = function override(config, env) {
config = injectBabelPlugin('transform-decorators-legacy', config);
config = injectBabelPlugin(['import', { libraryName: 'antd', style: true }], config);
config = rewireLessModule(config, env, {
modifyVars: {
'@primary-color': '#1DA57A',
'@link-color': '#1DA57A',
'@border-radius-base': '2px',
'@font-size-base': '14px',
'@line-height-base': '1.2',
'@card-actions-background': '#f5f8fa',
},
});
return config;
};
Big thanks @WhatAKitty and @codebandits - saved me a lot of time
I changed it a little, the difference is that all css and less from node_modules , for example antd will load normally
and all css and less loaded from src/ will be treated as css modules. No need for foo.module.less files.
Note the libraryDirectory: "es" in babel import for antd, will use node_modules/antd/es instead of node_modules/antd/lib
const path = require("path");
const { compose, getLoader, injectBabelPlugin } = require("react-app-rewired");
const rewireLessModules = (prefix = "", lessOptions = {}) => {
const cloneDeep = require("lodash/clonedeep");
const ruleChildren = loader =>
loader.use ||
loader.oneOf ||
(Array.isArray(loader.loader) && loader.loader) ||
[];
const findIndexAndRules = (rulesSource, ruleMatcher) => {
let result = undefined;
const rules = Array.isArray(rulesSource)
? rulesSource
: ruleChildren(rulesSource);
rules.some(
(rule, index) =>
(result = ruleMatcher(rule)
? { index, rules }
: findIndexAndRules(ruleChildren(rule), ruleMatcher)),
);
return result;
};
const findRule = (rulesSource, ruleMatcher) => {
const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
return rules[index];
};
const cssRuleMatcher = rule =>
rule.test && String(rule.test) === String(/\.css$/);
const createLoaderMatcher = loader => rule =>
rule.loader && rule.loader.indexOf(`/${loader}/`) !== -1;
const cssLoaderMatcher = createLoaderMatcher("css-loader");
const postcssLoaderMatcher = createLoaderMatcher("postcss-loader");
const fileLoaderMatcher = createLoaderMatcher("file-loader");
const addAfterRule = (rulesSource, ruleMatcher, value) => {
const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
rules.splice(index + 1, 0, value);
};
const addBeforeRule = (rulesSource, ruleMatcher, value) => {
const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
rules.splice(index, 0, value);
};
return function(config, env) {
const cssRule = findRule(config.module.rules, cssRuleMatcher);
cssRule.exclude = path.resolve(__dirname, "src");
cssRule.include = path.resolve(__dirname, "node_modules");
const lessRule = cloneDeep(cssRule);
lessRule.test = /\.less$/;
const cssModulesRule = cloneDeep(cssRule);
cssModulesRule.include = path.resolve(__dirname, "src");
cssModulesRule.exclude = path.resolve(__dirname, "node_modules");
const cssModulesRuleCssLoader = findRule(cssModulesRule, cssLoaderMatcher);
cssModulesRuleCssLoader.options = Object.assign(
{
modules: true,
localIdentName: `${env === "production"
? prefix
: "[local]"}-[hash:base64:8]`,
},
cssModulesRuleCssLoader.options,
);
addBeforeRule(config.module.rules, fileLoaderMatcher, cssModulesRule);
addAfterRule(lessRule, postcssLoaderMatcher, {
loader: require.resolve("less-loader"),
options: lessOptions,
});
addBeforeRule(config.module.rules, fileLoaderMatcher, lessRule);
const lessModulesRule = cloneDeep(cssModulesRule);
lessModulesRule.test = lessRule.test;
addAfterRule(
lessModulesRule,
postcssLoaderMatcher,
require.resolve("less-loader"),
);
addBeforeRule(config.module.rules, fileLoaderMatcher, lessModulesRule);
return config;
};
};
module.exports = function override(config, env) {
config = injectBabelPlugin(
["import", { libraryName: "antd", style: true, libraryDirectory: "es" }],
config,
);
const rewires = compose(
rewireHTML,
rewireLessModules("my-css-prefix", {
modifyVars: {
"@primary-color": "#..",
"@info-color": "#...",
"@font-size-base": "14px",
},
}),
);
return rewires(config, env);
};
@WhatAKitty i forked repo from @codebandits and put the code above in and tweaked it a bit:
https://github.com/andriijas/react-app-rewire-less-modules
I also added less options to less module loader which makes it possible to use theme variables in components (primary colors etc). Check example repo: https://github.com/andriijas/create-react-app-playground/
Check these files:
Footer.less
Footer.js
theme.less
config-overrides.js
.env
@andriijas good job
Most helpful comment
@WhatAKitty i forked repo from @codebandits and put the code above in and tweaked it a bit:
https://github.com/andriijas/react-app-rewire-less-modules
I also added less options to less module loader which makes it possible to use theme variables in components (primary colors etc). Check example repo: https://github.com/andriijas/create-react-app-playground/
Check these files:
Footer.less
Footer.js
theme.less
config-overrides.js
.env