Exposing library globals in window object.
In previous post, I've used webpack's ProvidePlugin to simply replace any reference into pre-defined library. This is useful if you want to have a library being declared globally, without the need to use import or require keyword in every file.
This works very well, but not something I was looking for. I wanted to actually load the library into the window object, making it accessible as a global variable. The way ProvidePlugin works is just like how webpack works, it's only going to replace the reference with raw reference pointed/processed by webpack. In production mode especially, you'll probably have your variables obfuscated because of the minifier and other process.
So, we need another plan.
And that's by using expose-loader module.
Quoting the description from the GitHub repository "The expose-loader loader allows to expose a module (in whole or in part) to global object (self, window and global)." Make sure to install the npm package first using npm or yarn.
// npm user npm install expose-loader --save-dev // yarn user yarn add expose-loader -D
It goes as simply as making a library/module available to access in the said global objects. Let's just go with example.
Suppose you have jQuery npm module installed, and you want to expose jQuery in the global objects without importing them using <script> tag (or import keyword), so you can just go using it in the browser console by using "$" variable.
To do that, assuming you've known a little about webpack configuration file (webpack.config.js), add a new rule inside the module like this.
module.exports = { module: { rules: [ { test: require.resolve("jquery"), loader: "expose-loader", options: { exposes: "$", }, }, ] } }
Assuming everything works well, you should be having "$" variable accessible from the console window.
Now, how to do that in Next.js? Simple!
Like in previous post, you can go to next.config.js, and instead of pushing to plugins, you're pushing to the rules inside the module. In below code, I'm exposing highlight.js under hljs variable to be used with Quill.js and doing the highlighting task on the /posts/ pages.
module.exports = { webpack: (config, { webpack }) => { config.module.rules.push({ test: require.resolve('highlight.js'), loader: 'expose-loader', options: { exposes: 'hljs', }, return config; }, };
Now, this should've been working, but we're missing one extra step. In Next.js, the module will only be exposed if you explicitly call the library for usage inside your React component. So, let's say that I have Next.js page stored in /posts/page1.tsx, inside this tsx file, go and import highlight.js.
// page1.tsx import React from 'react'; // a bunch of other imports import 'highlight.js'; ...
And you'll now have your library exposed. Once the library has loaded, it will persist until you closed your tab, so don't abuse this too much.
webpack works as bundler while also obfuscate some stuffs, and full of magical stuff. The need to load external library that exposes global variable can now be done by webpack using expose-loader loader.
Although this is a cool stuff, it's still preferred to load them from CDN if possible. Bundling more code means adding more data to process and transfer, which adds more weight to your server.
Until next time, see ya!
Back to Home