Getting Started with Webpack: A Beginner’s Guide - Part 2

Rajesh PolaratiRajesh Polarati
8 min read

In the previous blog, we have seen how webpack has evolved, webpack core concepts, and installation & setup. If you didn't read the previous article, read it before reading this article. Here is the link for Part 1
In this blog, we will look into some loaders & plugins that we commonly use during development, with examples.

Difference between Webpack and Loader

Firstly, let's see the difference between Webpack and Loader.

Loaders transform the files into modules that Webpack can understand and include in the bundle. They handle different file types, like CSS, images, or modern JavaScript, and convert them so Webpack can include them in your project.

some of the loaders like Babel Loader (which transpiles modern JavaScript), CSS Loader (which handles CSS files), and File Loader (which manages file assets like images). We will go through an example.

Now what does Webpack do?🤔

Webpack puts all your files and dependencies together into one or more bundles. It uses loaders to process the files and then combines them into a final output file (like bundle.js). It also optimizes the files and handles things like splitting code into chunks.

In short, loaders process individual files, while Webpack bundles everything together and makes sure it all works as one.

Role of Plugins

We have seen the difference between loaders and Webpack; then what is the role of the plugins here? 🤔
Plugins in Webpack extend and customize its functionality beyond what loaders can do. For example-

  • Optimize Bundles: Improve performance by minimizing and compressing files.

  • Generate Files: Create additional files, like an HTML file that links to your bundles.

  • Run Custom Code: Perform custom tasks during the build process.

Commonly used loaders and plugins

Before learning about Babel loader, first we should know about Babel

What is babel?

Babel is a JavaScript compiler that converts modern JavaScript code into a version that is compatible with older browsers.

Some key features of Babel

  • Transpiling Modern JavaScript: Converts new JavaScript syntax (like arrow functions, classes, etc.) into older syntax so it can run in all browsers.

  • Polyfilling: Adds missing features to older browsers. For example, if you use Promise in your code, Babel can add code (polyfill) to make it work in older browsers that don't support itPromise.

  • Presets are collections of plugins. For example,@babel/preset-env is a preset that includes all necessary plugins to transform modern JavaScript.

  • Source Maps: This helps with debugging by mapping your transformed code back to the original source code.

Babel Loader

We have learnt about Babel and Webpack. To integrate both of them, we use babel-loader. In terms of a typical definition, Babel Loader is a tool that lets you use Babel with Webpack. It transforms modern JavaScript into an older version that can run in all browsers during the Webpack build process.

Then how to use Babel Loader in our application. let's see

How to Use Babel Loader

  • Install Babel and Babel Loader:

    First, let's install the required modules in our application. Make sure Node is installed on your system before running these commands.

      npm install --save-dev @babel/core @babel/preset-env babel-loader core-js
    
    1. @babel/core: The main engine of Babel that processes and transforms modern JavaScript code into a version compatible with older browsers.

    2. @babel/preset-env: A set of rules for Babel that automatically determines which modern JavaScript features need to be transformed based on the browsers you want to support.

    3. core-js: It is a library that provides polyfills to add support for new JavaScript features in browsers that don’t support them natively.

  • Babel configuration

    We have different options for this. We can directly give the babel configuration directly in the webpack.config.js file, or We can create a file called babel.config.js or .babelrc in our project root. For now, I will choose babel.config.js file.

      {
        "presets": [
          ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
          }]
        ]
      }
    

    Here, the useBuiltIns option tells how polyfills are added to your code.

    1. "useBuiltIns": "usage" means Babel automatically adds the necessary polyfills for the features you use in your code. It analyzes your code and includes only the polyfills that are needed, which helps to reduce the final bundle size.

    2. "corejs":3option species which version of core-js to use. core-js is a library that provides polyfills for modern JavaScript features.

If you want to add presets directly to webpack.config.js file, you can write like this:

    const path = require('path');

    module.exports = {
      mode: 'development', // or 'production'
      entry: './src/index.js',
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: [
                  ['@babel/preset-env', {
                    useBuiltIns: 'usage',
                    corejs: 3
                  }]
                ]
              }
            }
          }
        ]
      }
    };

Here,

  1. module.rules: This option sets the rules for processing files

  2. test: /\.js$/This option specifies that Babel Loader should process files ending with.js.

  3. exclude: /node_modules/This option specifies that you ignore the JavaScript files in node_modules folder to improve build performance.

  4. use: { loader: 'babel-loader'}: This option specifies that babel-loader should handle the transmission

  5. options: {}It allows the configuration of Babel options directly within Webpack.

  • Some Examples:

    1. Transpiling ES6+ Syntax to ES5 for arrow functions

      JS Input (ES6+):

       const add = (a, b) => a + b;
      

      JS output (after processing with Babel):

      Arrow functions are converted to regular function expressions for compatibility with older browsers.

       function add(a, b) {
         return a + b;
       }
      
    2. Polyfilling: New features

      for example, Array.prototype.includes

      JS Input:

       const numbers = [1, 2, 3];
       console.log(numbers.includes(2));
      

      JS output (after processing with Babel):

      Polyfills are added to support new methods (Array.prototype.includes) in environments that don’t natively support them

       require('core-js/modules/es.array.includes');
       const numbers = [1, 2, 3];
       console.log(numbers.includes(2));
      
    3. Transforming JSX (React)

      JSX Input:

       const element = <div>Hello, world!</div>;
      

      JS output (after processing with Babel):

      JSX is converted to React.createElement calls, which are compatible with the React library.

       const element = React.createElement('div', null, 'Hello, world!');
      

