LESS style not applied to react component in react+webpack application - reactjs

In a react + web pack application, I'm trying to style my react component using LESS, but the style does not get applied, although I get no errors, so I wouldn't know where to look. Of course, my devDependencies includes less, less-loader, CSS-loader and style-loader.
webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
"babel-loader",
"eslint-loader"
]
},
{
test: /\.(c|le)ss$/,
use: [
"style-loader",
"css-loader",
"less-loader",
]
}
]
},
resolve: {
extensions: [".js", ".jsx"],
alias: {
"#components": path.resolve(__dirname, "src/components"),
"#containers": path.resolve(__dirname, "src/containers")
}
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
}
};
components/App/App.jsx
import React from "react";
import Body from "#components/Body/Body.jsx";
import Footer from "#components/Footer/Footer.jsx";
import styles from "./App.less";
class App extends React.Component {
render() {
return <div className={styles.root}>
<h1> test </h1>
<Body />
<Footer />
</div>;
}
}
export default App;
components/App/App.less
.root {
width: 100%;
height: 100%;
background-color: coral;
h1 {
margin-top: 200px;
color: red;
}
}
I expected to see the style applied, but it's not.

Try setting "root" as string-value to className.
The way your webpack has been configured, the content of the LESS-files will not be exported as css-rules but only collected to be rendered into a style-tag.
You need to import the less-file, so webpack knows which files to consider, but you neither can access its rules, or its styles. So to make it work, you simply set the CSS-class names so that the compiled CSS-rules match.

I had to enable CSS Modules in the Webpack config:
{
test: /\.(c|le)ss$/,
use: [
"style-loader",
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: "[path][name]__[local]--[hash:base64:5]",
},
},
"less-loader"
]
},

Related

How do you remove unused classes with Webpack 4 tree shaking with CSS modules?

Someone made a great example to remove unused CSS based on whether or not the JS Module is used, but I am trying to figure out how to remove the unused CSS classes from the bundle that are not actually used by components.
Example
// Sub.scss
.sub-container {
background-color: green;
}
.unused-junk {
color: blue;
}
// Sub.js
import React from "react";
import styles from "./Sub.scss";
export default function Sub() {
return <div className={styles.subContainer}>Hi from sub.</div>;
}
// App.scss
.app-container {
background-color: red;
}
// App.js
import React from "react";
import ReactDOM from "react-dom";
import Sub from "./Sub";
import styles from "./App.scss";
function App() {
return (
<div className={styles.appContainer}>
Hi from app.
<Sub />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: "./src/App.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js/,
loader: "babel-loader",
include: __dirname + "/src",
query: {
presets: ["react"]
}
},
{
test: /\.scss/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true,
camelCase: true,
importLoaders: 1,
localIdentName: "[name]--[local]--[hash:base64:5]"
}
},
"sass-loader"
],
include: __dirname + "/src"
}
]
},
plugins: [
new CopyWebpackPlugin([{ from: `src/index.html`, to: "index.html" }]),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};
// CSS bundle
.App--app-container--3wd6W {
background-color: red; }
.Sub--sub-container--38uqh {
background-color: green; }
.Sub--unused-junk--2-h5r {
color: blue; }
Is there a way to tree shake the .unused-junk class from the bundle?

toastr not showing when imported in a jsx file

I have a react app that uses webpack to bundle JS and CSS into 1 file and output it into a destination folder. I've recently added toastr to 1 of my jsx file:
import toastr from "toastr";
import "toastr/build/toastr.min.css"
Running the app and viewing the source, i've verified in the browser (viewing the source files) that toastr.min.js is included in the JS bundle and toastr.min.css is included in the CSS bundle. However, the toastr notification doesn't show. There is no error and a scrollbar appears in the right-side for a few seconds so I suspected the toastr code is working, just that the CSS is not properly styling for some reason.
I removed this line:
import "toastr/build/toastr.min.css"
and then directly added this to html
<link rel="stylesheet" type="text/css" href="~/css/toastr.min.css" />
and now it works. But I want to make it work where toastr.min.css is included in the bundle. Is there anything I'm missing?
webpack config
const path = require("path");
const webpack = require("webpack");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
home: "./Scripts/Components/Home/main.js",
login: "./Scripts/Components/Login/main.js",
vendor: [
"jquery",
"react",
"react-dom",
"react-router-dom",
"react-css-modules",
]
},
mode: "development",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "all",
name: "vendor",
test: "vendor",
enforce: true
}
}
}
},
output: {
publicPath: "/js/",
path: path.join(__dirname, "/wwwroot/js/"),
filename: "[name].bundle.js"
},
devtool: "source-map",
plugins: [
new miniCssExtractPlugin({
filename: "../css/[name].css"
}),
],
module: {
rules: [{
test: /\.jsx$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["env", "react"]
}
}
}, {
test: /\.css$/,
use: [{
loader: miniCssExtractPlugin.loader,
}, {
loader: "css-loader",
query: {
modules: true,
localIdentName: "[name]__[local]___[hash:base64:5]"
}
}]
}]
}
};

Nested classes not working in CSS Modules with webpack

Im using webpack and css-loader and style-loader to enable css modules in my React app. These are the following setup:
Webpack config:
module.exports = {
mode: "development",
entry: __dirname + "/app/index.js",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true,
localIdentName: "[name]__[local]___[hash:base64:5]"
}
}
]
}
]
},
output: {
filename: "bundle.js",
path: __dirname + "/build"
},
plugins: [HTMLWebpackPluginConfig]
};
And in my React component I've coded this:
import React from "react";
import styles from "./Carousel.css";
class Carousel extends React.Component {
render() {
return (
<div className={styles["carousel"]}>
<img
className={styles["test"]}
src="https://i2.wp.com/beebom.com/wp-content/uploads/2016/01/Reverse-Image-Search-Engines-Apps-And-Its-Uses-2016.jpg?resize=640%2C426"
/>
</div>
);
}
}
export default Carousel;
In my Carousel.css file:
.carousel {
background-color: red;
.test {
width: 200px;
}
}
When I check the rendered HTML, I can see carousel class and its properties coming in the parent div. But the child img tag shows the class name but no property is associated with it.
Any idea what Im doing wrong here?
EDIT:: Sam's suggestions worked and Im summarising the changes that solved it:
Since nesting is a feature of css, we need to use sass or less. And for that I used postcss-loader.
Updated webpack config rules section:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true,
localIdentName: "[name]__[local]___[hash:base64:5]"
}
},
*"postcss-loader"*
]
}
Also added a postcss.config.js file like this:
module.exports = {
plugins: [
require("postcss-nested")({
/* ...options */
})
]
};
And added postcss-loader, postcss-nested packages using npm install -D option.
How are you importing the css file ?
You can follow the below way to import too,
In your component,
import ‘styles.css’
In HTML element,
<div className='carousel'>
<div className='test'></div>
</div>
In webpack config,
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}

React-Date "SingleDatePicker" not working as expected?

I am using react-dates and trying to implement singledatepicker. All the functionality is working but I dont know why all the default styles are gone. I am also using babel "transform-class-properties"
import React from 'react';
import moment from 'moment'
import 'react-dates/initialize';
import {SingleDatePicker} from 'react-dates';
import 'react-dates/lib/css/_datepicker.css';
const now= moment();
export default class ExpenseForm extends React.Component{
state={
description:'',
note:'',
amount:'',
createdAt:moment(),
calendarFocused:false
}
onDateChange = (createdAt)=>{
this.setState(()=>({createdAt}));
}
onFocusChange =({focused})=>{
this.setState(()=>({calendarFocused:focused}))
}
render(){
return(
<div>
<h3>ExpenseForm</h3>
<form>
<SingleDatePicker
date={this.state.createdAt}
onDateChange={this.onDateChange}
focused={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
/>
</form>
</div>
)
}
}
Here is my Webpack config file and it is loaded with css-loader
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},{
test: /\.s?css$/,
use:['style-loader','css-loader','sass-loader']
}
]
},
devtool:'cheap-module-eval-source-map',
devServer:{
contentBase:path.resolve(__dirname, 'public'),
historyApiFallback:true
}
};
I had exact the same problem when integration react-dates into my project, and I believe the root cause is that the css module in your project also compile the css of react-dates which leads to missing of the style. To solve this problem, you could modify the rule in your module like:
...your original css module rule
exclude: [
/node_modules/
]
after applying this rule, you might encounter another issue which is that these css files can't be properly handled due to being excluded, you should then add another css module to handle those css file that you don't want to mess with, for example:
exports.vendorCss = {
test: /\.(css|scss|sass)$/,
include: [/node_modules/],
loaders: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'sass-loader',
},
],
};
and there you have it!! Hope this can help!

Webpack & React. Loaded image can't resolve path 404

At this case I am trying to set up sort of high-order component and further implement 'dynamic' image loads for it. Can you please explain what has been done wrong in order to reference to the inside the component.
React Component
class Slide extends Component {
constructor(props) {
super(props)
}
render () {
let imageLeft = {
backgroundImage: 'url(./assets/introleft.png)'
}
return (
<div className={styles.someStyles}>
<div className={styles.someStyles} style={imageLeft} > </div>
</div>
)
}
}
... state
export default connect(mapStateToProps)(Slide);
Project structure
Webpack config
const path = require('path'),
webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
'./index.js'
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/'
},
context: path.resolve(__dirname, 'logic'),
devtool: 'inline-source-map',
devServer: {
hot: true,
contentBase: path.resolve(__dirname, 'build'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader',
],
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader?modules',
'postcss-loader',
],
},{
test: /\.png$/,
use: { loader: 'url-loader', options: { limit: 15000 } },
},
{
test: /\.svg$/,
use: {
loader: 'svg-url-loader',
options: {}
}
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
template: './index.template.html'
})<script> tag
],
};
P.S: Project has no node.js server, just wepback-dev. So react-router uses hash history /#, wounder if it somehow affects the webpack publicPath property.
When you're using backgroundImage: 'url(./assets/introleft.png)', this will be inserted as is (it's just a string), so your url-loader won't be applied to it. Instead you should import the image:
import introleft from './assets/introleft.png';
Webpack will have applied the url-loader and you get back either the data URL or the URL to the extracted image, if the size was too big. All you need to do now is put that URL into your backgroundImage:
backgroundImage: `url(${introleft})`

Resources