2012-12-02 12 views
36

C'è un modo per creare un javascript micro-libreria (una libreria che ha dipendenze), che supportano tutti i seguenti formati di modulo:supporta sia CommonJS e AMD

  • asincrono del modulo Definizione
  • CommonJS
  • esponendo le esportazioni della biblioteca come un oggetto namespace globale (senza caricatore)

risposta

48

Sì, e devo questa risposta a ded ed i suoi moduli impressionante:

(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 + '!'); 
     } 
    }; 
})); 

Questo può poi essere utilizzati:

  1. a AMD (ad esempio con requireJS):

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

    var mod = require('./mod'); 
    mod.sayHi('Marc'); 
    
  3. a livello globale (ad esempio in HTML):

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

Questo metodo ha bisogno di ottenere più pubblicità - se jQuery e co. iniziato a usarlo la vita sarebbe molto più facile!

+1

ho dovuto usare 'define (nome, [ ], definizione); 'on line 3 per farlo funzionare con Curl. – jcollum

+0

Come farei per aggiungere dipendenze al modulo 'mod'? –

+2

Funzionerebbe se il modulo ha una dipendenza che voglio richiedere? Se dentro faccio var x = require ('./x'); Mi aspetterei di lavorare normalmente su amd e node, e senza un loader vorrei usare window.x –

1

solo per aggiornare un po 'su questa risposta per quanto riguarda @ Marc anche io dare credito a ded e hanno aggiornato un po' per stare con gli ultimi aggiornamenti:

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

oggetto alla fine è un riferimento al genitore o all'ambito corrente, diciamo che hai un pacchetto che stai scrivendo e questo è solo un pezzo della torta, beh quel contesto potrebbe essere un oggetto distanziato dal nome e questa è solo una fetta di quella torta .

Inoltre, se si desidera avere dipendenze, esiste un parametro facoltativo alla fine dopo l'ambito che supporta un array, in questo caso il parametro di definizione può quindi utilizzare ciascuna dipendenza come argomento. Inoltre, le dipendenze elencate in un array saranno richieste all'interno della piattaforma node-js per il tuo interesse.

Vedere: https://gist.github.com/Nijikokun/5192472 per un esempio reale.

0

ho risolto questo problema esatto ed è riuscito a supportare facilmente:

  • Dojo AMD (che fanno riferimento le specifiche RequireJS)
  • jQuery (sotto $/jQuery.fn [your_library_here].)
  • nodo .js using vanilla require ('path_to.js')
  • Finestra del browser.[Your_library_here]

E 'utilizzando una combinazione di iniezione di dipendenza e IIFE per ottenere il lavoro fatto.

vedere di seguito:

/*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 pubblici disponibili presso https://gist.github.com/forbesmyester/5293746

7

uRequire, il modulo universale & Resource Converter è lo strumento che fa esattamente questo.

  • Si principalmente converte AMD e CommonJS a UMD/AMD/CommonJS/script normale (senza AMD loader richiesto).

  • Permette esportazione dichiarativa di moduli, con un noConflict() cotto in.

  • Può manipolare moduli (iniettare/sostituire/rimuovere le dipendenze o codice) come li genera.

  • Si converte da coffeescript, coco, Livescript, icedCoffeescript e puoi aggiungere le tue conversioni in una sola unità!

+0

Non riuscivo a far funzionare questo strumento. Vedi il mio altro [post StackOverflow su di esso qui] (http://stackoverflow.com/questions/35135935/cannot-run-javascript-umd-command-line-tool-typeerror-any-is-not-a-function) – sjdirect

0

Questo è basato sulla risposta di Nijikokun. Poiché RequireJS scoraggia l'uso di nomi di moduli espliciti, questo è stato omesso in questa versione. Il secondo argomento del loader descrive le dipendenze. Passa al numero [] se non hai bisogno di caricare nessuno.

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