Search code examples
javascriptumd

UMD: is assigning to module.exports redundant?


I see JS libraries using these two different implementations. Only difference is the CommonJS line.

Are they functionally the same? Is assigning the value to module.exports not required?

/* 1: Assignment to module.exports */
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  $.fn.jqueryPlugin = function () { return true; };
}));

/* 2: Doesn't assign to module.exports */
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  $.fn.jqueryPlugin = function () { return true; };
}));

Solution

  • tl;dr It doesn't really matter, but including module.exports = ... is generally recommended.

    Longer explanation

    I believe the "better" version in the code you show is the one that does set module.exports:

    module.exports = factory(require('jquery'));
    

    However, it doesn't have to. In general, the way you use the jQuery-plugin is through the global $/jQuery variable, and in that case the module.exports = ... is not needed. The line making the jQuery-plugin work is:

    $.fn.jqueryPlugin = function () { return true; };
    

    But – in principle – you could use the plugin like this, calling it directly without going through jQuery:

    myjQueryPlugin = require('myjQueryPlugin');
    var $myElement = $('#my-element');
    myjQueryPlugin.apply($myElement, {});
    

    In that case you would need to set module.exports. Note that this does look a bit weird, so in general most people wouldn't be using your plugin like this.

    By setting module.exports you support both use cases, without losing anything.

    See also: http://blog.npmjs.org/post/112712169830/making-your-jquery-plugin-work-better-with-npm (the section Exporting the plugin as a module (optional))