Как написать модуль AMD для использования на страницах без RequireJS?

Мне нужно переструктурировать существующий модуль AMD, чтобы сделать его доступным для использования на страницах с/без RequjS. Как мне это сделать, и есть ли какой-нибудь примерный код? Предпочтительно, это был бы способ, не загрязняющий глобальное пространство имен, хотя и не строгое требование.

Ответ 1

Это совсем не плохая идея, довольно часто JS libs необходимы для поддержки среды AMD/non AMD. Вот один из вариантов решения:

!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

});

Единственным недостатком является то, что вы не можете запрашивать другие зависимости, поэтому это будет полезно только в автономных библиотеках, например, ниже

Ответ 2

Недавно я написал суть этой темы, поэтому я скопировал соответствующие биты ниже; однако, не стесняйтесь проверить оригинал Gist для получения дополнительной информации.

Следующий шаблонный планшет позволяет вам написать свой модуль один раз и работать в среде CJS/NodeJs, AMD или Browser Global.

Лучше всего использовать, когда...

  • Вы переходите от кода имен (err, globals) к модулям AMD или CJS или к тем и другим.
  • Вы еще не можете отфильтровать глобальные браузеры, но также необходимо протестировать свой код через NodeJS (например, Mocha)

Преимущества и компромиссы

  • Формат одного модуля, позволяющий настроить таргетинг на AMD, CJS/NodeJS и старые глобальные браузерные браузеры, такие как window.*.
  • Позволяет определять несколько зависимостей.
  • Выполнить тесты модулей с помощью CLI/NodeJS (например, Mocha).
  • Меньше боли при постепенной миграции на модули CJS/NodeJS или AMD.
  • Вы отказываетесь от Java-подобных пространств имен (например, com.company.package.module) - meh, они все равно беспорядочны.
  • Этот (UMD) не является стандартом; чтобы быть справедливым, ни AMD (это соглашение с четко определенной спецификацией).
  • Нетривиальное количество шаблона (и Ugly).

Пример

/**
 * 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;

});

Ответ 3

Отъезд UMD. Вы должны найти образец, подходящий для ваших целей. Шаблоны несколько уродливы, но работают.

Ответ 4

Я думаю, что это довольно плохая идея.

Ваши возможные шаги, которые вы должны предпринять, чтобы убедиться, что он работает:

  • убедитесь, что все зависимостей модулей загружены на эту страницу (jQuery, Backbone и другие)
  • укажите ваш модуль (модули) на странице в том порядке, в котором вы знаете, что они должны быть выполнены
  • убедитесь, что любой модуль, являющийся зависимостью другого модуля, создает глобальную переменную с тем же именем модуль "importing" ожидает и ссылается в своем коде
  • убедитесь, что ваш модуль ссылается на зависимости (включая другие модули) с тем же именем
  • переопределить/создать глобальный метод define, который выполняет функцию вашего модуля factory

И это только часть того, что вам нужно будет делать. Как насчет третьих сторон, которые должны быть совместимы с AMD для ваших страниц RequireJS (или, по крайней мере, быть в конфигурации shim), но также должны быть глобальными для ваших страниц без необходимости?

Проще говоря, IMO, было бы проще переделать существующий код в версию AMD, чтобы сделать ваши модули не-AMD

Ответ 5

Основываясь на ответе Саймона Смита, я имел дело с зависимостями модулей:

(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.$;
}
}));

Где goog.isDef есть функция Google Closure:

goog.isDef = function(val) {

  return val !== void 0;
};

Надеюсь, что это поможет кому-то.

Ответ 6

Отметьте Browserify, который создаст отдельный автономный .js файл со всеми зависимостями, встроенными в ваш код AMD/JS.

Затем вы можете отправить 2 версии кода, один для пользователей AMD, и один для пользователей "oldschool" js.