OK, es ist eine Weile her und dies ist eine beliebte Frage. Deshalb habe ich ein Gerüst-Github-Repository mit JavaScript-Code und einer langen README-Datei erstellt, in der erläutert wird, wie ich eine mittelgroße express.js-Anwendung strukturieren möchte.
focusaurus / express_code_structure ist das Repo mit dem neuesten Code dafür. Pull-Anfragen willkommen.
Hier ist eine Momentaufnahme der README-Datei, da der Stackoverflow keine Nur-Link-Antworten mag. Ich werde einige Updates vornehmen, da dies ein neues Projekt ist, das ich weiter aktualisieren werde, aber letztendlich wird das Github-Repo der aktuelle Ort für diese Informationen sein.
Express-Codestruktur
Dieses Projekt ist ein Beispiel für die Organisation einer mittelgroßen Webanwendung von express.js.
Aktuell, um mindestens v4.14 Dezember 2016 auszudrücken
Wie groß ist Ihre Bewerbung?
Webanwendungen sind nicht alle gleich, und meiner Meinung nach gibt es keine einzige Codestruktur, die auf alle express.js-Anwendungen angewendet werden sollte.
Wenn Ihre Anwendung klein ist, benötigen Sie keine so tiefe Verzeichnisstruktur wie hier dargestellt. Halten Sie es einfach und stecken Sie eine Handvoll .js
Dateien in das Stammverzeichnis Ihres Repositorys, und schon sind Sie fertig. Voilà.
Wenn Ihre Anwendung sehr umfangreich ist, müssen Sie sie irgendwann in verschiedene npm-Pakete aufteilen. Im Allgemeinen scheint der Ansatz von node.js viele kleine Pakete zu bevorzugen, zumindest für Bibliotheken, und Sie sollten Ihre Anwendung mithilfe mehrerer npm-Pakete aufbauen, da dies sinnvoll ist und den Overhead rechtfertigt. Wenn Ihre Anwendung wächst und ein Teil des Codes außerhalb Ihrer Anwendung eindeutig wiederverwendbar wird oder ein klares Subsystem ist, verschieben Sie ihn in das eigene Git-Repository und machen Sie ihn zu einem eigenständigen npm-Paket.
So im Mittelpunkt dieses Projektes ist es, eine tragfähige Struktur für eine mittelgroße Anwendung zu illustrieren.
Was ist Ihre Gesamtarchitektur?
Es gibt viele Ansätze zum Erstellen einer Webanwendung, z
- Serverseitige MVC a la Ruby on Rails
- Einseitiger Anwendungsstil a la MongoDB / Express / Angular / Node (MEAN)
- Grundlegende Website mit einigen Formularen
- Modelle / Operationen / Ansichten / Ereignisse Stil a la MVC ist tot, es ist Zeit, weiterzumachen
- und viele andere sowohl aktuelle als auch historische
Jedes davon passt gut in eine andere Verzeichnisstruktur. In diesem Beispiel handelt es sich nur um ein Gerüst und nicht um eine voll funktionsfähige App. Ich gehe jedoch von den folgenden wichtigen Architekturpunkten aus:
- Die Site enthält einige traditionelle statische Seiten / Vorlagen
- Der "Anwendungs" -Teil der Site wird als Single Page Application-Stil entwickelt
- Die Anwendung stellt dem Browser eine API im REST / JSON-Stil zur Verfügung
- Die App modelliert eine einfache Geschäftsdomäne. In diesem Fall handelt es sich um eine Autohausanwendung
Und was ist mit Ruby on Rails?
Während des gesamten Projekts wird es ein Thema sein, dass viele der in Ruby on Rails und den von ihnen getroffenen Entscheidungen zum "Übereinkommen über die Konfiguration" enthaltenen Ideen, obwohl sie weithin akzeptiert und verwendet werden, nicht wirklich sehr hilfreich sind und manchmal das Gegenteil von dem sind, was dieses Repository darstellt empfiehlt.
Mein Hauptpunkt hier ist, dass der Organisation von Code grundlegende Prinzipien zugrunde liegen. Basierend auf diesen Prinzipien sind die Ruby on Rails-Konventionen (meistens) für die Ruby on Rails-Community sinnvoll. Nur gedankenlos diese Konventionen nachzuahmen, geht jedoch daneben. Sobald Sie die Grundprinzipien verstanden haben, sind ALLE Ihre Projekte gut organisiert und klar: Shell-Skripte, Spiele, mobile Apps, Unternehmensprojekte und sogar Ihr Home-Verzeichnis.
Für die Rails-Community möchten sie, dass ein einzelner Rails-Entwickler von App zu App zu App wechselt und jedes Mal damit vertraut und vertraut ist. Dies ist sehr sinnvoll, wenn Sie 37 Signale oder Pivotal Labs sind, und hat Vorteile. In der serverseitigen JavaScript-Welt ist das allgemeine Ethos einfach viel wilder im Westen, und wir haben damit kein wirkliches Problem. Das ist unsere Art. Wir sind daran gewöhnt. Selbst innerhalb von express.js ist es eine enge Verwandtschaft von Sinatra, nicht von Rails, und Konventionen von Rails zu übernehmen, hilft normalerweise nichts. Ich würde sogar Prinzipien über Konvention über Konfiguration sagen .
Grundprinzipien und Motivationen
Der App-Symlink-Trick
Es gibt viele Ansätze skizziert und ausführlich von der Gemeinschaft in dem großen Kern diskutiert bessere lokale require () Pfade für Node.js . Ich könnte mich bald dafür entscheiden, entweder "nur mit vielen ../../../ .. umzugehen" oder das requireFrom- Modul zu verwenden. Im Moment habe ich jedoch den unten beschriebenen Symlink-Trick verwendet.
Ein Weg, um projektinterne Anforderungen mit lästigen relativen Pfaden wie zu vermeiden, require("../../../config")
besteht darin, den folgenden Trick zu verwenden:
- Erstellen Sie unter node_modules einen Symlink für Ihre App
- cd node_modules && ln -nsf ../app
- fügen Sie einfach die node_modules / app Symlink selbst , nicht die gesamte node_modules Ordner, zu git
- git add -f node_modules / app
- Ja, Sie sollten immer noch "node_modules" in Ihrer
.gitignore
Datei haben
- Nein, Sie sollten "node_modules" nicht in Ihr Git-Repository einfügen. Einige Leute werden Ihnen dies empfehlen. Sie sind falsch.
- Jetzt können Sie projektinterne Module mit diesem Präfix anfordern
var config = require("app/config");
var DealModel = require("app/deals/deal-model")
;;
- Grundsätzlich erfordert dies projektinterne Arbeiten, die den Anforderungen für externe npm-Module sehr ähnlich sind.
- Entschuldigung, Windows-Benutzer, Sie müssen sich an die relativen Pfade des übergeordneten Verzeichnisses halten.
Aufbau
Im Allgemeinen erwarten Codemodule und Klassen nur ein übergebenes grundlegendes JavaScript- options
Objekt. Nur app/server.js
das app/config.js
Modul sollte geladen werden. Von dort aus können kleine options
Objekte synthetisiert werden, um Subsysteme nach Bedarf zu konfigurieren. Die Kopplung jedes Subsystems an ein großes globales Konfigurationsmodul mit zusätzlichen Informationen ist jedoch eine schlechte Kopplung.
Versuchen Sie, die Erstellung von DB-Verbindungen zu zentralisieren und diese an Subsysteme zu übergeben, anstatt Verbindungsparameter zu übergeben und Subsysteme selbst ausgehende Verbindungen herstellen zu lassen.
NODE_ENV
Dies ist eine weitere verlockende, aber schreckliche Idee, die von Rails übernommen wurde. Es sollte genau 1 Stelle in Ihrer App sein, app/config.js
die die NODE_ENV
Umgebungsvariable betrachtet. Alles andere sollte eine explizite Option als Klassenkonstruktorargument oder Modulkonfigurationsparameter annehmen.
Wenn das E-Mail-Modul eine Option zum Zustellen von E-Mails hat (SMTP, Protokollieren bei stdout, Einfügen in die Warteschlange usw.), sollte es eine Option wie diese verwenden {deliver: 'stdout'}
, diese sollte jedoch absolut nicht überprüft werden NODE_ENV
.
Tests
Ich behalte meine Testdateien jetzt im selben Verzeichnis wie der entsprechende Code und verwende Namenskonventionen für Dateinamenerweiterungen, um Tests von Produktionscode zu unterscheiden.
foo.js
hat den Code des Moduls "foo"
foo.tape.js
hat die knotenbasierten Tests für foo und lebt im selben Verzeichnis
foo.btape.js
kann für Tests verwendet werden, die in einer Browserumgebung ausgeführt werden müssen
Ich verwende Dateisystem-Globs und den find . -name '*.tape.js'
Befehl, um bei Bedarf auf alle meine Tests zuzugreifen.
So organisieren Sie Code in jeder .js
Moduldatei
In diesem Projekt geht es hauptsächlich darum, wohin Dateien und Verzeichnisse gehen, und ich möchte nicht viel mehr hinzufügen, aber ich möchte nur erwähnen, dass ich meinen Code in drei verschiedene Abschnitte gegliedert habe.
- Das Öffnen des Blocks von CommonJS erfordert Aufrufe von Statusabhängigkeiten
- Hauptcodeblock von reinem JavaScript. Keine CommonJS-Verschmutzung hier. Verweisen Sie nicht auf Exporte, Module oder Anforderungen.
- Schließen des CommonJS-Blocks zum Einrichten von Exporten