1. 20
    Externalize Dependencies to be Loaded via CDN with webpack
    5m 11s

Externalize Dependencies to be Loaded via CDN with webpack

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

We can separate our custom application code from the common libraries we leverage, such as React and ReactDOM. In this lesson we'll configure webpack to treat React and ReactDOM as external dependencies. Then we'll update our HTML template to conditionally include the CDN links for those libraries for production builds.

Instructor: [00:00] Our application relies on React and ReactDOM. As it stands, webpack is going to include those libraries as part of our bundle every time we do a build. For a production build, we'd like to externalize these libraries and pull them in from a CDN instead. 

[00:14] We still want our imports inside of our bundle to work, but we want those to reference globally available versions of React and ReactDOM. We'll start with our webpack config. We're just going to do this for production, because we don't want to do this in development build. There, we'll just keep everything local. 

[00:32] We're going to add an externals key to our production webpack config, and that's going to take an object. In this object, we're going to pass it a key called react. Then it's referenced inside of our app as react. If we look here, we'll see that we're importing capital R, React from lowercase react.

[00:54] Here, we have the lowercase react key, with the capitalized React value. Then we're going to do the same thing for ReactDOM. We're going to have react-dom. That's going to have a value of ReactDOM, with capital DOM. In a string, we'll do react-dom, with the value ReactDOM. With that in place, let's save our updated configuration.

[01:22] In the terminal, we're going to do an npm run build. That's going to do a production build for us. We'll see that we have this output. webpack-bundle-analyzer saved a report, to this distBundleSizes.html. I'm going to open that. 

[01:42] When we look at this output, we'll see that our app bundle includes our source, a couple things from Node modules, but we're not going to see the React or the ReactDOM libraries. We've externalized those from our build. Now, if I take a look at the application itself, by running open dist, to my index.html file, we see that we'll get a blank page.

[02:04] If I open up the dev tools, we're going to see that we have a reference error that React is not defined. This is expected behavior because we've told webpack not to include React or ReactDOM in the bundle. It's on us to make it available globally on the page. Let's go into our index.html, under source, which is our template for our output.

[02:29] We want to add the CDN links for both React and ReactDOM, but we only want these available in a production build. We're going to keep React and ReactDOM in our bundle for development builds. We have the ability in this template, because of the way HTML webpack plugin processes this, to use variables and add some logic.

[02:50] We're actually going to use EJS style syntax to add an if statement, based on process.env.node_env. This is going to be set based on the mode in our webpack config during build time. This is all going to happen during build time, and at runtime we're just going to get static HTML on the other end.

[03:13] We're going to say if that is equal to production, we'll open a curly brace for this if. Then we have to close this tag with another percent angle bracket. Then we're going to close the if with a percent, closing curly brace, and another percent bracket. This syntax is a little weird. We don't have to use it a lot. Now we want our CDN links for React and ReactDOM to sit in here.

[03:44] I'm going to jump to the React website where they provide CDN links, and I want to grab the production links. These two script tags, click point to unpackage. You can use any CDN you want. Then we're going to drop those script tags right in there. I'll save that index.html, and then let's jump into a terminal, and we can do npm run build to do a new production build.

[04:20] Now, we can open dist index.html. This time we get our app. If we view source on this, you'll see that we have our script tags that we pulled from the CDN. If I come back to my terminal, I do an npm run dev, and if I view the source on this, we'll see that we do not have those CDN links. Our app.bundle includes React and ReactDOM in this case.

[05:03] Now, we're set up to leverage a CDN in production, but still have the convenience of everything being run locally for our development builds.

Luis Castro
Luis Castro
~ 3 years ago

What's the main benefit of doing this separation (is there a benefit?) of React and ReactDOM from the main app.bundle.js to CDNs?

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

What's the main benefit of doing this separation (is there a benefit?) of React and ReactDOM from the main app.bundle.js to CDNs?

One of the main advantages of using a CDN is reduced latency, so if you cannot, for some reason, host your main bundle on a CDN, you can at least speed up loading of some dependencies. In addition to that, if you use a commonly used CDN, you can potentially take advantage of the browser's cached copy of React and ReactDOM from other sites that are also hosting from that CDN.

Daniel St. Clair
Daniel St. Clair
~ 3 years ago

How does versioning work with this, especially if the cached copy is different? I assume it must match exactly. Also, I don't quite understand why there would be reduced latency - is this just because the CDN for popular packages like React is assumed to be faster than wherever I'm serving my bundle from, or is it because my bundle and CDN scripts can be served in parallel?

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

How does versioning work with this, especially if the cached copy is different? I assume it must match exactly. Also, I don't quite understand why there would be reduced latency - is this just because the CDN for popular packages like React is assumed to be faster than wherever I'm serving my bundle from, or is it because my bundle and CDN scripts can be served in parallel?

Yes, you would want your versions to match. In cases where SemVer is properly followed, your CDN version being a higher minor version should be fine, but going the other way would be an issue if you use new features from a recent minor in your code and serve a previous version from the CDN... your life will be much easier if you keep version synced.

The reduced latency comes from the fact that a CDN will serve files from a POP (point of presence) that is geographically closer to the requester. The reduced latency is a pure physics problem of distance. This doesn't solve other network issues like congestion and throughput limits, but it's a step in the right direction.

The added benefit of serving a popular library from a popular CDN is that you might benefit from a browser cached copy of React being on a user's machine from visiting other websites.

Naibedya
Naibedya
~ 3 years ago

Sir can this CDN approach be followed for css libraries like font-awesome and font-files as well?

Jon Saints
Jon Saints
~ 3 years ago

In your earlier video you mention "parsing time" of a bundle being the most significant factor, it seems like "parsing time" would be unaffected by this optimization and therefore not have a very significant impact on overall load time if I am understanding correctly?

Janis
Janis
~ 3 years ago

Why is Webpack supporting EJS and is it mentioned in the Webpack docs somewhere? If yes, where?

I like the feature, reminds me of Flask templates. However! I also want to know where this knowledge comes from and what is EJS and why is it supported :D

Ahmed Soliman
Ahmed Soliman
~ 3 years ago

What happens if my application in this case app.min.js loads before the cdn ? Will this add some level of inconsistency ?

Ahmed Soliman
Ahmed Soliman
~ 3 years ago

Also is there a config/workaround to add externals to the index.html template without having to add each package manually ?