最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to write an AMD module for use in pages without RequireJS? - Stack Overflow

programmeradmin2浏览0评论

I need to re-structure an existing AMD module to make it both usable by pages with/without RequireJS presented. How should I do it, and is there any example code? Preferably, it would be a way without polluting the global namespace, though not a strict requirement.

I need to re-structure an existing AMD module to make it both usable by pages with/without RequireJS presented. How should I do it, and is there any example code? Preferably, it would be a way without polluting the global namespace, though not a strict requirement.

Share Improve this question asked Sep 24, 2012 at 3:31 gskleegsklee 4,9444 gold badges40 silver badges56 bronze badges 2
  • Why would you do this? How much of a hassle is including RequireJS or building 2 versions of your script, one for RequireJS and another standalone? – Joseph Commented Sep 24, 2012 at 3:52
  • github.com/gfranko/amdclean – user985399 Commented Aug 12, 2019 at 0:13
Add a comment  | 

6 Answers 6

Reset to default 8

This is not a bad idea at all, quite often JS libs are required to support a AMD/non AMD environment. Here is one variation of the solution:

!function (name, definition) {
    if (typeof module != 'undefined') module.exports = definition()
    else if (typeof define == 'function' && define.amd) define(name, definition)
    else this[name] = definition()
}('reqwest', function () {

    // Module here

});

The only downside is you can't request other dependencies, so this would only be useful in stand alone libraries, like the ones below

  • Dustin Diaz's Reqwest
  • Mustache

I recently wrote a gist regarding this topic so I have copied the relevant bits for you below; however, feel free to check out the original Gist for more info.

The following boilerplate allows you to write your module once and have it work in a CJS/NodeJs, AMD, or Browser Global environment.

Best Used When...

  • You are migrating from namespaced (err, globals) code to either AMD or CJS modules or both.
  • You can't yet factor out browser globals but also need to test your code via NodeJS (e.g. Mocha)

Benefits & Trade-offs

  • A single module format allowing you to target AMD, CJS/NodeJS, and legacy browser globals like window.*.
  • Allows multiple dependencies to be defined.
  • Run unit tests via CLI/NodeJS runner (e.g. Mocha).
  • Less pain while incrementally migrating to CJS/NodeJS or AMD modules.
  • You give up the Java-like namespaces (e.g. com.company.package.module) -- meh, they are a mess anyway.
  • This (UMD) isn't a standard; to be fair, neither is AMD (it's a convention with a well-defined spec).
  • Non-trivial amount of boilerplate (and Ugly).

Example

/**
 * Creates a an "AppWidget" module that imports a "SingleDependency" constructor and exposes an "AppWidget" constructor.
 * 
 * Allows you to access AppWidget as a CJS/AMD module (i.e. NodeJS or RequireJs):
 * 
 * @example
 *    var AppWidget = require('app-widget')
 * 
 * Allows you to access AppWidget as a legacy browser global:
 * 
 * @example
 *    var AppWidget = window.AppWidget
 */

!(function (name, context, definition) {
  if (typeof exports === 'object') { module.exports = definition(require); } else if (typeof define === 'function' && define.amd) { define(definition); } else { context[name] = definition(); }
}).call(this, 'AppWidget', this, function (require) {
  'use strict'

  // imports
  var SingleDependency = (typeof require === 'function') ? require('./single-dependency') : window.SingleDependency;
  var singleDependency = new SingleDependency();

  function AppWidget() {}
  AppWidget.prototype.start = function () {};

  // exports
  return AppWidget;

});

Check out UMD. You should find a pattern suitable for your purposes there. The templates are somewhat ugly but work.

I think that this is quite a bad idea.

Your possible steps that you have to take to make sure that it works:

  1. ensure that all module's dependencies are loaded on that page (jQuery, Backbone and others)
  2. include your module(s) on the page in the order you know they should be executed
  3. ensure that any module that is a dependency of another module creates a global variable with the same name the "importing" module expects and refers to in its code
  4. ensure that your module refers to the dependencies (including other modules) by the same name
  5. override/create a global method define that executes your module's factory function

And that is only a part of what you'd have to do. What about 3rd parties that you need to be AMD-compliant for your RequireJS pages (or at least be in its shim configuration), but also should be global for your non-RequireJS pages?

Simply put, IMO, it'd be easier to rework existing code into AMD version, that to make your modules non-AMD

Based on Simon Smiths answer I dealed with module dependencies:

(function (root, factory) {
    if (typeof exports === "object") {
        module.exports = factory();
    } else if (typeof define === "function" && define.amd) {
        define(['jquery', 'ol'], factory);
    } else {
        root.module_name = factory();
    }
}(this, function (_$, _ol) {
    return new function () {
        // supposed that window.ol and window.$ are defined
        var ol = goog.isDef(_ol) ? _ol : window.ol;
        var $ = goog.isDef(_$) ? _$ : window.$;
}
}));

Where goog.isDef is Google Closure function:

goog.isDef = function(val) {

  return val !== void 0;
};

Hope it will help someone.

Check out Browserify, which will create single, standalone .js file with all dependencies embedded from your AMD/JS code.

You could then ship 2 versions of your code, one for AMD users and one for "oldschool" js users.

发布评论

评论列表(0)

  1. 暂无评论