javascript - Hur kan jag dela kod mellan Node.js och webbläsaren?


Jag skapar en liten applikation med en JavaScript-klient (körs i webbläsaren) och en Node.js-server, som kommunicerar med WebSocket.

Jag skulle vilja dela kod mellan klienten och servern. Jag har precis börjat med Node.js och min kunskap om modern JavaScript är lite rostig, minst sagt. Så jag håller fortfarande på att förstå CommonJS require()-funktionen. Om jag skapar mina paket genom att använda 'export'-objektet, kan jag då inte se hur jag skulle kunna använda samma JavaScript-filer i webbläsaren.

Jag vill skapa ett set av metoder och klasser som används på båda sidor för att underlätta kodning och avkodning av meddelanden, och andra speglade uppgifter. Dock verkar Node.js/CommonJS-paketeringssystemen förhindra mig från att skapa JavaScript-filer som kan användas på båda sidor.

Jag försökte också använda JS.Class för att få en stramare objektorienterad modell, men jag gav upp eftersom jag inte kunde lista ut hur jag skulle få de medföljande JavaScript-filerna att fungera med require(). Är det något jag missar här?

Svar #1

Om du vill skriva ett modul som kan användas både på klientsidan och serversidan, har jag ett kort blogginlägg om en snabb och enkel metod: Writing for Node.js and the browser, i princip följande (där this är samma som window):

(function(exports){

    // Your code goes here

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

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

Alternativt finns det några projekt som syftar till att implementera Node.js API på klientsidan, såsom Maraks gemini.

Du kanske också är intresserad av DNode, som låter dig exponera en JavaScript-funktion så att den kan anropas från en annan dator med hjälp av ett enkelt nätverksprotokoll baserat på JSON.

Svar #2

Epeli har en bra lösning här http://epeli.github.com/piler/ som till och med fungerar utan biblioteket, bara lägg detta i en fil som heter share.js

(function(exports){

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

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

På serversidan använd bara:

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

share.test();

Och på klientsidan, ladda bara js-filen och använd sedan

share.test();

Svar #3

Kolla in jQuery-källkoden som gör att detta fungerar i Node.js-modulmönstret, AMD-modulmönstret och globalt i webbläsaren:

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

Svar #4

Glöm inte att strängrepresentationen av en JavaScript-funktion representerar källkoden för den funktionen. Du kan helt enkelt skriva dina funktioner och konstruktörer på ett kapslat sätt så att de kan göras till strängar med toString() och skickas till klienten.

Ett annat sätt att göra det är att använda ett byggsystem, lägga den gemensamma koden i separata filer och sedan inkludera dem i både server- och klientskript. Jag använder det tillvägagångssättet för ett enkelt klient/server-spel via WebSockets där både servern och klienten kör i princip samma spel-loop och klienten synkroniserar med servern vid varje tick för att säkerställa att ingen fuskar.

Mitt byggsystem för spelet är ett enkelt Bash-skript som kör filerna genom C-förprocessorn och sedan genom sed för att rensa upp lite skräp som cpp lämnar efter sig, så att jag kan använda all vanlig förprocessorfunktionalitet som #include, #define, #ifdef, etc.

Svar #5

Jag skulle rekommendera att titta på RequireJS-adaptern för Node.js. Problemet är att CommonJS-modulmönstret som Node.js använder som standard inte är asynkront, vilket blockerar laddning i webbläsaren. RequireJS använder AMD-mönstret, som är både asynkront och kompatibelt med både server och klient, så länge du använder r.js-adaptern.

Svar #6

Kanske är detta inte helt i linje med frågan, men jag tänkte att jag skulle dela detta.

Jag ville skapa ett par enkla stränghjälpfunktioner, deklarerade på String.prototype, tillgängliga både för Node och webbläsaren. Jag håller helt enkelt dessa funktioner i en fil som heter utilities.js (i en undermapp) och kan enkelt referera till den både från en script-tagg i min webbläsarkod och genom att använda require (utan .js-tillägget) i mitt Node.js-skript:

my_node_script.js

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

min_webbläsarkod.html

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

Jag hoppas att detta är användbar information för någon annan än mig.

Svar #7

Om du använder modulbundlare såsom webpack för att bunta JavaScript-filer för användning i en webbläsare, kan du helt enkelt återanvända din Node.js-modul för frontend som körs i en webbläsare. Med andra ord kan din Node.js-modul delas mellan Node.js och webbläsaren.

Till exempel har du följande kod sum.js:

Normal Node.js-modul: sum.js

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

module.exports = sum

Använd modulen i 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

Återanvänd det i frontend

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

Relaterade artiklar