Webpack bundling UMD module
πŸ“¦

Webpack bundling UMD module

Tags
Technology
Description
Better not have to deal with it at all
Published
Published January 9, 2022

Background

Webpack is a module bundler that supports esm, cjs, amd out of box. But if you are migrating from a legacy web app that expect global dependencies and relying on namespace instead of any module system, you might have some problem to solve.

Problem

One of the common problem you might encounter with is some of the node dependencies installed are distributed in umd format. E.g.
// Example importer import 'moment/min/locales'; // pre bundle (function (root, factory) { if ( typeof define === 'function' && define.amd ) { define([], factory(root)); } else if ( typeof exports === 'object' ) { module.exports = factory(root); } else { root.myPlugin = factory(root); } })(typeof global !== "undefined" ? global : this.window || this.global, function (root) { ... }) // post bundle (function(module) { !function(a, b) { true ? module.exports = b() : undefined } ... })
When loading the bundle into browser, module.exports = b() instead of root.myPlugin = factory(root);been loaded. The reason is UMD is meant to run directly in browser or node without extra build steps.

Solution

https://v4.webpack.js.org/loaders/script-loader/ is the most simple and naive way to go. Think it as loading the script via script tags directly. This might be the best solution if you don’t have web security concerns. The biggest downside is that it is uses eval behind the scene, and eval will be blocked by https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy.
https://webpack.js.org/loaders/imports-loader/ grants more granular control over how global dependencies can be imported. Following example tells its power.
// webpack.config use: { loader: 'imports-loader', options: { wrapper: { thisArg: 'window', args: { module: false, exports: false, define: false, }, }, }, }, }, // broken bundle (function(module) { !function(a, b) { true ? module.exports = b() : undefined } ... })() // transformed bundle (function(module, exports, define) { // same as above pre bundle, w/o the broken transformation. // thanks to the IIFE wrapper due to the webpack config. (function (root, factory) { if ( typeof define === 'function' && define.amd ) { define([], factory(root)); } else if ( typeof exports === 'object' ) { module.exports = factory(root); } else { root.myPlugin = factory(root); } })(typeof global !== "undefined" ? global : this.window || this.global, function (root) { ... }) })(false, false, false)

Other resources you might find useful