A logo showing the text blog.marcnuri.com
Español
Home»Front-end»React : Babel + Webpack + Sass boilerplate application

Recent Posts

  • MCP Tool Annotations: Adding Metadata and Context to Your AI Tools
  • Fabric8 Kubernetes Client 7.2 is now available!
  • Connecting to an MCP Server from JavaScript using AI SDK
  • Connecting to an MCP Server from JavaScript using LangChain.js
  • The Future of Developer Tools: Adapting to Machine-Based Developers

Categories

  • Artificial Intelligence
  • Front-end
  • Go
  • Industry and business
  • Java
  • JavaScript
  • Legacy
  • Operations
  • Personal
  • Pet projects
  • Tools

Archives

  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • August 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • February 2020
  • January 2020
  • December 2019
  • October 2019
  • September 2019
  • July 2019
  • March 2019
  • November 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • December 2017
  • July 2017
  • January 2017
  • December 2015
  • November 2015
  • December 2014
  • March 2014
  • February 2011
  • November 2008
  • June 2008
  • May 2008
  • April 2008
  • January 2008
  • November 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007

React : Babel + Webpack + Sass boilerplate application

2018-07-08 in Front-end tagged Babel / Frontend / JavaScript / Node / npm / React / Sass / SCSS / Webpack by Marc Nuri | Last updated: 2021-04-03
Versión en Español

Introduction

In this tutorial, we’ll see how to build from scratch a React application with Webpack, Babel, and Sass.

The main requirement for this tutorial is to have a node installation with npm for your platform/OS.

The tutorial is structured in several parts:

  • Create an initial project directory
  • Webpack setup
  • Babel setup
  • React
  • Add support for Sass styles

Initial project

The first step is to create an initial empty project. For that purpose we’ll create an empty directory for the project and run the following command:

1npm init -y

This command will set up a new package.json file containing metadata for an empty project.

Relevant parts of the generated package.json should be updated to match those of the project, this is the contents of the file after the initial modifications:

1{
2  "name": "react-webpack-babel-sass-boilerplate",
3  "version": "2.0.0",
4  "description": "Boilerplate React application with Webpack, Babel and Sass.",
5  "main": "index.js",
6  "scripts": {
7    "test": "echo \"Error: no test specified\" && exit 1"
8  },
9  "repository": {
10    "type": "git",
11    "url": "git+https://github.com/marcnuri-demo/react-webpack-babel-sass-boilerplate.git"
12  },
13  "keywords": [],
14  "author": {
15    "name": "Marc Nuri",
16    "url": "https://blog.marcnuri.com"
17  },
18  "license": "Apache-2.0",
19  "licenses": [
20    {
21      "type": "Apache-2.0",
22      "url": "http://www.apache.org/licenses/LICENSE-2.0"
23    }
24  ],
25  "bugs": {
26    "url": "https://github.com/marcnuri-demo/react-webpack-babel-sass-boilerplate/issues"
27  },
28  "homepage": "https://github.com/marcnuri-demo/react-webpack-babel-sass-boilerplate#readme"
29}

Webpack 4 support

Webpack setup

The next step is to add support for Webpack.

1npm install --save-dev webpack webpack-dev-server webpack-cli html-webpack-plugin html-loader

The previous command will add Webpack development dependencies to our package.json. The first three are strictly Webpack related, if you’ve worked with Webpack in other projects probably you’ll already have them installed as global dependencies. For our purposes, and to support different versions of Webpack, we’ll install them as local development dependencies.

The other two dependencies (html-webpack-plugin, html-loader) will be used to minimize HTML and to be able to reference the bundled Javascript for our application.

After running the command, a new section will be created in our package.json with the new "devDependencies".

Webpack configuration

The first step is to create some source content that Webpack will process. We create a new directory for our sources (src) and add a new index.html file in this directory with the following content:

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8" />
5  <title>react-webpack-babel-sass-boilerplate</title>
6</head>
7<body>
8  <div id="root"></div>
9</body>
10</html>

For Webpack (4) to work, we are going to need a new webpack configuration file. We must create an empty webpack.config.js in the project’s root directory and add the following content:

