简体   繁体   English

同时支持CommonJS和AMD

[英]supporting both CommonJS and AMD

Is there a way to create a javascript micro-library (a library that has no dependencies), that support all of the following module formats: 有没有一种方法可以创建一个JavaScript微库(一个没有依赖性的库),该库支持以下所有模块格式:

  • Asynchronous Module Definition 异步模块定义
  • CommonJS 普通JS
  • exposing the library's exports as a global namespace object (no loader) 将库的导出公开为全局名称空间对象(无加载程序)

Yes, and I owe this answer to ded and his awesome modules: 是的,我将这个答案归功于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 + '!');
        }
    };
}));

This can then be used: 然后可以使用:

  1. in AMD (eg with requireJS): 在AMD中(例如,requireJS):

     requirejs(['mod'], function(mod) { mod.sayHi('Marc'); }); 
  2. in commonJS (eg nodeJS): 在commonJS(例如nodeJS)中:

     var mod = require('./mod'); mod.sayHi('Marc'); 
  3. globally (eg in HTML): 全局(例如HTML):

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

This method needs to get more publicity - if jQuery and co. 此方法需要更多宣传-如果是jQuery和co。 started using it life would be much easier! 开始使用它,生活会容易得多!

Here is a list of various cross-compatible module formats . 这是各种交叉兼容模块格式的列表

I suspect that the one you're looking for is what they're calling " commonjsStrict.js " 我怀疑您要寻找的是他们所说的“ commonjsStrict.js

uRequire , the Universal Module & Resource Converter is the tool that does exactly that. uRequire ,Universal Module&Resource Converter是实现此目的的工具。

  • It mainly converts AMD and CommonJS to UMD / AMD / CommonJS / Plain script (no AMD loader required) . 它主要将AMD和CommonJS转换UMD / AMD / CommonJS / Plain脚本(无需AMD加载程序)

  • It allows declarative exporting of modules, with a noConflict() baked in. 它允许声明式导出模块,并带有noConflict()

  • It can manipulate modules (inject/replace/remove dependencies OR code) as you build them. 在构建模块时,它可以操纵模块(注入/替换/删除依赖关系或代码)。

  • It converts from coffeescript, coco, Livescript, icedCoffeescript and you can add your own conversions in one liners! 它可以从coffeescript,coco,Livescript,icedCoffeescript进行转换,您可以将自己的转换添加到一个衬里中!

Just to update a little bit on this answer in regards to @marc I too give credit to ded and have updated it a bit to be with the latest updates: 只是为了对有关@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 || {}));

Object at the end is a reference to either the parent or the current scope, lets say you have a package you are writing and this is just a piece of the pie, well that context could be a name-spaced object and this is just a slice of that pie. 最后的对象是对父对象或当前作用域的引用,可以说您有一个正在编写的包,这只是一小部分,而上下文可能是一个以名称分隔的对象,而这仅仅是一个一块馅饼。

Also, if you wish to have dependencies, there is an optional parameter at the end after your scope which supports an array, in this case the definition parameter then can utilize each dependency as a argument. 另外,如果您希望具有依赖关系,则在作用域后的末尾有一个可选参数,该参数支持数组。在这种情况下,定义参数可以利用每个依赖关系作为参数。 Also, the dependencies listed in an array will be required inside node-js platform for your convenience sake. 另外,为方便起见,在node-js平台内部将需要数组中列出的依赖项。

See: https://gist.github.com/Nijikokun/5192472 for a real example. 有关真实示例,请参见: https//gist.github.com/Nijikokun/5192472

I have solved this exact problem and managed to easily support: 我已经解决了这个确切的问题,并设法轻松地支持:

  • Dojo AMD (referencing the RequireJS specs) Dojo AMD(参考RequireJS规格)
  • jQuery (under $/jQuery.fn.[your_library_here]) jQuery(在$ / jQuery.fn下。[your_library_here])
  • node.js using vanilla require('path_to.js') 使用香草require('path_to.js')的node.js
  • Browser window.[your_library_here] 浏览器窗口。[your_library_here]

It's using a combination of dependency injection and IIFE to get the job done. 它结合使用依赖注入和IIFE来完成工作。

See Below: 见下文:

/*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'; 
    })()
);

Public Gist available at https://gist.github.com/forbesmyester/5293746 可在https://gist.github.com/forbesmyester/5293746上找到Public Gist

This is based on Nijikokun's answer. 这是基于Nijikokun的答案。 Since RequireJS discourages the use of explicit module names this has been omitted in this version. 由于RequireJS不鼓励使用显式模块名称,因此在此版本中已将其省略。 The second argument to the loader describe the dependencies. 加载程序的第二个参数描述了依赖性。 Pass [] if you don't need to load any. 如果不需要加载任何内容,请传递[]

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM