Ridhwaan Shakeel
Ridhwaan Shakeel

Reputation: 1053

Webpack can't fix CSS override issue and bundle <style> elements in <head>

In my app, lets say I have two JS pages A and B, and each import a different stylesheet (import '../style/<A or B.css>').
Both stylesheets have identical classnames but but different properties.

I run yarn run dev ==> dev: webpack-dev-server --inline --hot ==> webpack -p

This is what my html <head> looks like
https://i.sstatic.net/cqpBR.jpg
page A stylesheet is loaded first, then page B css style is loaded after

When I go to Page B, the css is correct
When I go to Page A, the css is mixed up and some class styles are overriden by page B.css.

My project structure is like

public/
 bundle.js
 index.html
src/
 components/
 pages/
 style/
 App.js
 index.js
 package.json
 webpack.config.js

my webpack.config.js is

const path = require('path');

var config = {
    entry: path.resolve(__dirname, 'src', 'index.js'),
    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: path.resolve(__dirname, 'src'),
        publicPath: path.resolve(__dirname, 'public')
    },
    module: {
        rules: [
        {
            test: /\.js$/,
            exclude: /(node_modules|bower_components)/,
            use: [
                { loader: 'babel-loader',
                options: { presets: ['react','env'] } }
            ]
        },
        {
            test: /\.css$/,
            use: [
                { loader: "style-loader?singleton", 
                  options: 
                  { singleton: true } 
                },
                { loader: "css-loader" }
            ]
        }
        ]
    }
};
module.exports = config;

I want Webpack to merge the multiple elements and fix the css override issue
In Webpack, I have tried style-loader?singleton and { singleton: true } but it didnt work.

EDIT 1: looking into extract-text-webpack-plugin

EDIT 2:

import movieStyle from '../style/MovieDetail.css' 
... 
return (
<div id="CellDetail_right" className={ movieStyle['cell-detail-right'] }>...</div>
) 

Ok, I added options: { modules: true } and it didnt work. My classNames are hyphenated and after compiling the browser renders the components WITHOUT any style or classes. Div on browser looks like <div id="CellDetail_right">...<div>

Upvotes: 0

Views: 3624

Answers (1)

Carloluis
Carloluis

Reputation: 4320

One solution is to enable local scoped css to avoid styles bleeding/overrides. Update your css-loader options to include modules: true

{
    test: /\.css$/,
    use: [
        {
            loader: "style-loader", 
            options: { singleton: true }
        },
        {
            loader: "css-loader",
            options: {
                modules: true,
                camelCase: 'dashes',
                localIdentName: '[path][name]__[local]'
            }
        }
    ]
}

Then, using in your components as:

import styles from '../style/MovieDetail.css';

function MyComponent() {
    return (
        <div className={styles.container}>
            <div className={styles.cellDetailRight}>Some Content</div>
        </div>
    );
}

This ensures that despite you have more .container rules defined in other css files, this particular rule becomes to something like ._-path-to-component__container.

Using camelCase: 'dashes' in options transform your hyphenated rules.

dashes in class names will be camelized

You can also review my webpack-demo project which includes configs to handle your scenario. Check the webpack configurations

Read more on css-loader options


enter image description here

Upvotes: 1

Related Questions