What is PostCSS?

We have seen what Babel does in the case of javascript; likewise, PostCSS also do the same thing in the case of CSS transformation.

PostCSS is a tool that processes your CSS using JavaScript plugins. These plugins can do various things, like add browser prefixes, minify your CSS, and enable new CSS features

Some key features of PostCSS

  • Usage of plugins: PostCSS uses plugins to perform different tasks, like adding browser prefixes or minifying CSS.
    For example: Adding Vendor Prefixes
    To add browser-specific prefixes automatically (e.g., -webkit--moz-), use the Autoprefixer plugin.
    For PostCSS configuration, we use postcss.config.js file. Add this code to the configuration file:

      module.exports = {
        plugins: [
          require('autoprefixer') 
        ]
      };
    

    CSS Input:

      .display {
        display: grid;
      }
    

    CSS output (after processing):

      .display {
        display: -ms-grid;
        display: grid;
      }
    
  • Compatibility: It helps make your CSS work in all browsers by automatically adding necessary prefixes.
    For example: To use the new CSS featuresnesting, you can use the postcss-preset-env plugin which enables modern CSS features

    Add this code to the postcss configuration file:

      module.exports = {
        plugins: [
          require('postcss-preset-env')({
            stage: 0 // Here this value enable the all modern CSS features
          })
        ]
      };
    

    CSS Input:

      .card {
        border: 1px solid black;
        .title {
          font-weight: bold;
        }
      }
    

    CSS output (after processing):

      .card {
        border: 1px solid black;
      }
      .card .title {
        font-weight: bold;
      }
    
  • Optimization: Minify your CSS to make it smaller and load faster.

    For example, to reduce the size of your CSS for production, use the cssnano plugin. In the modification process, it will remove comments, remove spaces, remove redundant code, remove unused CSS rules, etc.

    Add this code to the postcss configuration file:

      module.exports = {
        plugins: [
          require('cssnano')({
            preset: 'default'
          })
        ]
      };
    

    CSS Input:

      .card {
        border: 1px solid black;
        padding: 10px;
      }
    

    CSS output (after processing):

      .card{border:1px solid #000;padding:10px}
    

How to set up PostCSS

  • Install required packages

      npm install --save-dev postcss postcss-loader autoprefixer cssnano postcss-preset-env
    
  • Create PostCSS Configuration:

    Create a file named postcss.config.js in your project root

      module.exports = {
        plugins: [
          require('postcss-preset-env')({
            stage: 0
          }),
          require('autoprefixer'),
          require('cssnano')({
            preset: 'default',
          })
        ]
      };
    
  • Configure Webpack to use PostCSS:

      const path = require('path');
    
      module.exports = {
        mode: 'development', // or 'production'
        entry: './src/index.js',
        output: {
          filename: 'bundle.js',
          path: path.resolve(__dirname, 'dist')
        },
        module: {
          rules: [
            {
              test: /\.js$/,    //
              exclude: /node_modules/,
              use: 'babel-loader'
            },
            {
              test: /\.css$/,
              use: [
                'style-loader',
                'css-loader',
                'postcss-loader'
              ]
            }
          ]
        }
      };
    

    Let's see how all CSS loaders work together:

    1. CSS Import:

      Import CSS into the JavaScript file:

       import './styles.css';
      
    2. Processing withcss-loader:

      css-loaderprocesses the CSS file, handling @import and url() statements, and converts the CSS into a JavaScript module.

    3. PostCSS Transformation with postcss-loader:

      postcss-loaderapplies PostCSS plugins to the CSS, performing tasks such as adding vendor prefixes, enabling modern CSS features, and optimizing the CSS.

    4. Injecting into the DOM withstyle-loader:

      style-loaderinjects the processed CSS into a<style> tag in the DOM, making sure that the styles are applied to your page.

  • Like this, we have some other loaders

    1. Sass Loader (sass-loader): It compiles Sass or SCSS files into CSS.

    2. TypeScript Loader (ts-loader): It transpiles TypeScript files into JavaScript.

    3. File Loader (file-loader): It handles importing files like images and fonts. It emits the files to the output directory and returns the URL to the file.

    4. Html Loader (html-loader): It handles importing HTML files, inlining them or converting them into modules

Conclusion

From this blog, we learned about Webpack and how it helps with web development:

  1. What Webpack Does: It bundles and optimizes your code and assets for better performance

  2. Loaders: These tools preprocess different file types, like converting JavaScript with Babel or compiling Sass into CSS with examples

  3. Optimization: Webpack can make your site faster by reducing file sizes and loading only what's needed.

Why It’s Important

Understanding Webpack helps you build faster, more efficient websites and manage your code and assets effectively. It’s a must-have tool for modern web development

References

https://webpack.js.org/concepts
https://github.com/rajeshpolarati/Webpack-Example-Project

Want to dive deeper into web development topics and stay updated? Connect with me on LinkedIn and Instagram for more insights and tips. See you there!

0
Subscribe to my newsletter

Read articles from Rajesh Polarati directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rajesh Polarati
Rajesh Polarati

Full Stack Developer experienced in creating scalable web applications. Proficient in React, Express.js, Node.js, and SQL, MongoDB, Kafka, DSA. Skilled in team collaboration and passionate about building efficient, responsive solutions