Tworzę małą aplikację z klientem JavaScript (uruchomionym w przeglądarce) i serwerem Node.js, komunikującym się za pomocą WebSocket.
Chciałbym udostępnić kod między klientem a serwerem. Dopiero zacząłem z Node.js, a moja znajomość współczesnego JavaScript jest trochę zardzewiała, delikatnie mówiąc. Nadal więc skupiam się na funkcji wymagającej () funkcji CommonJS. Jeśli tworzę swoje pakiety za pomocą obiektu „eksportuj”, nie widzę, jak mogę korzystać z tych samych plików JavaScript w przeglądarce.
Chcę utworzyć zestaw metod i klas używanych na obu końcach w celu ułatwienia kodowania i dekodowania wiadomości oraz innych lustrzanych zadań. Wydaje się jednak, że systemy pakowania Node.js / CommonJS uniemożliwiają mi tworzenie plików JavaScript, których można używać po obu stronach.
Próbowałem też użyć JS.Class, aby uzyskać ściślejszy model OO, ale poddałem się, ponieważ nie mogłem wymyślić, w jaki sposób uzyskać dostarczone pliki JavaScript do pracy z wymaganiem (). Czy czegoś tu brakuje?
źródło
Odpowiedzi:
Jeśli chcesz napisać moduł, którego można używać zarówno po stronie klienta, jak i po stronie serwera, mam krótki post na blogu o szybkiej i łatwej metodzie: Pisanie dla Node.js i przeglądarki , zasadniczo następujące (gdzie
this
to samo cowindow
) :Alternatywnie istnieją projekty mające na celu implementację API Node.js po stronie klienta, takie jak gemini Maraka .
Może Cię również zainteresować DNode , który pozwala ujawnić funkcję JavaScript, dzięki czemu można ją wywoływać z innego komputera za pomocą prostego protokołu sieciowego opartego na JSON.
źródło
Epeli ma fajne rozwiązanie tutaj http://epeli.github.com/piler/, które działa nawet bez biblioteki, wystarczy umieścić to w pliku o nazwie share.js
Po stronie serwera wystarczy użyć:
A po stronie klienta wystarczy załadować plik js, a następnie użyć
źródło
Sprawdź kod źródłowy jQuery, który sprawia, że działa to we wzorcu modułów Node.js, wzorcach modułów AMD i globalnie w przeglądarce:
źródło
Nie zapominaj, że ciąg znaków funkcji JavaScript reprezentuje kod źródłowy tej funkcji. Możesz po prostu napisać swoje funkcje i konstruktory w sposób enkapsulowany, aby mogły one być toString () i wysłane do klienta.
Innym sposobem na to jest użycie systemu kompilacji, umieszczenie wspólnego kodu w osobnych plikach, a następnie uwzględnienie ich w skryptach serwera i klienta. Używam tego podejścia do prostej gry klient / serwer za pośrednictwem WebSockets, w której serwer i klient działają zasadniczo w tej samej pętli gry, a klient synchronizuje się z serwerem za każdym razem, aby upewnić się, że nikt nie oszukuje.
Mój system kompilacji gry to prosty skrypt Bash, który uruchamia pliki przez preprocesor C, a następnie przez sed, aby wyczyścić niektóre śmieciowe cpp pozostawia po sobie, dzięki czemu mogę używać wszystkich normalnych rzeczy preprocesora, takich jak #include, #define, #ifdef itp.
źródło
Polecam patrząc na adapterze RequireJS dla node.js . Problem polega na tym, że wzorzec modułu CommonJS, który Node.js używa domyślnie, nie jest asynchroniczny, co blokuje ładowanie w przeglądarce internetowej. RequireJS używa wzorca AMD, który jest zarówno asynchroniczny, jak i zgodny zarówno z serwerem, jak i klientem, o ile korzystasz z
r.js
adaptera.źródło
Może nie jest to całkowicie zgodne z pytaniem, ale pomyślałem, że podzielę się tym.
Chciałem, aby kilka prostych funkcji narzędziowych napisanych w String.prototype było dostępnych zarówno dla węzła, jak i przeglądarki. Po prostu przechowuję te funkcje w pliku o nazwie utilities.js (w podfolderze) i mogę łatwo odwoływać się do nich zarówno ze znacznika script w kodzie przeglądarki, jak i używając wymaganego (pomijając rozszerzenie .js) w moim skrypcie Node.js :
my_node_script.js
my_browser_code.html
Mam nadzieję, że jest to przydatna informacja dla kogoś innego niż ja.
źródło
utilites.js
za pomocą jednej liniimodule.exports = require('./static/js/utilities');
. W ten sposób musisz zaktualizować tylko jedną ścieżkę, jeśli przetasujesz różne rzeczy.utilities.js
jest wshared
folderze w ramach projektu. Używanierequire('/shared/utilities')
dało mi błądCannot find module '/shared/utilities'
. Muszę użyć czegoś takiego,require('./../../shared/utilities')
aby to działało. Tak więc zawsze idzie z bieżącego folderu i podróżuje do katalogu głównego, a następnie do dołu.Jeśli używasz użytku bundlers modułów takich jak WebPack do wiązki plików JavaScript do użytku w przeglądarce, można po prostu ponowne wykorzystanie modułu node.js dla frontend działającej w przeglądarce. Innymi słowy, moduł Node.js może być współdzielony między Node.js a przeglądarką.
Na przykład masz następujący kod sum.js:
Normalny moduł Node.js: sum.js
Użyj modułu w Node.js
Użyj go ponownie w interfejsie
źródło
Serwer może po prostu wysyłać pliki źródłowe JavaScript do klienta (przeglądarki), ale sztuczka polega na tym, że klient będzie musiał zapewnić środowisko mini „eksportu”, zanim będzie mógł
exec
kod i zapisać go jako moduł.Prostym sposobem na stworzenie takiego środowiska jest użycie zamknięcia. Załóżmy na przykład, że Twój serwer udostępnia pliki źródłowe przez HTTP, takie jak
http://example.com/js/foo.js
. Przeglądarka może załadować wymagane pliki za pośrednictwem XMLHttpRequest i załadować kod w następujący sposób:Kluczem jest to, że klient może owinąć obcy kod w anonimową funkcję, która ma być natychmiast uruchomiona (zamknięcie), która tworzy obiekt „eksportuje” i zwraca go, abyś mógł przypisać go tam, gdzie chcesz, zamiast zanieczyszczać globalną przestrzeń nazw. W tym przykładzie jest przypisany do atrybutu window,
fooModule
który będzie zawierał kod wyeksportowany przez plikfoo.js
.źródło
window.fooModule = {}; (new Function('exports', xhr.responseText))(window.fooModule)
.Żadne z poprzednich rozwiązań nie wprowadza systemu modułów CommonJS do przeglądarki.
Jak wspomniano w innych odpowiedzi, są wartościowe rozwiązania manager / Packager jak Browserify lub PILER i istnieją rozwiązania RPC jak dnode lub nowjs .
Ale nie mogłem znaleźć implementacji CommonJS dla przeglądarki (w tym
require()
funkcji iexports
/module.exports
obiektów itp.). Więc napisałem własny, aby później odkryć, że ktoś inny napisał to lepiej niż ja: https://github.com/weepy/brequire . Nazywa się Brequire (skrót od przeglądarki wymaga).Sądząc po popularności, zarządzający aktywami odpowiadają potrzebom większości programistów. Jednak jeśli potrzebujesz implementacji CommonJS w przeglądarce, Brequire prawdopodobnie będzie pasować do rachunku.
Aktualizacja 2015: Nie używam już Brequire (nie był aktualizowany od kilku lat). Jeśli piszę tylko mały moduł o otwartym kodzie źródłowym i chcę, aby ktokolwiek mógł z niego łatwo korzystać, podążę za wzorem podobnym do odpowiedzi Caolana (powyżej) - napisałem o nim na blogu kilka lat temu.
Jeśli jednak piszę moduły do użytku prywatnego lub społeczności znormalizowanej na CommonJS (takiej jak społeczność Ampersand ), to po prostu napiszę je w formacie CommonJS i skorzystam z Browserify .
źródło
warto też zajrzeć na now.js. Pozwala wywoływać funkcje po stronie serwera po stronie klienta, a funkcje po stronie klienta - po stronie serwera
źródło
Jeśli chcesz napisać swoją przeglądarkę w stylu podobnym do Node.js, możesz wypróbować dualify .
Nie ma kompilacji kodu przeglądarki, więc możesz pisać aplikacje bez ograniczeń.
źródło
Napisz swój kod jako moduły RequireJS , a testy jako testy Jasmine .
W ten sposób kod może być ładowany wszędzie za pomocą RequireJS, a testy mogą być uruchamiane w przeglądarce za pomocą jasmine-html i jasmine-node w Node.js bez potrzeby modyfikowania kodu lub testów.
Oto działający przykład tego.
źródło
Przypadek użycia: udostępnij konfigurację aplikacji między Node.js a przeglądarką (jest to tylko ilustracja, prawdopodobnie nie najlepsze podejście w zależności od aplikacji).
Problem: nie możesz użyć
window
(nie istnieje w Node.js) aniglobal
(nie istnieje w przeglądarce).Rozwiązanie:
Plik config.js:
W przeglądarce (index.html):
Możesz teraz otworzyć narzędzia programistyczne i uzyskać dostęp do zmiennej globalnej
config
W Node.js (app.js):
Z Babel lub TypeScript:
źródło
shared.js
ihelpers.js
-shared.js
używa funkcji zhelpers.js
, więc musi byćconst { helperFunc } = require('./helpers')
u góry, aby działał po stronie serwera. Problem leży po stronie klienta, narzeka on na to, żerequire
nie jest funkcją, ale jeśliif (typeof module === 'object') { ... }
wstawię wymaganą linię , serwer mówi, że helperFunc () nie jest zdefiniowany (poza instrukcją if). Jakieś pomysły na to, żeby działało na obu?shared.js
:helperFunc = (typeof exports === 'undefined') ? helperFunc : require('./helpers').helperFunc;
- Niestety, potrzebuję linii dla każdej eksportowanej funkcji, ale mam nadzieję, że to dobre rozwiązanie?Napisałem prosty moduł , który można zaimportować (albo używając wymaga w węźle, albo znaczników skryptu w przeglądarce), którego można użyć do załadowania modułów zarówno z klienta, jak iz serwera.
Przykładowe użycie
1. Definiowanie modułu
Umieść następujące elementy w pliku
log2.js
w folderze statycznych plików internetowych:Proste!
2. Korzystanie z modułu
Ponieważ jest to moduł ładujący moduły dwustronne , możemy go ładować z obu stron (klienta i serwera). Dlatego możesz wykonać następujące czynności, ale nie musisz wykonywać obu naraz (nie mówiąc już o określonej kolejności):
W węźle jest to proste:
To powinno wrócić
2
.Jeśli twój plik nie znajduje się w bieżącym katalogu węzła, pamiętaj, aby zadzwonić
loader.setRoot
ze ścieżką do folderu ze statycznymi plikami internetowymi (lub gdziekolwiek znajduje się moduł).Najpierw zdefiniuj stronę internetową:
Upewnij się, że nie otwierasz pliku bezpośrednio w przeglądarce; ponieważ używa AJAX, sugeruję, aby spojrzeć na
http.server
moduł Pythona 3 (lub cokolwiek, co jest twoim superszybkim, wierszem poleceń, rozwiązaniem do wdrażania serwera sieciowego dla folderów).Jeśli wszystko pójdzie dobrze, pojawi się:
źródło
Napisałem to, jest prosty w użyciu, jeśli chcesz ustawić wszystkie zmienne w zakresie globalnym:
źródło