DEV Community

Cover image for Setting up CSS and Sass with Webpack!!
Deepanjan Ghosh
Deepanjan Ghosh

Posted on • Edited on

Setting up CSS and Sass with Webpack!!

One of the most fundamental parts of frontend development is styling, in this post, we will see how to use styles with webpack. This post is a continuation of my earlier post where I have explained How to set up react project with webpack and babel. So if you have never set up a react project with webpack then I'll suggest you read my previous post and then come back to this post or happen to have a react project already set up and wonder how to work with styles then you are in the right place.

In this post, we will see how to set up both CSS and a CSS pre-processor like Sass with webpack one by one.

As we know webpack is a module bundler and it is responsible for analyzing the files and bundles all your need to run the application in a single JavaScript output file which we commonly call bundle.js. Webpack by default only understands javascript and in order to make webpack understand other resources like .css, .scss, etc we need the help of loaders to compile it. Let see how to do it.

Setting up CSS with webpack

At first, let's install some dev dependencies.



npm i --save-dev css-loader style-loader


Enter fullscreen mode Exit fullscreen mode
  • The definition says css-loader interprets @import and url() like import/require() and will resolve them. What do we mean by this? css-loader will take all the CSS from the CSS file and generate it to a single string and will pass this to style-loader.
  • style-loader will take this string and will embed it in the style tag in index.html.

Now let's add the configuration in webpack.config.js. Add this line inside rules in the module.



...
   module: {
        rules: [
            {
                test: /\.(css)$/,
                use: ['style-loader','css-loader']
            }
        ]
    }
...


Enter fullscreen mode Exit fullscreen mode

Here the test property will tell the webpack to use style-loader and css-loader for all the .css files.

(Note: The order in which webpack apply loaders is from last to first, so as said earlier the css-loader will generate the output string which will be used by the style-loader.)

The overall content of webpack.config.js will be:



const path = require('path');

module.exports = {
    mode: "development",
    entry: path.resolve(__dirname, './src/index.js'),
    devtool: "eval-source-map",
    module: {
        rules: [
          {
             test: /\.(js|jsx)$/,
             exclude: /node_modules/,
             use: ['babel-loader']
          },
          {
             test: /\.(css)$/,
             use: ['style-loader','css-loader']
          }
        ]
    },
    resolve: {
        extensions: ['*', '.js', '.jsx']
    },
    output: {
        path: path.resolve(__dirname, './public'),
        filename: 'bundle.js',
    },
    devServer: {
        contentBase: path.resolve(__dirname, './public'),
        hot: true
    },
};


Enter fullscreen mode Exit fullscreen mode

Next, we will add an app.css file with the following content.



.container {
    height: 100vh;
    background-color: #E7E3EB;
}

.header {
    padding: 15px 20px;
    background-color: #6200EE;
}

h1 {
    color: #FFF;
}


Enter fullscreen mode Exit fullscreen mode

App.jsx



import React from 'react';
import './app.css';

const App = () => {
    return (
        <div className="container">
            <div className="header">
                <h1>Welcome to React application</h1>
            </div>
        </div>
    )
}

export default App


Enter fullscreen mode Exit fullscreen mode

and now run npm start and you'll see the output in your browser.

Screenshot 2021-04-28 at 6.51.19 PM

Configuration for your production environment.

If you have a webpack configuration for production then you'll need a different configuration for using CSS. At first, install mini-css-extract-plugin



npm i --save-dev mini-css-extract-plugin


Enter fullscreen mode Exit fullscreen mode

and now extract the miniCssExtractPlugin and replace the style-loader with MiniCssExtractPlugin.loader and add the MiniCssExtractPlugin in plugin.
MiniCssExtractPlugin extracts CSS and create a CSS file per JS file.



