Sharing a Webpack vendor bundle across applications

If you find yourself maintaining standalone, yet related SPAs, and you would like your users to benefit from their browser's cache to download some third-party code they have in common only once, Webpack has you (pretty much) covered thanks to its DllPlugin, which is actually part of a duet along with DllReferencePlugin. To make a long story short, the former allows you to generate, through a separate build, a standalone bundle and an accompanying manifest file, whereas the latter takes these two as input and in consideration in the context of a full, regular build. Let's get started!

We will assume one of the apps will bear responsibility for building the common bundle. As I mentioned earlier, this implies creating a separate, specific Webpack config:

const webpack = require("webpack");
const path = require("path");

module.exports = {
entry: {
commonVendors: [/* list the names of your common dependencies here */]
},

output: {
path: path.join(__dirname, "vendor"),
filename: "[name].js",
publicPath: "/",
library: "Vendor"
},

plugins: [
new webpack.DllPlugin({
context: __dirname,
path: path.join(__dirname, "vendor", "manifest.json")
})
]
};

You might need extra stuff, like setting up loaders to support your framework's DSL, if any - I will leave that up to you. Let's build!

$ webpack --config path/to/specific/config.js

This should result in the creation of a vendor folder, containing commonVendors.js and manifest.json files. Now, on to our main config:

const webpack = require("webpack");

module.exports = {
// ...

plugins: [
// ...

new webpack.DllReferencePlugin({
context: __dirname,
manifest: require("./vendor/manifest.json"),
name: "Vendor" // this has to match output.library in the specific config
})
]
};

If you run your build as usual (and you ran the first one already), you should notice a decrease in your regular bundles' size! Of course, make sure to add a <script src="path/to/vendor/commonVendors.js"></script> tag to your HTML page.

OK, so we now have a separate bundle that we can use in this one application. How should we proceed to benefit from it in another build? Well, that is really up to you and your concrete use case: there is, to my knowledge, no perfect solution given it will always imply build coupling. Feel free to drop your knowledge in a comment below!

Just as a proof of concept, let's have it working in development though: have commonVendors.js and manifest.json available through a local server or, like me, just rely on the filesystem, and in your second app's Webpack config, make use of DllReferencePlugin as well:

const webpack = require("webpack");

module.exports = {
// ...

plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require("../path/to/manifest.json"),
name: "Vendor"
})
]
};

Once again, you should see your JavaScript footprint decrease, and no lack of code if you correctly import the common bundle file in your app!