Webpack bundling UMD module

lxyyz

lxy-yz

Posted on January 10, 2022

Webpack bundling UMD module

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
    }
        ...
})
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Other resources you might find useful

💖 💪 🙅 🚩
lxyyz
lxy-yz

Posted on January 10, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related