Webpack: Creating multiple bundles using entry points
Webpack is module bundler that generates static assets for almost all of your front-end dependencies, and their dependencies. It's primary use-case is for creating optimized bundles for you Javascript, but it's quickly been extended to handle everything from fonts, images, and even a compilation step for CoffeeScript, LESS, and pretty much anything else you can think of.
A common use case for Webpack is single page applications, but another large one is for multi page applications. Loading a large JavaScript bundle on every page is not ideal, so let's set up Webpack to create multiple bundles for us.
A basic setup
So let's say the front-end JavaScript/Stylesheets structure of our site looks like this:
└── static ├── dist └── src ├── js │ ├── Account.js │ └── Front.js ├── node_modules ├── package.json ├── stylesheets │ └── main.scss └── webpack.config.js
Most importantly, We have a main Javascript file for Front and Account.
The goal is to have Webpack generate a front-bundle.js
and
account-bundle.js
bundle. The advantage here is that new visitors
who aren't logged in don't need to load a huge JavaScript bundle
just for visiting the homepage.
Single Entry Point
With a goal in mind, we can dig into Webpack and see what it offers.
By default, Webpack makes you define an entry-point
, basically the
root JavaScript file for you app:
module.exports = { entry: { app: "./static/src/app.js" }, output: { path: "./static/dist", filename: "app-bundle.js" } };
Our site structure doesn't match up with that. With this, we would have to load all the account panel JavaScript on the homepage too - which is far from ideal.
Multiple Entry Points
Webpack supports multiple entry points for this reason. Here's a new configuration more suited to our site structure:
module.exports = { entry: { front: "./static/src/js/Front.js", account: "./static/src/js/Account.js" }, output: { path: "./static/dist", filename: "[name]-bundle.js" } };
Much better. What's happening here is that Webpack is now looking
for both Front.js
and Account.js
, and will create a separate
bundle, including the Webpack runtime and dependencies, for each of
those. In the output object, we export the bundle to static/dist
and use the [name]
variable to name each bundle.
We end up with /static/dist/front-bundle.js
and
/static/dist/account-bundle.js
. Great, so now we can the script
tag to each page and we're done!
Almost
Even though the bundles contain different code, there are a few libraries/modules that we use in both Front and Account. So, what about the use-case where a new user does end up logging in?
We wouldn't want to make them re-download the same JavaScript!
Common Chunks
While the solution above is good, it can be better.
Ideally, we have Front-bundle.js and Account-bundle.js - but we also have a Common-bundle.js that contains the modules we use everywhere. The browser will cache Common-bundle.js, so when a user transitions from the Front to the Account, they've already got most of what they need.
Say hi to the CommonChunksPlugin.
Configuring CommonChunksPlugin
The common chunks plugin will look for and find all common modules and dependencies between your entry points, and automatically bundle them. All we need to is a little configuration:
let commonsPlugin = new webpack.optimize.CommonsChunkPlugin( 'commons', // Just name it 'common.js' // Name of the output file // There are more options, but we don't need them yet. ); module.exports = { entry: { front: "./static/src/js/Front.js", account: "./static/src/js/Account.js" }, output: { path: "./static/dist", filename: "[name]-bundle.js" }, plugins: [ commonsPlugin ] // more config options };
We initialize a new instance of the CommonChunksPlugin
and pass
a couple parameters (annotated). After that, the Webpack will do
the rest.
The commons
bundle will also be output to static/dist/
, with
the name that we gave it (common.js
).
Wrapping Up
Now we're done! Remeber to add the <script>
for both the entry
bundle and the common bundle to the correct pages, and Webpack will
do the rest.
It's a powerful tool, and I think does a great job of cleaning up the mess that is front-end dependency management. There's an endless amount of plugins and extentions already out there, so we'll see where Webpack ends up in 6 months to a year.
:: Cody Reichert