javascript - Hogyan tudom megosztani a kódot a Node.js és a böngésző között?
Készítek egy kis alkalmazást egy JavaScript klienssel (ami a böngészőben fut) és egy Node.js szerverrel, amelyek WebSocket segítségével kommunikálnak.
Szeretném megosztani a kódot a kliens és a szerver között. Épp most kezdtem el a Node.js-t, és modern JavaScript ismereteim - enyhén szólva - kissé rozsdásak. Szóval még mindig próbálom átlátni a CommonJS require() függvényt. Ha a csomagjaimat az 'export' objektum használatával hozom létre, akkor nem látom, hogyan tudnám ugyanazokat a JavaScript fájlokat a böngészőben is használni.
Szeretnék létrehozni egy készletnyi metódust és osztályt, amelyeket mindkét oldalon használnak az üzenetek kódolásának és dekódolásának, valamint más tükrözött feladatok megkönnyítésére. Azonban a Node.js/CommonJS csomagolási rendszerek úgy tűnik, hogy megakadályozzák, hogy JavaScript fájlokat hozzak létre, amelyeket mindkét oldalon lehetne használni.
Megpróbáltam a JS.Class-t is használni egy szorosabb objektumorientált modell kialakításához, de feladtam, mert nem tudtam rájönni, hogyan lehet a mellékelt JavaScript fájlokat működésre bírni a require() segítségével. Van valami, amit kihagytam itt?
Válasz #1
Ha szeretnél írni egy modult, amit mind kliens oldalon, mind szerver oldalon lehet használni, van egy rövid blogbejegyzésem egy gyors és egyszerű módszerről: Írás Node.js-hez és a böngészőhöz, lényegében a következő (ahol a this ugyanaz, mint a window):
(function(exports){
// Your code goes here
exports.test = function(){
return 'hello world'
};
})(typeof exports === 'undefined'? this['mymodule']={}: exports);
Alternatívaként léteznek olyan projektek is, amelyek a Node.js API-t a kliens oldalon kívánják megvalósítani, mint például Marak gemini projektje.
Érdekelhet még a DNode is, amely lehetővé teszi, hogy egy JavaScript-függvényt kiteszel, így az egy másik gépről egyszerű, JSON-alapú hálózati protokollt használva meghívható.
Válasz #2
Epelinek van itt egy jó megoldása http://epeli.github.com/piler/, ami még a könyvtár nélkül is működik, csak tedd ezt egy share.js nevű fájlba
(function(exports){
exports.test = function(){
return 'This is a function from shared module';
};
}(typeof exports === 'undefined' ? this.share = {} : exports));
A szerver oldalon egyszerűen használd:
var share = require('./share.js');
share.test();
És a kliens oldalon csak töltsd be a js fájlt, majd használd
share.test();
Válasz #3
Tekintse meg a jQuery forráskódját, amely lehetővé teszi ezt a működést a Node.js modulmintában, az AMD modulmintában és a böngésző globális környezetében:
(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)
Válasz #4
Ne feledd, hogy egy JavaScript függvény string reprezentációja a függvény forráskódját jelenti. Egyszerűen írhatnád a függvényeidet és konstruktoraidat kapszulázott módon, így azok toString() segítségével lekérhetők és elküldhetők a kliensnek.
Egy másik módja annak, hogy ezt megtegyük, az, hogy használunk egy build rendszert, a közös kódot külön fájlokba tesszük, majd mindkettőbe, a szerver és a kliens szkriptekbe is beillesztjük. Én ezt a megközelítést használom egy egyszerű kliens/szerver játékhoz WebSocketeken keresztül, ahol a szerver és a kliens lényegében ugyanazt a játékhurokot futtatja, és a kliens minden ütemben szinkronizál a szerverrel, hogy megbizonyosodjon arról, hogy senki sem csal.
A játékomhoz használt build rendszer egy egyszerű Bash script, ami átfuttatja a fájlokat a C preprocesszoron, majd a sed-en, hogy eltakarítsa a cpp után maradt szemétmaradékot, így minden normál preprocesszoros dolgot használhatok, mint például #include, #define, #ifdef stb.
Válasz #5
Azt javasolnám, hogy nézzen utána a RequireJS adapternek a Node.js-hez. A probléma az, hogy a Node.js által alapértelmezés szerint használt CommonJS modulminta nem aszinkron, ami blokkolja a betöltést a web böngészőben. A RequireJS az AMD mintát használja, amely egyszerre aszinkron és kompatibilis mind a szerverrel, mind a klienssel, amennyiben a r.js adaptert használja.
Válasz #6
Lehet, hogy ez nem teljesen felel meg a kérdésnek, de gondoltam, megosztom ezt.
Szerettem volna néhány egyszerű karakterlánc segédfüggvényt létrehozni, amelyek a String.prototype-on vannak deklarálva, és mind a node, mind a böngésző számára elérhetők legyenek. Egyszerűen ezek a függvények egy utilities.js nevű fájlban vannak, egy almappában, és könnyedén hivatkozhatok rájuk mind a böngészőbeli script-tagből, mind a Node.js szkriptben a require használatával (a .js kiterjesztés elhagyásával):
my_node_script.js
var utilities = require('./static/js/utilities')
my_browser_code.html
<script src="/static/js/utilities.js"></script>
Remélem, hogy ez másnak is hasznos információ, nem csak nekem.
Válasz #7
Ha modulcsomagolókat, például a webpack-et használ a JavaScript fájlok böngészőben történő használatra történő összefűzéséhez, egyszerűen újra felhasználhatod a Node.js modulodat a böngészőben futó frontendhez. Más szóval, a Node.js modulod megosztható a Node.js és a böngésző között.
Például a következő kódod van sum.js fájlban:
Normál Node.js modul: sum.js
const sum = (a, b) => {
return a + b
}
module.exports = sum
Használd a modult Node.js-ben
const sum = require('path-to-sum.js')
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5: 7
Használd újra a frontendben
import sum from 'path-to-sum.js'
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5: 7
