Skip to content

Instantly share code, notes, and snippets.

@ifandelse
Last active December 11, 2015 14:59
Show Gist options
  • Save ifandelse/4617996 to your computer and use it in GitHub Desktop.
Save ifandelse/4617996 to your computer and use it in GitHub Desktop.
UMD boilerplate to handle AMD, Commonjs, and standard browser js
// Example UMD wrapper for a module that takes dependencies on underscore and postal.js
(function ( root, factory ) {
if ( typeof module === "object" && module.exports ) {
// Node, or CommonJS-Like environments
// Intentionally returning a factory method
module.exports = function( _, postal ) {
return factory( _, postal );
}
} else if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define( ["underscore", "postal"], function ( _, postal ) {
return factory( _, postal, root );
} );
} else {
// Browser globals
factory( root._, root.postal, root );
}
}( typeof global !== "undefined" ? global : this.window || this.global, function ( _, postal, global, undefined ) {
// module code here....
});
@ifandelse
Copy link
Author

The main concern for me: is there a better way to handle line 17 (typeof window, etc.). The issue is that in some environments, this is the document, not window (I've seen this happen when using this wrapper in libs that are pulled into jsfiddle, for example - but believe it's due to an error...researching that). Also, someone recently opened an issue on the postal.js repo because they are running into it in Chrome in their app. It only happens in a non-amd, non-commonjs scenario.

UPDATE: haven't had time to research in depth yet, but @dcneiner mentioned that using this UMD in an AMD scenario, but not shimming a non-AMD lib will cause the dep to be undefined in the factory function. I'm trying to find out which of my projects ran into the this === document issue, so I can repro it.

@unscriptable
Copy link

If I am reading this correctly, in node-like environments this code will export a function that will execute the factory. That doesn't seem right to me. Shouldn't module.exports be assigned to the result of the factory? I forked this to try a variation....

@unscriptable
Copy link

Oops. just saw your comment that you're intentionally returning a factory. That's interesting. Why are you doing that?

@unscriptable
Copy link

I've never seen this === document. That's strange, and if jsfiddle is doing that, then they should expect problems. :)

typeof window !== 'undefined' ? window : this

This will result in exports in node.js. That's probably not what you want, I'm guessing. If you want the global object in node.js, you need to sniff for it, unfortunately. The following short expression will work in "normal" browser environments and ringojs. This might solve the this === document scenario, too.

this && this.window || this.global

Too bad that won't work in node. The following will, though:

typeof global !== "undefined" && global

What if we just combined these? Hmmm, if this isn't defined, there are bigger problems, so maybe just assume it is?

// look for node-like, browser-like, then ringo
typeof global !== "undefined" ? global : this.window || this.global

What do you think of that? I kinda like it and might start using it now. :)

@ifandelse
Copy link
Author

@unscriptable - seriously, man, you are my code hero. First, to answer your question: I'm opting for the factory in node because I often have situations where I want the same instance of a dependency to be passed in to multiple factories. postal is good example, as the add-ons for it need to target the same instance. It's one of the nice by-nature-of-design aspects of AMD, IMO - singletons are easy. I wish node had that capability built in. If you think of something I'm missing here, let me know.

I like your idea a lot - makes tons of sense. Not sure why this.window didn't occur to me! smacks forehead. I updated the gist to reflect your input....

@unscriptable
Copy link

Yah, I almost slapped my own forehead when I realized this.window finds window when this == window or document == window. Kinda neat.

It's still unclear to me why you need to export a factory for node in order to support singletons. Maybe I just haven't played with node enough to know why singletons can be a problem. Is this why? Interesting. So how is that factory called? How do you get the "true singletons" into that factory? (Sorry if I'm being too curious for you. :) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment