поддержка как CommonJS, так и AMD

Есть ли способ создать микробиблиотеку javascript (библиотека, которая не имеет зависимостей), которая поддерживает все следующие форматы модулей:

  • Определение асинхронного модуля
  • CommonJS
  • отображение экспорта библиотеки как объекта глобального пространства имен (без загрузчика)

person slobo    schedule 02.12.2012    source источник


Ответы (6)


Вот список различных форматов кросс-совместимых модулей.

Я подозреваю, что вы ищете то, что они называют "commonjsStrict. js "

person Lee    schedule 02.12.2012
comment
UMD - лучший вариант - проверьте uRequire.org, который преобразует AMD / CommonJS в UMD (а также AMD / CommonJS / простой сценарий) - person Angelos Pikoulas; 02.10.2013

Да, и этим ответом я обязан ded и его потрясающим модулям:

(function(name, definition) {
    if (typeof module != 'undefined') module.exports = definition();
    else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
    else this[name] = definition();
}('mod', function() {
    //This is the code you would normally have inside define() or add to module.exports
    return {
        sayHi: function(name) {
            console.log('Hi ' + name + '!');
        }
    };
}));

Затем это можно использовать:

  1. в AMD (например, с requireJS):

    requirejs(['mod'], function(mod) {
        mod.sayHi('Marc');
    });
    
  2. в commonJS (например, nodeJS):

    var mod = require('./mod');
    mod.sayHi('Marc');
    
  3. глобально (например, в HTML):

    <script src="mod.js"></script>
    <script>mod.sayHi('Marc');</script>
    

Этот метод должен получить больше огласки - если jQuery и др. начал бы его использовать жизнь будет намного проще!

person Marc    schedule 25.12.2012
comment
Мне пришлось использовать define(name, [], definition); в строке 3, чтобы заставить это работать с Curl. - person jcollum; 14.02.2013
comment
Как мне добавить зависимости в модуль 'mod'? - person Dan Ramos; 21.05.2013
comment
Будет ли это работать, если у модуля есть нужная мне зависимость? Если внутри я делаю var x = require ('./x'); Я бы ожидал нормально работать в amd и node, а без загрузчика я бы хотел использовать window.x - person Hernan Rajchert; 20.07.2013
comment
Идея правильная, используйте оболочку вокруг определения модуля, чтобы обмануть загрузчик модуля. uRequire освобождает вас от необходимости писать эти оболочки для каждого из ваших модулей, что довольно болезненно. Он также имеет ряд таких шаблонов оболочек (UMD / UMDplain / AMD / nodejs) и других полезных вещей, таких как 'rootExports', noConflict() и т. Д. - person Angelos Pikoulas; 29.10.2013
comment
Отлично. Обратите внимание, что тест typeof module != undefined предназначен для тестирования commonJS, но module может быть определен как глобальный объект другими сценариями, которые можно включить (например, QUnit), таким образом предотвращая его загрузку под AMD. Поэтому я считаю, что лучше сначала поменять порядок и протестировать AMD. - person prototype; 09.02.2015

uRequire, универсальный конвертер модулей и ресурсов - это инструмент, который делает именно это.

  • В основном он конвертирует AMD и CommonJS в UMD / AMD / CommonJS / Plain script (загрузчик AMD не требуется).

  • Он позволяет декларативно экспортировать модули со встроенным noConflict().

  • Он может управлять модулями (вводить / заменять / удалять зависимости ИЛИ код) по мере их создания.

  • Он конвертирует из coffeescript, coco, Livescript, icedCoffeescript, и вы можете добавлять свои собственные преобразования в один лайнер!

person Angelos Pikoulas    schedule 02.10.2013
comment
Я не мог заставить этот инструмент работать. См. Мой другой сообщение о переполнении стека о это здесь - person sjdirect; 01.02.2016

Чтобы немного обновить этот ответ в отношении @marc, я тоже отдаю должное ded и немного обновил его, чтобы быть с последними обновлениями:

(function (name, definition, context, dependencies) {
  if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
  else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
  else { context[name] = definition(); }
})('events', function () {
  // Insert code here
  return {
    sayHi: function(name) {
      console.log('Hi ' + name + '!');
    }
  };
}, (this || {}));

Объект в конце - это ссылка либо на родительскую, либо на текущую область, допустим, у вас есть пакет, который вы пишете, и это всего лишь кусок пирога, хорошо, что контекст может быть объектом с разделением имен, и это просто кусок этого пирога.

Кроме того, если вы хотите иметь зависимости, в конце после вашей области видимости есть необязательный параметр, который поддерживает массив, в этом случае параметр определения может использовать каждую зависимость в качестве аргумента. Кроме того, зависимости, перечисленные в массиве, потребуются внутри платформы node-js для вашего удобства.

См. Реальный пример: https://gist.github.com/Nijikokun/5192472.

person Nijikokun    schedule 18.03.2013

Я решил именно эту проблему, и мне удалось легко поддержать:

  • Dojo AMD (ссылка на спецификации RequireJS)
  • jQuery (в $ / jQuery.fn. [your_library_here])
  • node.js с использованием vanilla require ('path_to.js')
  • Окно браузера. [Your_library_here]

Он использует комбинацию внедрения зависимостей и IIFE для выполнения работы.

См. ниже:

/*global jQuery:false, window:false */
// # A method of loading a basic library in AMD, Node.JS require(), jQuery and Javascript's plain old window namespace.
(function(exporterFunction) {
exporterFunction('cll',
    function(a,b) {
        return a+b;
    }
);
})(
    (function() { // Gets an exportFunction to normalize Node / Dojo / jQuery / window.*

        if ((typeof module != 'undefined') && (module.exports)) { // Node Module
            return function(library_name,what_was_exported) {
                module.exports = what_was_exported;
                return;
            };
        }
        if (typeof define != 'undefined' && define.hasOwnProperty('amd') && define.amd) { // Dojo AMD
            return function(library_name,what_was_exported) {
                define(function() {
                    return what_was_exported;
                });
            };
        }
        if (typeof jQuery === 'function') { // jQuery Plugin
            return function(library_name,source) {
                jQuery.fn[library_name] = source;
                return;
            };
        }
        if (typeof window != 'undefined') { // Fall down to attaching to window...
            return function(library_name,what_was_exported) {
                window[library_name] = what_was_exported;
            };
        }

    })(),
    (function() { 
        // ## Other Parameters Here
        // You could add parameters to the wrapping function, to include extra 
        // functionalilty which is dependant upon the environment... See 
        // https://github.com/forbesmyester/me_map_reduce for ideas.
        return 'this_could_be_more_arguments_to_the_main_function'; 
    })()
);

Общедоступный Gist доступен по адресу https://gist.github.com/forbesmyester/5293746

person Forbesmyester    schedule 02.04.2013

Это основано на ответе Нидзикокуна. Поскольку RequireJS не рекомендует использовать явные имена модулей, в этой версии это было опущено. Второй аргумент загрузчика описывает зависимости. Передайте [], если вам не нужно ничего загружать.

var loader = function(name, dependencies, definition) {
  if (typeof module === 'object' && module && module.exports) {
      dependencies = dependencies.map(require);
      module.exports = definition.apply(context, dependencies);
  } else if (typeof require === 'function') {
    define(dependencies, definition);
  } else {
    window[name] = definition();
  }
};

loader('app', ['jquery', 'moment'], function($, moment) {
   // do your thing
   return something;
}
person monken    schedule 29.05.2015