Cum pot partaja cod între Node.js și browser-ul?

Am creat o mica aplicatie cu un client JavaScript (rula în browser-ul) și o Node.js server, care comunică folosind WebSocket.

Aș dori să vă împărtășesc codul între client și server. De abia am început cu Node.js și cunoștințele mele de modern JavaScript este un pic ruginit, pentru a spune cel mai puțin. Deci, eu sunt încă obtinerea de capul meu în jurul CommonJS necesită() funcție. Daca imi creez pachete cu ajutorul 'export' obiect, atunci eu nu văd cum am putea folosi aceeași fișiere JavaScript în browser-ul.

Vreau pentru a crea un set de metode și clase care sunt folosite la ambele capete pentru a facilita codificarea și decodificarea mesajelor, și alte oglindă sarcini. Cu toate acestea, Nodul.js/CommonJS sisteme de ambalare pare să mă împiedică crearea de fișiere JavaScript care poate fi folosit pe ambele părți.

De asemenea, am încercat, folosind JS.Class pentru a obține o mai stricte OO model, dar am renunțat pentru că nu puteam't dau seama cum de a obține condiția fișiere JavaScript pentru a lucra cu require(). Este ceva ce am pierdut pe aici?

Comentarii la întrebare (1)
Soluția

Dacă doriți să scrie un modul care poate fi folosit atât pe partea de client și partea de server, am un scurt post pe blog pe o metodă rapidă și ușoară: Scris pentru Node.js și browser-ul, în esență, următoarele (în cazul în care "asta" este la fel ca "fereastra"):

(function(exports){

    // Your code goes here

   exports.test = function(){
        return 'hello world'
    };

})(typeof exports === 'undefined'? this['mymodule']={}: exports);

Alternativ, există unele proiecte menite să pună în aplicare Node.js API pe partea de client, precum Marak's gemeni.

S-ar putea fi, de asemenea, interesat în DNode, care vă permite să vă expuneți o funcție JavaScript, astfel încât acesta poate fi numit de la un alt aparat, folosind un simplu JSON pe bază de protocol de rețea.

Comentarii (9)

Epeli are o soluție frumos aici http://epeli.github.com/piler/, care funcționează chiar și fără bibliotecă, pune-o într-un fișier numit share.js

(function(exports){

  exports.test = function(){
       return 'This is a function from shared module';
  };

}(typeof exports === 'undefined' ? this.share = {} : exports));

Pe partea de server doar folosi:

var share = require('./share.js');

share.test();

Și pe partea de client doar încărcați fișierul js și de a folosi apoi

share.test();
Comentarii (3)

Checkout jQuery codul sursă care face acest lucru în Node.js modul model, AMD modul model, și la nivel mondial în browser-ul:

(function(window){
    var jQuery = 'blah';

    if (typeof module === "object" && module && typeof module.exports === "object") {

        // Expose jQuery as module.exports in loaders that implement the Node
        // module pattern (including browserify). Do not create the global, since
        // the user will be storing it themselves locally, and globals are frowned
        // upon in the Node module world.
        module.exports = jQuery;
    }
    else {
        // Otherwise expose jQuery to the global object as usual
        window.jQuery = window.$ = jQuery;

        // Register as a named AMD module, since jQuery can be concatenated with other
        // files that may use define, but not via a proper concatenation script that
        // understands anonymous AMD modules. A named AMD is safest and most robust
        // way to register. Lowercase jquery is used because AMD module names are
        // derived from file names, and jQuery is normally delivered in a lowercase
        // file name. Do this after creating the global so that if an AMD module wants
        // to call noConflict to hide this version of jQuery, it will work.
        if (typeof define === "function" && define.amd) {
            define("jquery", [], function () { return jQuery; });
        }
    }
})(this)
Comentarii (1)

Mi-ar recomanda căutarea în RequireJS adaptor pentru Node.js. Problema este că CommonJS modulul model Node.js utilizează în mod implicit este't asincron, care blochează de încărcare în browser-ul web. RequireJS foloseste AMD model, care este atât asincron și compatibile cu atat server cat si client, atâta timp cât utilizați r.js adaptor.

Comentarii (1)

Don't uitați că șir de reprezentare a unei funcții JavaScript reprezintă codul sursă pentru această funcție. Ai putea pur și simplu scrie funcții și constructori încapsulate într-un mod, astfel încât acestea pot fi toString()'d și trimis la client.

