Skip to content

Instantly share code, notes, and snippets.

@jaridmargolin
Last active February 11, 2024 22:47
Show Gist options
  • Save jaridmargolin/9010540 to your computer and use it in GitHub Desktop.
Save jaridmargolin/9010540 to your computer and use it in GitHub Desktop.
;(function (id, name, context, definition) {
// --------------------------------------------------------------------------
// Dependencies
//
// This is an attempt to make this library compatible with multiple module
// formats. Other UMD implementations do not take into account dependencies:
// Example: https://github.com/ForbesLindesay/umd/blob/master/template.js
//
// **NOTE: Named AMD modules are more suitable for libraries as it provides
// a consistent naming convention to access it by (anonymous AMD modules are
// better suited on an app level where files/paths may be changed).
// --------------------------------------------------------------------------
var deps = [];
// CommonJS
if (typeof module !== 'undefined' && module.exports) {
for (var i = 0, l = deps.length; i < l; i++) {
deps[i] = require(deps[i])
};
module.exports = definition.apply(context, deps);
// AMD
} else if (typeof define === 'function' && define.amd) {
define(id, deps, definition);
// STANDARD
} else {
context[name] = definition.apply(context, deps);
}
})('amdName', 'contextName', this, function () {
@jaridmargolin
Copy link
Author

Hey man,

Much appreciated on the timely response.

Anonymous vs Named AMD Modules

I guess I didn't quite think through all of the ramifications of setting the module ID. The key used in the paths configuration really ends up being the defacto name to reference the module :/ I'm now second guessing my original thoughts and wondering if passing the module ID solves anything....

Handling Dependencies

  • AMD: module will ultimately be called via the key passed in the paths configuration.
  • CommonJS (node): module will be called via npm module name.
  • Global (web): called via the declared global name set in the UMD wrapper.

Handling Dependencies Continued (Library naming conventions)

* Example*: backbone.customs.js (a backbone binding for a validation library I wrote)

I'm thinking attaching a .js ext to my module name is only making my life harder. A convention I started using in order to distinguish between internal libraries we are using at my current employer, First Opinion. We have a module called endpoints (written in python) and I created enpoints.js. Anyways..

  • AMD: bb-customs to call it but then I pass it to my factory as bbCustoms
  • CommonJS (node): bb-customs set to var bbCustoms
  • Global (web): bbCustoms

Now if I create a library that depends on bb-customs. I don't want to package it with the library so I exclude it in my require.js config. It is then run through AMDClean and I have yet another naming convention to deal with.

src:

define(['bb-customs'], function ('bbCustoms') {
  return {};
});

output:

var  = function (bbCustoms) {
  return {};
}(bb_customs);

Now it is being passed into my module as: bb_customs and my UMD declaration now has account for all 3:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['bb-customs'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('bb-customs'));
    } else {
        // Browser globals (root is window)
        root['libName'] = factory(root.bbCustoms);
    }
}(this, function (bb_customs) {

So I am not sure what I am expecting you to say here :D Just feels like a mess to me. Maybe if there was a way in AMDClean to specify how I want names converted (camelCase rather than using underscores?).. This way I would at least only have to deal with bb-customs and bbCustoms.

AMDClean Source

I am still trying to digest what exactly is happening here. You are passing your dependencies in as an object... then in your actual source code you are defining them as scope vars and requiring (CommonJs) or grabbing (from browser window)if necessary.

Disreagrding implementation, does your approach actually differ in what it accomplishes compared to the UMD template here?

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['b'], factory);
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory(require('b'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(root.b);
    }
}(this, function (b) {

Also, I may not be understanding the following Note:

"Note: Something to keep in mind is that not every library is AMD compatible. Because of this, you should default to your web environment (even if there is an AMD loader on the page) if there is not an expected return value for a certain module."

...Isn't this why we have the shim option?

Automating The Process

As for automating... There will be most difinetly be edge cases, and for those I can provide advanced options for correctly mapping. Over the next few days I will update this thread with an outline of the full interface and available options. Perhaps you could review so we can iron out as many details as possible before implementing.

And if you are happy with the final product, I think it could be a useful option to implement into AMDClean. Thoughts?


UPDATE:

May be a solved problem already. Have not had an opportunity to thoroughly investigate yet:
https://github.com/alexlawrence/grunt-umd

@gfranko
Copy link

gfranko commented Feb 18, 2014

I just released AMDClean 1.2.1, which added the prefixMode option. You can now have all of your modules use camelCase instead of underscores. If that's not enough, you can use the new prefixTransform function hook to customize the logic yourself.

Usually, the Require.js shim configuration will work (but there are exceptions). AMDClean depends on the escodegen library, which does not work even with the shim configuration: estools/escodegen#115 (comment)

The AMDClean approach still works (even though Escodegen does not work with Require.js), since it also checks if there is a global window.escodegen object that is declared (which there is) and a window.escodegen.generate method.

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