Webpack-prebundle-plugin is a Webpack plugin for fast prebundling with esbuild. Prebunding vendors and common code can lower the number of modules Webpack need to build and boost build speed.
Webpack-prebundle-plugin use external internally and is a more simple and fast replacement for DLLPlugin. ESbuild can bundle thousands of modules in a few seconds so you don't need to build the DLL bundle in advance(Or commit the bundle in Git repo). The plugin prebundles right before the Webpack build start. Brings seamlessly developer experience.
The usage is three simple steps:
Step1: Install package:
yarn add webpack-prebundle-plugin
Step2: Init plugin in Webpack config:
const webpackPrebundlePlugin = require("webpack-prebundle-plugin")
const path = require("path")
module.exports = {
plugins: [
new webpackPrebundlePlugin({
vendors: {
entries: ['react', 'react-dom', 'antd'],
output: path.resolve(__dirname, "../public/vendors.js")
},
})
]
}
Step3: Add vendors script tag in HTML(public/index.html in CRA template for example):
<head>
<title>React App</title>
<script src="%PUBLIC_URL%/vendors.js"></script>
</head>
Then you are done! Enjoy the build performance boost.
Example of webpack-prebundle-plugin with react/@redux/toolkit/antd
{
vendors: {
entries: ['react', 'react-dom', 'antd'], // vendors entries, similar to entries in webpack
output: path.resolve(__dirname, "../public/vendors.js"), // output file's path
esbuildOptions: {
// extra esbuildOptions, doc: https://esbuild.github.io/api/#simple-options
}
},
}
{
commons: [
// a common code bundle
{
entry: path.resolve(__dirname, '../src/services/index.ts'), // common code entry file path
output: path.resolve(__dirname, '../src/prebuilt/services/index.js'), // output file's path
watch: true, // config watch mode, pass in true will watch on entries, you can pass in arrays of paths to force wath specific paths like watch: [path.resolve(__dirname, './foo')]
esbuildOptions: {
external: ['src/utils/Url'],
// extra esbuildOptions, doc: https://esbuild.github.io/api/#simple-options
},
},
}
watch options is passed to chokidar. Please Reference chokidar watch paths config for more advanced watch option.
View complete option schema in Schema.json
Webpack runs faster when it builds less modules. We can make Webpack build faster by reduce the number of modules, like externalize all dependencies from node_modules or prebundle vendors code with DLLPLugin. But both external and DLLPlugin have some inconveniences. External requires modify HTML template when upgrade dependency version. DLLPlugin need to rebuild every time when dependency change. And we need to commit JS files built with DLLPlugin to Git repo, which require more disk space.
Compare with External method, DLLPlugin is better for large-scale Web apps that use hundreds of deps. Not all deps are UMD bundled and can be externalized. So DLLPlugin is kind of a universal solution for externalize modules. The way DLLPlugin works, is bundling less frequently changed code ahead of time. That's what prebundle means. DLLPlugin works fine, but it has the defect metioned above.
As the raise of front-end tooling written with compile-to-native language. We can integrate tool like esbuild with Webpack for pre-bundling. ESbuild bundle is so fast that we can build vendors on the fly right before webpack build starts.
This plugin integrate esbuild into Webpack compile flow, and allow user to pre-bundle two categories of files.
1. vendors
Files in node_modules are basicly immutable. So we assume these files will not change during the build. Pre-bunding vendors code will drastically improve build speed becase the number of files in node_modules in huge.
2. commons
We may have some auto-generated files in project, like Pont code(api request code generated from swagger api definition). Or we may have large amount of common util code like i18n. These files will not change that frequently.
We can pre-bundle commons codes as well, and webpack-prebundle-plugin provide watch mode for common code. common bundle will be rebuild when watch path has file change event.
This plugin use Webpack externals internally, so theoretically it will work fine in production. You need to define process.env.NODE_ENV
with '"production"'
in vendors.esbuildOptions.define
to get minified prod version of your deps. And set minify to true. Example:
{
vendors: {
esbuildOptions: {
minify: true,
define: "process.env.NODE_ENV": '"production"',
}
}
}
Since esbuild support ES module standard in a more strict way, unlike Webpack, which has build-in polyfill for nodejs core modules(Webpack 4) and backward compatible with many historical design. Some module may have issue built with esbuild but works fine under Webpack. The issue varies. To solve this, get to know why that module is not a standard es module, and search for esbuild doc and github issue for help.
You can tweak esbuild options in vendors.esbuildOptions
and commons.esbuildOptions
.
Or you can use DLLPlugin with Webpack-prebundle-plugin all together. Let DLLPlugin deal with module that has es module compatibility issue.