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.
The DLL plugin creates two things:
manifest.json
fileWithout 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.
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
.
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.
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') }) ] }
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.
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
.
Then add a build script for the main bundle:
"scripts": { "buildVendor": "webpack --config webpack.vendor.config", "build": "webpack --config webpack.config.js" }
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.
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.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]