Improve webpack build with the DllPlugin and DllReferencePlugin

  1. DllPlugin
  2. DllReferencePlugin
  3. Example

In this essay we’ll be using the DllPlugin and DllReferencePlugin in a sample project and find out how it works to “drastically improve build time performance”.

DllPlugin

This plugin is designed to optimize the build performance by pre-compiling certain libraries and frameworks into a separate bundle. It is particularly beneficial for large projects that rely heavily on stable third-party dependecies which do not change often.

The DllPlugin creates two things:

  • A manifest.json file - It contains mappings from import requests to module ids, it is used by the DllReferencePlugin.
  • A bundle of modules that are not frequently changed

Note: This plugin is used in a sperate webpack configuration file to create a dll-only-bundle.

DllReferencePlugin

This plugin is used to reference the dll-only-bundle(s) to require pre-built dependencies, and it used in the primary webpack configuration file.

Example

We are going to create a basic webpage that uses lodash and React.

package.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.24.9",
"@babel/preset-env": "^7.25.0",
"@babel/preset-react": "^7.24.7",
"babel-loader": "^9.1.3",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}

dist/index.html:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
</head>
<body>
<div id="app"></div>
<script src="main.js"></script>
</body>
</html>

scr/index.js:

1
2
3
4
5
6
7
8
9
10
11
import React from "react";
import ReactDOM from "react-dom";

import _ from "lodash";

const App = () => {
const text = _.join(["Hello", "webpack", "and", "React"], " ");
return <h1>{text}</h1>;
};

ReactDOM.render(<App />, document.getElementById("app"));

babel.config.json:

1
2
3
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

webpack.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const path = require("path");
const webpack = require("webpack");

module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
],
},
plugins: [],
};

We can run npm run build to generate main.js in the dist folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> [email protected] build
> webpack

asset main.js 205 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1010 bytes 5 modules
modules by path ./node_modules/ 673 KiB
modules by path ./node_modules/react/ 6.95 KiB
./node_modules/react/index.js 190 bytes [built] [code generated]
./node_modules/react/cjs/react.production.min.js 6.77 KiB [built] [code generated]
modules by path ./node_modules/react-dom/ 130 KiB
./node_modules/react-dom/index.js 1.33 KiB [built] [code generated]
./node_modules/react-dom/cjs/react-dom.production.min.js 129 KiB [built] [code generated]
modules by path ./node_modules/scheduler/ 4.33 KiB
./node_modules/scheduler/index.js 198 bytes [built] [code generated]
./node_modules/scheduler/cjs/scheduler.production.min.js 4.14 KiB [built] [code generated]
./node_modules/lodash/lodash.js 531 KiB [built] [code generated]
./src/index.js 334 bytes [built] [code generated]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

webpack 5.93.0 compiled with 1 warning in 2290 ms

At the point, the size of main.js is 205Kb.

Step 1. Create webpack.vendor.config.js

This configuration file is used to create the DLL bundle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const path = require("path");
const webpack = require("webpack");

module.exports = {
entry: {
vendor: ["react", "react-dom", "lodash"],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].dll.js",
library: "[name]_dll",
},
plugins: [
new webpack.DllPlugin({
name: "[name]_dll",
path: path.join(__dirname, "dist", "[name]-manifest.json"),
}),
],
};

Add the following to your package.json:

1
2
3
4
5
{
"scripts": {
"buildVendor": "webpack --config webpack.vendor.config.js"
}
}

Then run npm run buildVendor to generate the DLL bundle and the manifest file.

This will create vendor.dll.js and vendor-manifest.json in the dist directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> [email protected] buildVendor
> webpack --config webpack.vendor.config.js

asset vendor.dll.js 205 KiB [emitted] [minimized] (name: vendor) 1 related asset
runtime modules 344 bytes 2 modules
cacheable modules 673 KiB
modules by path ./node_modules/react/ 6.95 KiB
./node_modules/react/index.js 190 bytes [built] [code generated]
./node_modules/react/cjs/react.production.min.js 6.77 KiB [built] [code generated]
modules by path ./node_modules/react-dom/ 130 KiB
./node_modules/react-dom/index.js 1.33 KiB [built] [code generated]
./node_modules/react-dom/cjs/react-dom.production.min.js 129 KiB [built] [code generated]
modules by path ./node_modules/scheduler/ 4.33 KiB
./node_modules/scheduler/index.js 198 bytes [built] [code generated]
./node_modules/scheduler/cjs/scheduler.production.min.js 4.14 KiB [built] [code generated]
./node_modules/lodash/lodash.js 531 KiB [built] [code generated]
dll vendor 12 bytes [built] [code generated]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

webpack 5.93.0 compiled with 1 warning in 1682 ms

In our case, the file vendor.dll.js is created with the size of 205Kb.

Step 2: Reference the DLL in main webpack configuration

Modify the main Webpack configuration to use the DllReferencePlugin.

1
2
3
4
5
6
7
8
9
10
11
const path = require("path");
const webpack = require("webpack");

module.exports = {
// other configurations...
plugins: [
new webpack.DllReferencePlugin({
manifest: require(path.resolve(__dirname, "dist/vendor-manifest.json")),
}),
],
};

Step 3: Include the DLL bundle in HTML

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>Webpack DLL Example</title>
</head>
<body>
<script src="dist/vendor.dll.js"></script>
<script src="dist/main.js"></script>
</body>
</html>

Step 4. Generate main.js

Run npm run build to generate main.js, this will create a file without any React or lodash code in it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> [email protected] build
> webpack

asset main.js 749 bytes [emitted] [minimized] (name: main)
runtime modules 663 bytes 3 modules
built modules 502 bytes [built]
modules by path delegated ./node_modules/ 126 bytes
delegated ./node_modules/react/index.js from dll-reference vendor_dll 42 bytes [built] [code generated]
delegated ./node_modules/react-dom/index.js from dll-reference vendor_dll 42 bytes [built] [code generated]
delegated ./node_modules/lodash/lodash.js from dll-reference vendor_dll 42 bytes [built] [code generated]
./src/index.js 334 bytes [built] [code generated]
external "vendor_dll" 42 bytes [built] [code generated]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

webpack 5.93.0 compiled with 1 warning in 623 ms

We can see the size of main.js has been dramatically decreased from 205Kb to 249 bytes, also the compilation time was much shorter.