supporting both CommonJS and AMD

后端 未结 6 2138
臣服心动
臣服心动 2020-11-29 18:15

Is there a way to create a javascript micro-library (a library that has no dependencies), that support all of the following module formats:

  • Asynchronous Module
相关标签:
6条回答
  • 2020-11-29 18:48

    Yes, and I owe this answer to ded and his awesome modules:

    (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 (e.g. with requireJS):

      requirejs(['mod'], function(mod) {
          mod.sayHi('Marc');
      });
      
    2. in commonJS (e.g. nodeJS):

      var mod = require('./mod');
      mod.sayHi('Marc');
      
    3. globally (e.g. in HTML):

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

    This method needs to get more publicity - if jQuery and co. started using it life would be much easier!

    0 讨论(0)
  • 2020-11-29 18:54

    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:

    (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.

    See: https://gist.github.com/Nijikokun/5192472 for a real example.

    0 讨论(0)
  • 2020-11-29 18:55

    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"

    0 讨论(0)
  • 2020-11-29 19:02

    I have solved this exact problem and managed to easily support:

    • Dojo AMD (referencing the RequireJS specs)
    • jQuery (under $/jQuery.fn.[your_library_here])
    • node.js using vanilla require('path_to.js')
    • Browser window.[your_library_here]

    It's using a combination of dependency injection and IIFE to get the job done.

    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

    0 讨论(0)
  • 2020-11-29 19:10

    This is based on Nijikokun's answer. Since RequireJS discourages the use of explicit module names this has been omitted in this version. 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;
    }
    
    0 讨论(0)
  • 2020-11-29 19:14

    uRequire, the Universal Module & Resource Converter is the tool that does exactly that.

    • It mainly converts AMD and CommonJS to UMD / AMD / CommonJS / Plain script (no AMD loader required).

    • It allows declarative exporting of modules, with a noConflict() baked in.

    • 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!

    0 讨论(0)
提交回复
热议问题