const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    mode: "production",
    entry: path.resolve(__dirname, './src/index.js'),
    devtool: "source-map",
    module: {
        rules: [
          {
             test: /\.(js|jsx)$/,
             exclude: /node_modules/,
             use: ['babel-loader']
          },
          {
             test: /\.(css)$/,
             use: [MiniCssExtractPlugin.loader,'css-loader']
          }
        ]
    },
    resolve: {
        extensions: ['*', '.js', '.jsx']
    },
    plugins: [new MiniCssExtractPlugin()],
    output: {
        path: path.resolve(__dirname, './public'),
        filename: 'bundle.js',
    },
};


Enter fullscreen mode Exit fullscreen mode

Now, run npm run build and you will see the external files generated in your public folder like main.css and main.css.map. If you want to check whether your build folder has everything as expected you can check it on by running it on the local web server, run this command on your command line.



npx http-server public


Enter fullscreen mode Exit fullscreen mode

This will provide you a URL that you can visit in a browser.


Setting up Sass with webpack

If you happen to prefer Sass more than CSS like me then you need to install some packages to set up Sass with webpack.



npm i --save-dev sass-loader node-sass


Enter fullscreen mode Exit fullscreen mode
  • node-sass provides binding Node.js to LibSass (The C version of Sass). sass-loader document says "The sass-loader requires you to install either Node Sass or Dart Sass on your own. This allows you to control the versions of all your dependencies, and to choose which Sass implementation to use." Essentially this loader has internal dependencies which require node-sass.
  • sass-loader loads a Sass/SCSS file and compiles it to CSS.

Now let's update the webpack.config.js.



const path = require('path');

module.exports = {
    mode: "development",
    entry: path.resolve(__dirname, './src/index.js'),
    devtool: "eval-source-map",
    module: {
        rules: [
          {
             test: /\.(js|jsx)$/,
             exclude: /node_modules/,
             use: ['babel-loader']
          },
          {
             test: /\.(s(a|c)ss)$/,
             use: ['style-loader','css-loader', 'sass-loader']
          }
        ]
    },
    resolve: {
        extensions: ['*', '.js', '.jsx']
    },
    output: {
        path: path.resolve(__dirname, './public'),
        filename: 'bundle.js',
    },
    devServer: {
        contentBase: path.resolve(__dirname, './public'),
        hot: true
    },
};


Enter fullscreen mode Exit fullscreen mode

We just need to add the sass-loader ahead of css-loader, so now first, the .scss file compiles back to CSS and after that process remains the same as explained above.
Next, let's change the app.css file to app.scss and update the file with our favorite sass features.

app.scss



