Optimizing JavaScript

As we continue working on our project and add more code to the src/index.js file, it's very common to end up with some code that is no longer needed. In larger projects, this can lead to bloated codebases. However, when using webpack, it intelligently analyzes our code and identifies any unused functions, variables, or other artifacts. It then eliminates this unused code during the bundling process, ensuring that it is not included in the final output.

Let's put it to the test by introducing a multiply function and a foo variable in our src/index.js file, and then running webpack again. This will allow us to see how webpack handles the unused code and excludes it from the final bundle.

import './index.css'

const form = document.getElementById('add-form')
const output = document.getElementById('result')

const foo = 'bar'

function multiply(nums) {
  const result = nums.reduce((acc, num) => acc * num, 1)
  return result
}

function sum(nums) {
  const result = nums.reduce((acc, num) => acc + num, 0)
  return result
}

form.addEventListener('submit', (e) => {
  e.preventDefault()
  const { first, second } = e.target.elements
  const result = sum([+first.value, +second.value])
  output.innerText = `Total = ${result}`
})

During the bundling process, webpack analyzes the code and determines that only the sum() functions is actually used. Upon inspecting the dist/main.js file, you will notice that it no longer contains the multiply function and the foo variable. These unused code snippets have been effectively removed by webpack during the bundling process, resulting in a more optimized and concise output file.

By eliminating the unused code, webpack significantly reduces the size of the bundle, resulting in faster loading times and improved performance. This ensures that only the necessary code is delivered to the browser, optimizing the user experience.

Optimizing CSS

We have observed how webpack optimizes our JavaScript file, but what about CSS? Let's introduce an unused class in our src/index.css file and see if webpack can successfully tree shake it during the bundling process.

/* <https://www.swyx.io/css-100-bytes> */

html {
  max-width: 70ch;
  padding: 3em 1em;
  margin: auto;
  line-height: 1.75;
  font-size: 1.25em;
}

.font-bold {
  font-weight: 700;
}

Upon running the build again and examining the dist/index.css file, we can observe that the font-bold class is still present in our bundled CSS, despite not being used in our project. The reason why webpack hasn't tree shaken our unused CSS class is that tree shaking primarily focuses on eliminating unused JavaScript code. webpack's tree shaking feature is designed to analyze and remove unused JavaScript imports, functions, and variables from the bundled output. However, it does not perform the same level of analysis and optimization for CSS code.

To achieve a similar optimization for CSS, we need to utilize other plugins or tools specifically designed for CSS optimization. Fortunately, purgecss-webpack-plugin exists which solves this exact problem.

  1. Let’s begin by installing this as our development dependency:

    pnpm add -D purgecss-webpack-plugin
    
  2. Import the plugin and configure the plugin in the plugins section of your webpack configuration::

    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const { PurgeCSSPlugin } = require('purgecss-webpack-plugin')
    const TerserPlugin = require('terser-webpack-plugin')
    const path = require('path')
    
    module.exports = {
      entry: './src/index.js',
      module: {
        rules: [
          {
            test: /\\.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
          },
        ],
      },
      optimization: {
        minimizer: [new CssMinimizerPlugin(), new TerserPlugin()],
      },
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
      },
      plugins: [
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: './src/index.html',
        }),
        new MiniCssExtractPlugin({
          filename: 'index.css',
        }),
        new PurgeCSSPlugin({
          paths: ['./src/index.html'],
        }),
      ],
    }
    

    In the example above, we configure the PurgeCSSPlugin to analyze our src/index.html file and retain only the CSS classes that are actually used in this file. The plugin will then generate the optimized dist/index.css file containing only the necessary styles.

  3. Run webpack to build our project.

Upon inspecting the dist/index.css file, you'll notice that the font-bold class is no longer present. This is because the PurgeCSSPlugin has successfully eliminated the unused class, resulting in a more optimized and streamlined CSS file.

<aside> 😛 Try adding the font-bold class to one of the html element in our html file and run webpack again. This time, the font-bold class will be present in the output file.

</aside>

Resources

Introduction | PurgeCSS

Tree Shaking | webpack