OK, è passato un po 'di tempo e questa è una domanda popolare, quindi sono andato avanti e ho creato un repository github per impalcature con codice JavaScript e un lungo README su come mi piace strutturare un'applicazione express.js di medie dimensioni.
focusaurus / express_code_structure è il repository con l'ultimo codice per questo. Pull richieste di benvenuto.
Ecco un'istantanea del file README poiché StackOverflow non ama le risposte "just-a-link". Farò alcuni aggiornamenti poiché si tratta di un nuovo progetto che continuerò ad aggiornare, ma alla fine il repository github sarà il luogo aggiornato per queste informazioni.
Struttura del codice espresso
Questo progetto è un esempio di come organizzare un'applicazione web express.js di medie dimensioni.
Corrente almeno per esprimere v4.14 dicembre 2016
Quanto è grande la tua applicazione?
Le applicazioni Web non sono tutte uguali e, secondo me, non esiste un'unica struttura di codice che dovrebbe essere applicata a tutte le applicazioni express.js.
Se la tua applicazione è piccola, non hai bisogno di una struttura di directory così profonda come esemplificata qui. Mantienilo semplice e metti una manciata di .js
file nella radice del tuo repository e il gioco è fatto. Ecco.
Se l'applicazione è enorme, a un certo punto è necessario suddividerla in pacchetti npm distinti. In generale, l'approccio node.js sembra favorire molti piccoli pacchetti, almeno per le librerie, e dovresti costruire la tua applicazione usando diversi pacchetti npm poiché questo inizia a dare un senso e giustificare il sovraccarico. Quindi man mano che la tua applicazione cresce e una parte del codice diventa chiaramente riutilizzabile al di fuori della tua applicazione o è un sottosistema chiaro, spostalo nel suo repository git e trasformalo in un pacchetto npm autonomo.
Così l'obiettivo di questo progetto è quello di illustrare una struttura praticabile per un'applicazione di medie dimensioni.
Qual è la tua architettura complessiva
Esistono molti approcci alla creazione di un'applicazione Web, ad esempio
- Server Side MVC alla Ruby on Rails
- Applicazione a pagina singola in stile MongoDB / Express / Angolare / Nodo (MEAN)
- Sito Web di base con alcuni moduli
- Lo stile dei modelli / operazioni / viste / eventi a la MVC è morto, è ora di spostarsi
- e molti altri sia attuali che storici
Ognuno di questi si adatta perfettamente a una diversa struttura di directory. Ai fini di questo esempio, è solo un'impalcatura e non un'app completamente funzionante, ma presumo i seguenti punti chiave dell'architettura:
- Il sito ha alcune pagine / modelli statici tradizionali
- La parte "applicazione" del sito è sviluppata come uno stile di applicazione a pagina singola
- L'applicazione espone un'API di stile REST / JSON al browser
- L'app modella un semplice dominio aziendale, in questo caso è un'applicazione di un concessionario di automobili
E che dire di Ruby on Rails?
Durante questo progetto sarà un tema che molte delle idee incorporate in Ruby on Rails e le decisioni "Convenzione sulla configurazione" che hanno adottato, sebbene ampiamente accettate e utilizzate, non sono in realtà molto utili e talvolta sono l'opposto di ciò che questo repository raccomanda.
Il mio punto principale qui è che ci sono principi di base nell'organizzazione del codice e, sulla base di tali principi, le convenzioni di Ruby on Rails hanno senso (principalmente) per la comunità di Ruby on Rails. Tuttavia, solo sconsiderare quelle convenzioni non ha senso. Una volta individuati i principi di base, TUTTI i tuoi progetti saranno ben organizzati e chiari: script di shell, giochi, app mobili, progetti aziendali, persino la tua home directory.
Per la comunità di Rails, vogliono essere in grado di avere un singolo sviluppatore di Rails da un'app all'altra dell'app e avere familiarità con essa ogni volta. Questo ha molto senso se hai 37 segnali o Pivotal Labs e ha dei vantaggi. Nel mondo JavaScript lato server, l'ethos generale è semplicemente molto più selvaggio ovest e non abbiamo davvero problemi con questo. È così che andiamo. Ci siamo abituati. Anche all'interno di express.js, è un parente stretto di Sinatra, non di Rails, e prendere convenzioni da Rails di solito non aiuta nulla. Direi anche Principi sulla Convenzione sulla Configurazione .
Principi e motivazioni sottostanti
Il trucco del collegamento simbolico dell'app
Ci sono molti approcci descritti e discussi a lungo dalla comunità nella grande Gist Meglio locale richiede) i percorsi per Node.js ( . Potrei presto decidere di preferire "solo occuparmi di un sacco di ../../../ .." o utilizzare il mod request di Rom. Tuttavia, al momento, sto usando il trucco del link simbolico descritto di seguito.
Quindi un modo per evitare intra-progetto richiede con percorsi relativi fastidiosi come require("../../../config")
è quello di usare il seguente trucco:
- crea un link simbolico in node_modules per la tua app
- cd node_modules && ln -nsf ../app
- aggiungi solo il link simbolico node_modules / app stesso , non l'intera cartella node_modules, a git
- git aggiungi -f node_modules / app
- Sì, dovresti avere ancora "node_modules" nel tuo
.gitignore
file
- No, non dovresti inserire "node_modules" nel tuo repository git. Alcune persone ti consiglieranno di farlo. Non sono corretti
- Ora puoi richiedere moduli intra-progetto usando questo prefisso
var config = require("app/config");
var DealModel = require("app/deals/deal-model")
;
- Fondamentalmente, questo rende il progetto intra-progetto molto simile a quello richiesto per i moduli npm esterni.
- Siamo spiacenti, utenti di Windows, è necessario attenersi ai percorsi relativi della directory principale.
Configurazione
Generalmente i moduli di codice e le classi prevedono solo un options
oggetto JavaScript di base passato. Solo app/server.js
il app/config.js
modulo deve essere caricato . Da lì può sintetizzare piccoli options
oggetti per configurare i sottosistemi secondo necessità, ma accoppiare ogni sottosistema a un grande modulo di configurazione globale pieno di informazioni extra è un cattivo accoppiamento.
Provare a centralizzare la creazione di connessioni DB e passare quelle nei sottosistemi anziché passare i parametri di connessione e fare in modo che i sottosistemi effettuino connessioni in uscita.
NODE_ENV
Questa è un'altra idea allettante ma terribile riportata da Rails. Dovrebbe esserci esattamente 1 posto nella tua app, app/config.js
che esamina la NODE_ENV
variabile di ambiente. Tutto il resto dovrebbe prendere un'opzione esplicita come argomento del costruttore di classe o parametro di configurazione del modulo.
Se il modulo e-mail ha un'opzione su come recapitare le e-mail (SMTP, accedere a stdout, mettere in coda ecc.), Dovrebbe prendere un'opzione come {deliver: 'stdout'}
ma non dovrebbe assolutamente controllare NODE_ENV
.
test
Ora mantengo i miei file di test nella stessa directory del codice corrispondente e utilizzo le convenzioni di denominazione dell'estensione del nome file per distinguere i test dal codice di produzione.
foo.js
ha il codice del modulo "pippo"
foo.tape.js
ha i test basati sul nodo per foo e vive nella stessa directory
foo.btape.js
può essere utilizzato per i test che devono essere eseguiti in un ambiente browser
Uso i globs del filesystem e il find . -name '*.tape.js'
comando per accedere a tutti i miei test, se necessario.
Come organizzare il codice all'interno di ciascun .js
file del modulo
Lo scopo di questo progetto riguarda principalmente dove vanno i file e le directory e non voglio aggiungere altro ambito, ma menzionerò solo che organizzo il mio codice in 3 sezioni distinte.
- Il blocco di apertura di CommonJS richiede chiamate per dichiarare dipendenze
- Blocco di codice principale di puro JavaScript. Nessun inquinamento da CommonJS qui. Non fare riferimento a esportazioni, moduli o richieste.
- Blocco di chiusura di CommonJS per impostare le esportazioni