.container {
    height: 100vh;
    background-color: #E7E3EB;
    .header {
        padding: 15px 20px;
        background-color: #6200EE;
        h1 {
            color: #FFF;
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

Now run npm start the result will be the same as above but now we have written Sass in place of CSS.

Sass configuration for production environment

Configuration for production remains pretty same as we did for CSS setup, we will be using the same mini-css-extract-plugin to extract our separate CSS file, it is just that we need to add sass-loader ahead of css-loader as we did earlier for our development configuration. The updated file will look like this.



const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    mode: "production",
    entry: path.resolve(__dirname, './src/index.js'),
    devtool: "source-map",
    module: {
        rules: [
          {
             test: /\.(js|jsx)$/,
             exclude: /node_modules/,
             use: ['babel-loader']
          },
          {
             test: /\.(s(a|c)ss)$/,
             use: [MiniCssExtractPlugin.loader,'css-loader', 'sass-loader']
          }
        ]
    },
    resolve: {
        extensions: ['*', '.js', '.jsx']
    },
    plugins: [new MiniCssExtractPlugin()],
    output: {
        path: path.resolve(__dirname, './public'),
        filename: 'bundle.js',
    },
};


Enter fullscreen mode Exit fullscreen mode

Now build your project again by running npm run build and check the output by running in the local webserver.


Extras

Congratulations!! 🎉 You have now successfully set up CSS and Sass with webpack in your react project but your project needs a bit more than styles to make it more attractive and user friendly like images and fonts. I am will give a short tutorial on how to set them up with webpack.

Let's add a dev dependency to support these file formats.



npm i --save-dev url-loader


Enter fullscreen mode Exit fullscreen mode

Font Setup

First, download fonts, for this tutorial purpose I have downloaded Open Sans Italic from google fonts and moved them in a folder (src/Assets/Fonts/). Now create a font.scss file and add the font face inside



@font-face {
    font-family: 'Open Sans Italic';
    src: url('./Assets/Fonts/OpenSansItalic.eot');
    src: url('./Assets/Fonts/OpenSansItalic.eot?#iefix') format('embedded-opentype'),
         url('./Assets/Fonts/OpenSansItalic.woff') format('woff'),
         url('./Assets/Fonts/OpenSansItalic.ttf') format('truetype'),
         url('./Assets/Fonts/OpenSansItalic.svg#OpenSansItalic') format('svg');
    font-weight: normal;
    font-style: italic;
}


Enter fullscreen mode Exit fullscreen mode

and let's import the fonts file inside app.scss and apply the fonts to <h1> tag.

app.scss



@import url(./font.scss);

.container {
    height: 100vh;
    background-color: #E7E3EB;
    .header {
        padding: 15px 20px;
        background-color: #6200EE;
        h1 {
            color: #FFF;
            font-family: 'Open Sans Italic';
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

Next, update the webpack.config.js to support all the file formats.



...
   rules: [
          ....
          {
                test: /\.(woff|woff2|eot|ttf|svg)$/,
                use: {
                  loader: 'url-loader',
                },
          },
          ....
          ]
...


Enter fullscreen mode Exit fullscreen mode

Now, run npm start and now your font will be updated.

Image setup

To use images with webpack we just need to add the image file extension which we need inside the test of url-loader.
Updated webpack.config.js



...
   rules: [
          ....
          {
                test: /\.(woff|woff2|eot|ttf|svg|jpg|png)$/,
                use: {
                  loader: 'url-loader',
                },
          },
          ....
          ]
...


Enter fullscreen mode Exit fullscreen mode

Now, let's update the app.jsx and app.scss.

App.jsx



import React from 'react';
import './app.scss';

const App = () => {
    return (
        <div className="container">
            <div className="header">
                    <h1>Welcome to React application</h1>
            </div>
            <div className="react-logo"></div>
        </div>
    )
}

export default App


Enter fullscreen mode Exit fullscreen mode

app.scss



@import url(./font.scss);

.container {
    height: 100vh;
    background-color: #E7E3EB;
    .header {
        padding: 15px 20px;
        background-color: #6200EE;
        h1 {
            color: #FFF;
            font-family: 'Open Sans Italic';
        }
    }

    .react-logo {
        background: url('./Assets/Images/react-logo.png') no-repeat center;
        height: 500px;
        width: 500px;
        background-size: contain;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
}


Enter fullscreen mode Exit fullscreen mode

Now let's run the npm start again and see the output in the browser.

Screenshot 2021-04-29 at 2.06.17 AM

As we can see our image has been added and the fonts have been updated.
There are plenty of options for all the loaders we have used in this tutorial, I suggest you read the documents and use them according to your project needs or you can just explore them also.

Don't forget to give a ❤️ if you liked it and thanks for reading and if you want to support me then you can just buy me a coffee 😃

Happy coding! 🧑🏻‍💻

Top comments (5)

Collapse
 
seanraad123 profile image
Sean Conrad

Great tutorial! Heads up, your link for 'How to set up react project with webpack and babel' is pointing to google.com

Collapse
 
karenmbuitrago1 profile image
Karenmbuitrago

Best tutorial!

Collapse
 
aderchox profile image
aderchox • Edited

Thanks a lot for this article.
I just didn't understand this regex: \.(s(a|c)ss)$
So I used mine: \.(c|sa|sc)ss$.

Collapse
 
tehkonst profile image
tehkonst

Please, fix the link at the beginning. It leads to the google.

Collapse
 
deepanjangh profile image
Deepanjan Ghosh • Edited

Done! Thanks for pointing out 🙂