1const webpack = require('webpack');
2const HtmlWebpackPlugin = require('html-webpack-plugin');
3
4const SRC_DIR = __dirname + '/src';
5const DIST_DIR = __dirname + '/dist';
6
7module.exports = {
8  entry: [
9    SRC_DIR + '/index.html',
10  ],
11  output: {
12    path: DIST_DIR,
13    publicPath: '/',
14    filename: 'bundle.js'
15  },
16  module: {
17    rules: [
18      {
19        test: /\.(html)$/,
20        exclude: /node_modules/,
21        use: {
22          loader: 'html-loader',
23          options: {minimize: true}
24        }
25      }
26    ]
27  },
28  resolve: {
29    extensions: ['*', '.js', '.jsx']
30  },
31  plugins: [
32    new webpack.HotModuleReplacementPlugin(),
33    new HtmlWebpackPlugin({
34      template: SRC_DIR + '/index.html',
35      filename: './index.html'
36    })
37  ],
38  devServer: {
39    contentBase: DIST_DIR,
40    hot: true,
41    port: 9000
42  }
43};

In the first section we add the script requirements and declare two constants (SRC_DIR, DIST_DIR) for the source and distribution directories.

Next, we declare a new module using the index.html file we created in the earlier step as the entry point. The output files for the module will be generated in a directory named ./dist. When the project is built a minimized index.html file and a bundle.js will be generated in this directory.

In the rules section, we are going to add our first loader. In this case, we are going to use the html-loader to preprocess all of the html files located in the src directory.

