Chisimdiri Ejinkeonye Fullstack developer.

Improve your webpack build with the DLL plugin

3 min read 1111

The Webpack logo against a white background;

As a JavaScript developer, you’ve probably had ample opportunity to come across webpack, whether it be while bundling frontend assets with React or transpiling some TypeScript Node.js code.

Most of the time you never have to interact with webpack directly. Rather, you interact with webpack indirectly as a dependency for build tools. But if you develop these build tools, or manage your own webpack configuration, this tutorial will help you improve build times.

We’ll be using the DLL plugin, which webpack promises “to drastically improve load times” in its documentation.

How does it work?

The DLL plugin creates two things:

  • A manifest.json file
  • A bundle of modules that are not frequently changed

Without the DLL plugin enabled, webpack compiles all the files in your code base regardless of whether it’s been modified. This has the effect of making compilation times longer than necessary.

But there is a way to tell webpack not to bother recompiling libraries that hardly change: for example, libraries in your node_modules folder.

This is where the DLL plugin comes in. It bundles code you specify as rarely changing (e.g., vendor libraries), and never compiles them again, drastically improving build times.

The DLL plugin does this by creating a manifest.json file. This file is used to map import requests to the bundled module. When an import request is made to a module from other bundles, webpack checks if there is an entry in the manifest.json file to that module. If so, it skips building that module.

Overview

The DLL plugin should be used for bundles of code that hardly get changed, like your vendor bundles. As such, you’ll need a separate webpack configuration file. Learn how to create vendor bundles here.

For this tutorial, we’ll use two webpack configurations. These will be named webpack.config.js and webpack.vendor.config.js.

We made a custom demo for .
No really. Click here to check it out.

webpack.config.js will be your primary configuration for non-vendor code; i.e., code that is modified often.

webpack.vendor.config.js will be used for your unchanging bundles, like libraries in node_modules.

To use the DLL Plugin, two plugins must be installed in the appropriate webpack config:

DllReferencePlugin → webpack.config.js
DllPlugin → webpack.vendor.config.js

We’ll be using webpack version 4.x, as 5.x is still in beta. However, they both share similar configurations.

Configure the DLL plugin (webpack.vendor.config.js)

The DLL plugin has the following compulsory options:

  • name: This is the name of the DLL function. It can be called anything. We will call this vendor_lib.
  • path: This is the path of the outputed manifest json file. It must be an absolute path. We will store this in a folder called “build” in the root directory. The file will be called vendor-manifest.json.

To specify the path, we shall use path.join like so:

path.join(__dirname, 'build', 'vendor-manifest.json')

In the webpack.vendor.config.js file, make sure output.library is the same as the DLL plugin name option.

Include as many entry points as you want. In this example, I’ve included some really heavy-weight libraries. Your output folder doesn’t matter while using this plugin.

So here’s how webpack.vendor.config.js looks now:

var webpack = require('webpack')
const path = require('path');
module.exports = {
    mode: 'development',
    entry: {
        vendor: ['lodash', 'react', 'angular', 'bootstrap', 'd3', 'jquery', 'highcharts', 'vue']
    },
    output: {
        filename: 'vendor.bundle.js',
        path: path.join(__dirname, 'build'),
        library: 'vendor_lib'
    },
    plugins: [
        new webpack.DllPlugin({
            name: 'vendor_lib',
            path: path.join(__dirname, 'build', 'vendor-manifest.json')
        })
    ]
}

Configure the DllReferencePlugin (webpack.config.js)

The DllReferencePlugin has two compulsory fields:

  • context: This is an absolute path to the directory containing the build folder. Leave this as __dirname for this tutorial.
  • manifest: This is an absolute path to the DLL’s manifest json file. We’ll set this to path.join(__dirname, 'build', 'vendor-manifest.json').

Here’s how your webpack.config.js should look:

const webpack = require("webpack")
var path = require("path");
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
  mode: 'development',
  entry: {
    app: ['./src/index.js']
  },
  output: {
    filename: 'main.bundle.js',
    path: path.join(__dirname, 'build')
  },
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: path.join(__dirname, 'build', 'vendor-manifest.json')
    }),
    // new BundleAnalyzerPlugin()
  ]
})

With that, we’re done setting up the DLL plugin.

Building the bundles

Generate the DLL manifest.json

You’ll first need to run webpack with the webpack.vendor.config.js configuration, which generates the vendor.manifest.json needed for webpack.config.js to work. This build could be done at the start of every development session when its configuration changes, or when the versions of the libraries in the vendor bundle change.

Add this script to your package.json file. It will create the manifest json file and the vendor bundle:

"scripts": {
    "buildVendor": "webpack --config webpack.vendor.config"
}

On subsequent code changes, you’ll only have to use webpack.config.js.

Build the main bundle

Then add a build script for the main bundle:

  "scripts": {
    "buildVendor": "webpack --config webpack.vendor.config",
    "build": "webpack --config webpack.config.js"
  }

Benchmarks

To test the plugin, I’ve instantiated a simple Vue.js app in the src/index.js file. It will import some heavy-weight dependencies:

import Vue from "vue"
import lodash from 'lodash'
import 'react'
import 'angular'
import 'bootstrap'
import 'd3'
import 'jquery'
import 'highcharts'
export default function createApp() {
  // vendor()
  const el = document.createElement("div")
  el.setAttribute("id", "app")
  document.body.appendChild(el)
  console.log("hello")
  new Vue({
    el: "#app",
    render: h => h("h1", "Hello world")
  })
}
document.addEventListener('DOMContentLoaded', () => {
  createApp()
})

To import the two bundles created by the webpack config, we need to add the following script tags to the index.html header:

<head>
  <title>Webpack DllPlugin Test</title>
  <script src="/build/vendor.bundle.js"></script>
  <script src="/build/main.bundle.js"></script>
</head>

Testing the bundles using the speed-measure-webpack-plugin gives the following benchmarks:

Specs: i5-6200U 8gb ram windows 10

With DllPlugin (Average 3 builds)
Building vendor bundle:
*3370ms

Building main bundle:
146.6ms

Without DllPlugin (Average 3 builds)
Building vendor bundle:
3312ms

Building main bundle:
3583.6ms

Assuming you only build the vendor bundle at the beginning of a coding session, and you reload say a hundred times in a session, here’s the total time you’ll spend waiting:

With DllPlugin
3370+(146.6*100) = 18030ms

Without DllPlugin
3312+(3583.6*100) = 361672ms

That’s a 95% decrease of build time! Makes for incredible productivity gains.

Conclusion

This optimization doesn’t in any way apply to your production build. It only caches the specified bundles to speed up development builds.

Check out the GitHub repo for the tutorial code.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Chisimdiri Ejinkeonye Fullstack developer.

Leave a Reply