Using the Library field in Webpack to allow external Javascript in your App

If you’ve made it to this page, there’s a good chance that you’ve written a web application that is bundled with something like WebPack, and now you find yourself in the predicament of needing some external (not bundled) Javascript to interact with your app. In a normal Javascript environment, this is not a problem. All objects and variables that are accessible in the global scope can be used by whatever files that you’ve loaded into memory.

Things get a bit trickier once you begin bundling all of your files into a single bundle. Now, if you have a file from outside of your bundle trying to call anything from inside your bundle, you’ll receive an error that looks like:

Uncaught ReferenceError: validFunc is not defined

You might begin to think that you are referencing the wrong function name, or that your function is not available in the current execution context’s scope. While those may very well be additional issues that you need to address, chances are that the main issue that you are running into is that Javascript that is bundled together is not made available to external code without some additional settings being applied.

Libraries to the rescue!

Webpack comes with a feature that can be applied inside of the webpack.config.js file that specifically addresses this issue. It is designed for bundling open source libraries and allowing other files to utilize those libraries, but that same functionality can be used to target specific aspects of your application that you want to be accessible outside of your bundled code. Fortunately, setup is only a few lines of code.

In your webpack.config.js file, you’ll want to add a library field to your output object, and set it to whichever variable name you’d like to use to have your external Javascript talk with your bundle. For example:

entry: './index.js',
output: {
path: path.resolve('build'),
filename: 'bundle.js',
library: 'myApp'
},

Now, external Javascript will have a reference point inside of your bundle that it can call. However, at this point, the myApp object is empty, so we need to explicitly export some Javascript from the Javascript file that is specified as our entry for the Webpack, so that it can be called externally. In the above example, our entry point is index.js, so let’s enter the following code at the bottom of that file.

module.exports = {
testFunction: () => console.log('I am being called from an external file!')
};

That’s it! Now, if we were to call myApp.testFunction() from any code outside of our bundle, we’ll see a comment show up on our console log.

At this point, you might be asking yourself, “why wouldn’t I just bundle all of the code I need together to avoid this?” That’s a valid question. If you can, you should absolutely put all of your code into a single bundle to take advantage of the benefits that bundling provides(such as being able to provide all of your code inside a single HTTP get request). There are times where that is not practical though, and if you are working with an external API then it might not be an option at all. Take, for example, the Google Maps API, which is a script loaded from a script tag in an html file, and was the reason why I learned about Webpack’s library functionality in the first place. Here’s what the syntax for loading the google API looks like:

<script src=
"https://maps.googleapis.com/maps/api/js?libraries=places,geometry,drawing&key=<apikey>&callback=someFunction">
</script>

Notice how the script link allows you to provide a callback function as part of the URL in order for your app to know precisely when the google map API is ready to be used. This is a convenient feature, but it doesn’t play nicely with bundled code. This is an ideal example for providing an entry point inside of your bundle. All you need to do is to declare a library in your Webpack, export a function for Google Maps to call, and you are all set. I hope this example helps illuminate how this feature can be incredibly useful for specific use cases.