Next, we define the resolve extensions. This configuration for extensions allows us to import resources using only the filename, so when importing a component in our code (import Component from ./feature/Component') Webpack will look for the component source file in ./feature/Component, ./feature/Component.js and ./feature/Component.jsx.

In the plugins section, we are going to add Webpack’s HotModuleReplacementPlugin which exchanges, adds, or removes modules while the application is running without the need for a full reload whenever a change is made to the source code (hot reloading).

We are also going to add HtmlWebpackPlugin which will add our bundled javascript in the index.html file we created earlier.

Finally, we are defining a devServer to serve our module using hot reloading in port 9000.

package.json webpack scripts

The final step to setup Webpack 4 is to add some scripts to package.json file so that the application can be built and served:

1"scripts": {
2    "build": "./node_modules/.bin/webpack -p --mode production",
3    "start": "./node_modules/.bin/webpack-dev-server --config ./webpack.config.js --mode development",
4    "test": "echo \"Error: no test specified\" && exit 1"
5  },

The first script (npm run build) will build the application in our dist directory generating two files: index.html and bundle.js. These files could be deployed and served by a web server without further configurations.

The second script (npm start) will launch a development server with the compiled module and will listen for changes. When invoked, we could open our browser and point to http://localhost:9000 where the application should now be available. Any change to any of the source files should trigger a reload in the browser and changes should be displayed.

A particularity for these scripts is that they are triggering local webpack client installation (./node_modules/.bin/webpack) instead of the maybe globally available webpack client (webpack). This will allow us to run a specific version of webpack in our project, controlled at devDependencies section of package.json.

Babel 7 support

Babel setup

The next step is to add support for Babel. Babel will be in charge of transpiling JSX and Javascript to ES5 compatible Javascript. React recommends writing code using JSX syntax as it provides an easy way to mix HTML code with regular Javascript.

1npm install --save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react

The previous command will add all Babel development dependencies to our package.json. @babel/core package will add basic support for Babel. babel-loader will enable running Babel from webpack, @babel/preset-env will add support to transpile Javascript > ES5 files into ES5 compatible Javascript. @babel/preset-react will add support to transpile JSX files.

We’ll also add some additional plugins that will make our life easier when coding and add support for new Javascript features. These plugins will also serve as an example of how we must configure Babel + Webpack to enable them.

1npm install --save-dev @babel/plugin-proposal-object-rest-spread @babel/plugin-syntax-dynamic-import @babel/plugin-transform-runtime @babel/runtime

Babel configuration

In previous Babel versions, we used to add configuration in a .babelrc file. Since Babel 7, the recommended approach is to set the configuration in a project-wide babel.config.js file.

The configuration file will be used to load the presets and the plugins we’ve added in our devDependencies section of our package.json in the previous step.

1module.exports = {
2  presets: ['@babel/preset-env', '@babel/preset-react'],
3  plugins: [
4    '@babel/plugin-transform-runtime',
5    '@babel/plugin-proposal-object-rest-spread',
6    '@babel/plugin-syntax-dynamic-import'
7  ]
8};

Now we have to configure webpack to use the Babel loader and preprocess jsx and js files before packaging them. To do so we’ll add the following rule to the module rules section in webpack.config.js:

1{
2  test: /\.(js|jsx)$/,
3  exclude: /node_modules/,
4  use: {
5    loader: 'babel-loader'
6  }
7},

From this point whenever any of the defined Webpack scripts is triggered, Babel will run and transpile js/jsx using the presets defined and configurations defined in babel.config.js file.

React

React setup

In order to be able to use React in the project we must add two additional packages:

1npm install --save react react-dom

The previous command will add React dependencies to our package.json.

Application entrypoint

Next, we are going to create the entry point for our demo React application. For this purpose, we’ll create an index.jsx file under the src directory with the following content:

1import React from 'react';
2import ReactDOM from 'react-dom';
3
4ReactDOM.render(
5    <p>Hello world</p>,
6    document.getElementById('root')
7);
8
9if (module.hot) {
10  module.hot.accept();
11}

This file will render <p>Hello world</p> inside the <div id="root"... tag in the index.html file we created in the previous step.

As of now, we could already launch our application using npm start command and load our application pointing our browser to http://localhost:9000/

Screenshot fo the React Hello World in a browser
Screenshot fo the React Hello World in a browser

Hot Module Replacement

Our application includes Webpack’s Hot Module Replacement plugin (HMR). This plugin exchanges, adds or removes modules from an application while it’s running without the need of triggering a full reload. This improves performance and development productivity because changes in the source code are reflected almost instantly without the need to completely redeploy the application.

Any change to a source file will trigger an automatic page reload in the browser and changes will be reflected instantly.

The only drawback to HMR is that it doesn’t preserve the application state. In a future post we’ll see how we can use React Hot Loader to speed up even more application development by preserving the application state.

React App Component

In order to keep the code structured, we are going to add our first component to the application and nest it inside our main index.jsx. We’ll create an app.jsx file with the following content:

1import React, {Component} from 'react';
2
3const content = 'Hello world!';
4
5class App extends Component {
6  render() {
7    return (
8      <p>{content}</p>
9    );
10  }
11}
12
13export default App;

Next, we’ll import the new component in index.jsx (import App from "./app";) and add the new component:

1/* ... */
2ReactDOM.render(
3    <App/>,
4    document.getElementById('root')
5);
6/* ... */

SCSS support

Although React offers several ways to style components and there are plenty of styling libraries available, I still find it useful to use plain old school CSS or Sass style sheets to style the application. The main reasons are that Sass allows me to share variables, media queries, partials, mixins… efficiently throughout the application and even between different code bases with different frameworks (I can share the same SCSS library between a site built with React, Angular, Hugo…).

SCSS Setup

In order to preprocess SCSS files, we’ll need to add a couple of loaders to webpack and the Sass preprocessor LibSass bindings for node (node-sass):

1npm install --save-dev mini-css-extract-plugin css-loader sass-loader node-sass

mini-css-extract-plugin will be in charge of extracting all of our generated css into a single file. css-loader will be in charge of our css modules (explained later on) and of resolving styles within our React components. sass-loader and node-sass will be responsible for SCSS preprocessing and compiling Sass into regular CSS.

Next we add a new rule to the module rules section of our webpack.config.js to invoke the loaders we just added:

1{
2  test: /\.(scss|sass|css)$/,
3  exclude: /node_modules/,
4  loaders: [
5    MiniCssExtractPlugin.loader,
6    {
7      loader: 'css-loader',
8      options: {
9        modules: true,
10        sourceMap: true,
11        importLoaders: 1,
12        localIdentName: '[local]___[hash:base64:5]'
13      }
14    },
15  'sass-loader',
16  ]
17},

Here we are referencing the 3 loaders we just installed. For css-loader we add a special configuration to support CSS modules (explained in the CSS modules section).

We also need to add a reference and configuration for MiniCssExtractPlugin in the plugins section (Please review full webpack.config.js file to check imports and constant declarations):

1new MiniCssExtractPlugin({
2  filename: devMode ? '[name].css' : '[name].[hash].css',
3  chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
4})

In these lines we define MiniCssExtractPlugin plugin configuration and how is our CSS file going to be generated.

Global SCSS

For our global styles we’ll create the following structure:

1src
2└─┬ styles
3  ├─┬ partials
4  | ├── _base.scss
5  | ├── _mixins.scss
6  | └── _variables.scss
7  └── main.scss

main.scss file contains imports for the partials files. As an example we’ve included three Sass partials files: _variables.scss to declare variables for colors, fonts, etc.; _mixins.scss which includes an example mixin to make a box resizeable; and _base.scss which includes the basic styles for the application.

In order to enable these global styles in the application, we need to import the main.scss styles in our app.jsx, this is as simple as adding the following line to the imports section: import styles from './styles/main.scss';. Webpack will automatically resolve and add the imports during transpilation using the module rule and loader we added in the previous step.

CSS Modules: component styling

In the previous section, we saw how to declare the global styles for our application. In this section, we’ll see how to use CSS modules to enable per component SCSS styles to React.

In webpack.config.js we declared a rule for SCSS processing and the configuration for css-loader. To enable CSS modules we declared css-loader with several options: modules: true and localIdentName which configures the way class names will be extended. What we are doing here is basically enabling the css modular approach and appending a hash to classes defined in each file.

To show how this works we are going to create two components (Button and FancyButton), both of them having the same code and style class names, but that will render differently thanks to the modular approach.

1src
2├─┬ button
3| ├── button.jsx
4| └── button.scss
5└─┬ fancy-button
6  ├── fancy-button.jsx
7  └── fancy-button.scss

For each component we are going to add a jsx file with the component definition:

1import React, {Component} from 'react';
2import styles from './button.scss'
3
4class Button extends Component {
5
6  render() {
7    return (
8        <button className={styles.button}>{this.props.label}</button>
9    );
10  }
11}
12
13export default Button;

Both buttons have the same code, the only difference is the class name. In order to reference the class name from the component SCSS we will use {styles.button}, where styles is the reference to the SCSS file and button is the name of the class defined within this file.

We will also add an SCSS file with the styles for each button component:

1@import '../styles/partials/variables';
2
3.button {
4  /* ... */
5}

Again, for both components, the structure and class names are the same for both buttons, only difference are the inner style definitions.

Finally, we add both buttons to our App component:

1import React, {Component, Fragment} from 'react';
2import Button from "./button/button";
3import styles from './styles/main.scss';
4import FancyButton from "./fancy-button/fancy-button";
5
6class App extends Component {
7  render() {
8    return (
9      <Fragment>
10        <Button label="Regular Button"/>
11        <FancyButton label="Fancy Button"/>
12      </Fragment>
13    );
14  }
15}
16
17export default App;

When the page is rendered we can see that although both components share the same class name, each of them is rendered with the styles defined in its own SCSS file.

A screenshot of the rendered ReactJS buttons
A screenshot of the rendered ReactJS buttons

If we inspect the class names for each button, both will have the same class name (button) but with a different suffix added by the css-loader:

A screenshot of the Developer Tools (DevTools) inspection of the rendered ReactJS buttons
A screenshot of the Developer Tools (DevTools) inspection of the rendered ReactJS buttons

Conclusion

This post is a tutorial to create a basic React application with support for Sass styles, Babel, and Webpack 4. The tutorial shows how to install all dependencies and how to setup Webpack and Babel to transpile React jsx files into regular Javascript. In the last section, there are instructions to add support for Sass using global styles and per component styles using CSS modules. The post is meant as a guide to creating boiler-plate configuration whenever starting a new React project.

The full source code for this post can be found at Github.

You can also check the source code for Isotope mail client which is using these techniques for the front-end component build. And here an introductory post for the application and its features.

React webpack babel sass mn logo
React webpack babel sass mn logo
Twitter iconFacebook iconLinkedIn iconPinterest iconEmail icon

Comments in "React : Babel + Webpack + Sass boilerplate application"

  • Avatar for Sunny
    Sunny
    2018-10-19 07:03
    Thanks for this valuable article and its really fixed my problem. I was looking for solution but finally your valuable article help me to configured it.
    once again many many thanks
  • Avatar for a1
    a1
    2019-02-26 19:50
    This was really helpful and informative. Thanks from Bosnia
  • Avatar for Kir
    Kir
    2019-05-24 07:42
    WOW!!! You are the best!!! I've been searching for the solution to combine webpack + jsx + scss for two days, and only yours method works!
    THX a lot dude! ))

Post navigation
Isotope Mail Client: Introduction and featuresLinux: How to list installed RPM packages
© 2007 - 2025 Marc Nuri