This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Chunking common modules from multiple apps with the Webpack CommonsChunkPlugin

4:11 Tools lesson by

If you have a multi-page application (as opposed to a single page app), you’re likely sharing modules between these pages. By chunking these common modules into a single common bundle, you can leverage the browser cache much more powerfully. In this lesson we’ll use webpack’s CommonsChunkPlugin to easily share common modules between apps.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

If you have a multi-page application (as opposed to a single page app), you’re likely sharing modules between these pages. By chunking these common modules into a single common bundle, you can leverage the browser cache much more powerfully. In this lesson we’ll use webpack’s CommonsChunkPlugin to easily share common modules between apps.

Avatar
Steve

I didn't follow the change you made for the vendor common chunk. Are you saying you'd have both common and vendor chunks? Then what ends up in each of those bundles? and how does supplying the chunks in the plugin definition work differently from the entries list containing the same names?

Avatar
Kent C.

Hi Steve!

Are you saying you'd have both common and vendor chunks?

Yes

What ends up in each of those bundles?

The vendor chunk has the vendor files (the files from the vendor entry as demonstrated in another video). The common chunk has common files between the other entries (as demonstrated in this video).

how does supplying the chunks in the plugin definition work differently from the entries list containing the same names?

The chunks plugin by itself will determine the common modules between all entries (or listed entries if you specify a chunks array) and place those in a separate chunk. The chunk with a name that matches an entry will just be that entry's modules and other chunks will reference that chunk to get those modules.

In reply to Steve
Avatar
Steve

Hi Kent,

Sorry I think I'm close to following you... In the other video the 'vendor' entry contained ['lodash', 'jquery'] and only those modules ended up in that common bundle. I follow that.

In this video are you saying you would you still have that same vendor entry? Because then I don't understand why the 'app' and 'animalFacts' chunks are being supplied to the vendor common plugin. I'd think without supplying any chunks (and only supplying the name) bundle.vendor.js would still only contain lodash and jquery, bundle.common.js would extract other modules common to the two apps, and the bundle.app.js and bundle.animalFacts each contain what is unique to them.

I think I'm missing something!
Thanks

In reply to Kent C.
Avatar
Kent C.

You know what Steve, I think you may be right. I think for this case you wouldn't have to list the chunks for a vendor chunk. I seem to remember @sokra telling me it may be necessary, but I don't think that it is. I'd say give it a shot! Good luck!

In reply to Steve

Here you'll see we have two applications being bundled by WebPack. The first is our todo app. The second is this AnimalFAX app. These two applications both use the helpers module. This is the animalfaxout.js file that uses a couple of the methods from the helpers module and this is the todo MVC app that also uses a couple methods from the helpers module.

Consequently, each bundle uses all of the code for the helpers module, and instead we'd like to split this helpers module into its own file so the browser only has to load and cache the code once for our entire application, rather than once for each page of our application.

For a small app like this that only shares a single module this isn't really a huge win, but as the applications grows this can make a real improvement in the performance of our application at load time.

To do this we're going to use the CommonsChunk plugin that comes with WebPack. Let's go ahead and jump into our WebPack config, and we'll require WebPack here. Now we can scroll down here, and right after module add plugins as an array, and we'll add a new webpack.ultimize.commonschunkplugin.

This will take an object where we can specify a couple of properties. We'll specify the name as common and the filename as bundle.common.js. This is literally all we have to do to make WebPack chunk our common modules together in a single file.

Now if we run the build, we'll see that WebPack manages everything for us, and we get a nice bundle.common.js file here, and that holds our helpers module. Then we have our other entries that we've specified in our WebPack config as well.

Unfortunately, we're not totally done. If we restart our server, then we're going to see that our applications are totally broken. The problem is that we get error, "webpackJsonp is not defined" in our console.

We still need to add this file as a script to the index HTML of both of the pages that reference it. So, we'll go ahead and do that here, and here.

Now if we restart our server, we'll see that both applications are now running just fine, and they're loading the same common file that we can see in our network tab, this bundle.com.js. We're taking full advantage of the browser cache for these common modules.

I wish I could say we're done, but there's still one more thing left to do. If we run our test, we're going to get that same error that we had before with the webpackJsonp is not defined. For the test we don't really care that the CommonsChunk plugin is used, so we're going to conditionally use this plugin by determining whether we're in a test environment.

If we open up our WebPack config, we'll see that it's a function that accepts an environment object that has properties on it that we can use to know what our environment currently is, and if we open up our common config where we get the WebPack configuration its passing test is true. So, we can simply conditionally load this plugin based off of ENV.test.

We can say ENV.test. If we're in test, then this will be undefined, otherwise we'll specify a new WebPack plugin, and because undefined plugins are not valid we'll have to call filter the plugins that are actually defined.

Now if we run our test again, we'll see that they pass just as they did before. It's notable that if you wish to combine this with an explicit vendor trunk strategy, you can add another CommonsChunk plugin to this plugins array with the configuration for the vendor chunk.

You'll likely be required to explicitly list the entries to use in the CommonsChunk, though. You can do this by adding a chunks property with an array of the entry names to have this plugin apply to.

In review, to chunk common files together you simply add the CommonsChunk plugin and specific a name and a filename for the chunk. Then update your index HTML files for each of your apps to utilize the new file.

Finally, you have to exclude the plugin in a test environment. That's how you chunk your common modules into a single bundled file to take full advantage of the browser cache for those modules.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?