Un alt mod de a face asta este de a utiliza un sistem construi, pune codul comun în fișiere separate, și apoi să le includă în atât de server și client script-uri. Am'm folosind această abordare pentru un simplu client/server joc prin WebSockets în cazul în care serverul și clientul ambele rula în esență, același joc buclă și client se sincronizează cu serverul la fiecare tick de a face sigur că nimeni nu's înșelăciune.

Mea de a construi sistemul de joc este un simplu Bash script care ruleaza fișierele prin C preprocessor și apoi prin sed pentru a curăța unele junk cpp lasă în urmă, așa că am putea folosi toate normală preprocesor chestii de genul #include, #define, #ifdef, etc.

Comentarii (1)

Poate că acest lucru nu este în întregime în concordanță cu întrebarea, dar am crezut că am'd împărtășească acest.

Am vrut să fac un cuplu de simplu șir de funcții de utilitate, a declarat în Șir.prototip, disponibil pentru ambele nod și browser-ul. Pur și simplu am păstra aceste funcții într-un fișier numit utilities.js (într-un subfolder) și poate cu ușurință de referință atât dintr-un script tag-ul în browser-ul meu de cod, și de a folosi necesită (omițând .js extensie) în Node.js script:

my_node_script.js

var utilities = require('./static/js/utilities')

my_browser_code.html

<script src="/static/js/utilities.js"></script>

Sper că acest lucru este informații utile pentru altcineva decât pentru mine.

Comentarii (3)

Dacă utilizați utilizați modul de susținători, cum ar fi webpack la pachet JavaScript fișiere pentru utilizare într-un browser, puteți pur și simplu reutilizarea Node.js modulul de interfață care rulează într-un browser. Cu alte cuvinte, Node.js modulul poate fi partajat între Node.js și browser-ul.

De exemplu, următorul cod sum.js:

Normal Node.js module: sum.js

const sum = (a, b) => {
    return a + b
}

module.exports = sum

Utilizați modul în Node.js

const sum = require('path-to-sum.js')
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5:  7

Reutiliza în frontend

import sum from 'path-to-sum.js'
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5:  7
Comentarii (0)

Serverul poate trimite pur și simplu JavaScript fișiere sursă pentru client (browser) dar truc este că clientul va trebui să furnizeze o mini "exporturile" mediu înainte de a putea "exec" codul și depozitați-l ca un modul.

Un mod simplu de a face un astfel de mediu este de a utiliza o închidere. De exemplu, spune că server-ul dvs. oferă o sursă de fișiere prin HTTP ca http://example.com/js/foo.js`. Browser-ul poate încărca fișierele necesare prin intermediul unui XMLHttpRequest și încărcați codul astfel:

ajaxRequest({
  method: 'GET',
  url: 'http://example.com/js/foo.js',
  onSuccess: function(xhr) {
    var pre = '(function(){var exports={};'
      , post = ';return exports;})()';
    window.fooModule = eval(pre + xhr.responseText + post);
  }
});

Cheia este faptul că clientul poate încheia cod străin într-o funcție anonim să fi rulat imediat (o închidere) care creează "exporturile" obiect și returnează astfel încât să puteți atribui în cazul în care te'd place, mai degrabă decât poluante de nume global. În acest exemplu, este repartizat la fereastră atribut fooModule care va conține codul exportate de către fișier foo.js.

Comentarii (2)

Niciuna dintre soluțiile anterioare aduce CommonJS modulul de sistem pentru browser-ul.

Așa cum am menționat în alte răspunsuri, sunt manager de active/ambalator soluții, cum ar fi Browserify sau Stive și există RPC soluții, cum ar fi dnode sau nowjs.

Dar nu puteam't găsi o punere în aplicare a CommonJS pentru browser-ul (inclusiv o necesită () funcția și de "exporturi" / `module.pentru exportul de obiecte, etc.). Așa că mi-am scris singur, doar pentru a descoperi ulterior că altcineva a scris-o mai bine decât am avut: https://github.com/weepy/brequire. L's a numit Brequire (scurt pentru Browser-ul avea nevoie).

Judecând după popularitatea, manageri de active satisfacă nevoile de majoritatea dezvoltatorilor. Cu toate acestea, dacă aveți nevoie de un browser punerea în aplicare a CommonJS, Brequire probabil va potrivi proiectul de lege.

2015 Actualizare: eu nu mai folosesc Brequire (n't a fost actualizat în câțiva ani). Dacă am'm a scris doar un mic, open-source module și vreau ca cineva să fie capabil de a utiliza cu ușurință, apoi m-am'll urmează un model similar cu Caolan's a răspunde (de mai sus) ... am scris un post pe blog](http://csnw.github.io/2013/06/23/this-in-node-modules-and-iifes.html) despre un cuplu de ani în urmă.

Cu toate acestea, dacă am'm scris module pentru uz personal sau pentru o comunitate care este standardizat pe CommonJS (ca Ampersand comunitar) apoi am'll doar scrie-le în CommonJS format și de a folosi Browserify.

Comentarii (0)

now.js este, de asemenea, în valoare de o privire. Acesta vă permite să apelați server-side de la partea de client și client-side funcții de server-side

Comentarii (3)

Scrie codul ca RequireJS module și teste cu Jasmine teste.

În acest fel codul poate fi încărcat pretutindeni cu RequireJS și testele fi rula în browser-ul cu jasmine-html și cu jasmine-nod în Node.js fără a fi nevoie de a modifica codul sau teste.

Aici este un exemplu de lucru]4 pentru acest lucru.

Comentarii (0)

Dacă vrei să scrii în browser-ul dvs. în Nod.js-ca stil, puteți încerca dualify.

Nu există nici un browser codul de compilare, astfel încât să puteți scrie cererea dumneavoastră, fără limitări.

Comentarii (0)

Caz de utilizare: partajați aplicația de configurare între Node.js și browser-ul (ăsta e doar un exemplu, probabil nu cea mai bună abordare în funcție de aplicație).

Problemă: nu puteți utiliza "fereastra" (nu există în Node.js) nici "global" (nu există în browser-ul).

Soluție:

  • Fișier config.js:

var config = { foo: 'bar' }; if (typeof module === 'obiect') a modulului.exporturile = config;

  • In browser-ul (index.html):
<script src="config.js"></script> <script src="myApp.js"></script>

Acum puteți deschide dev tools și accesează variabila globală "config"

  • În Node.js (app.js):

const config = necesită('./config'); console.log(config.foo); // Afișează 'bar'

  • Cu Babel sau mașina de Scris:

import config din './config'; console.log(config.foo); // Afișează 'bar'

Comentarii (3)

Am scris un modul simplu, care pot fi importate (fie folosind necesită în Nod, sau tag-uri script în browser-ul), pe care le puteți folosi pentru a încărca module, atât de la client și de server.

Exemplu de utilizare

1. Definirea modulului

Loc următorul text într-un fișier, log2.js, în interiorul web statice fișiere folder:

let exports = {};

exports.log2 = function(x) {
    if ( (typeof stdlib) !== 'undefined' )
        return stdlib.math.log(x) / stdlib.math.log(2);

    return Math.log(x) / Math.log(2);
};

return exports;

Simplu ca asta!

2. Folosind modulul

Deoarece este un bilaterale module loader, putem încărcați-l din ambele părți (client și server). Prin urmare, puteți face următoarele, dar nu't nevoie pentru a face ambele simultan (să nu mai vorbim într-o anumită ordine):

  • În Nod

În Nod, l's simplu:

var loader = require('./mloader.js');
loader.setRoot('./web');

var logModule = loader.importModuleSync('log2.js');
console.log(logModule.log2(4));

Acest lucru ar trebui să se întoarcă 2.

Dacă fișierul dvs. este't în Nodul's directorul curent, asigurați-vă că pentru a apela `loader.setRoot cu calea la web statice fișiere folder (sau oriunde module).

  • În browser-ul:

În primul rând, pentru a defini pagina de web:


    <header>
        <meta charset="utf-8" />
        Module Loader Availability Test

        <script src="mloader.js"></script>
    </header>


        <h1>Result</h1>
        <p id="result"><span style="color: #000088">Testing...</span></p>

        <script>
            let mod = loader.importModuleSync('./log2.js', 'log2');

            if ( mod.log2(8) === 3 && loader.importModuleSync('./log2.js', 'log2') === mod )
                document.getElementById('result').innerHTML = "Your browser supports bilateral modules!";

            else
                document.getElementById('result').innerHTML = "Your browser doesn't support bilateral modules.";
        </script>

Asigurați-vă că don't deschide fișierul direct în browser-ul dumneavoastră; când se folosește AJAX, vă sugerez să luați o privire la Python 3's http.server module (sau oricare ar fi super, linia de comandă, director web server soluție de implementare este) în loc.

Dacă totul merge bine, aceasta va apărea:

Comentarii (0)

Am scris acest lucru, este simplu de utilizat, dacă doriți să setați toate variabilele globale domeniul de aplicare:

(function(vars, global) {
    for (var i in vars) global[i] = vars[i];
})({
    abc: function() {
        ...
    },
    xyz: function() {
        ...
    }
}, typeof exports === "undefined" ? this : exports);
Comentarii (0)