Wie strukturiere ich eine express.js-Anwendung?


102

Gibt es eine gängige Konvention zum Aufteilen und Modularisieren der app.jsDatei in einer Express.js- Anwendung? Oder ist es üblich, alles in einer einzigen Datei zu speichern?


3
Es gab Leute, die sie in Routen aufteilten. Sie können sich auch Express-Ressourcen ansehen.
BRampersad

@Brandon_R haben Sie Ressourcen ausprobiert? Ich warf einen Blick darauf und fand es ordentlich, habe aber noch nicht gegen die Reifen getreten.
Chance

1
Ein bisschen spät, aber ich habe kürzlich einen Router für Express geöffnet, mit dem Sie die App.js schön in Intro-Controller + Ansichten usw.
aufteilen können

Antworten:


82

Ich habe meine wie folgt aufgeteilt:

~/app
|~controllers
| |-monkey.js
| |-zoo.js
|~models
| |-monkey.js
| |-zoo.js
|~views
| |~zoos
|   |-new.jade
|   |-_form.jade
|~test
|  |~controllers
|    |-zoo.js
|  |~models
|    |-zoo.js
|-index.js

Ich verwende Exporte, um zurückzugeben, was relevant ist. Zum Beispiel in den Modellen, die ich mache:

module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema);

und wenn ich dann eine Telefonnummer erstellen muss, ist es so einfach wie:

var PhoneNumber = require('../models/phoneNumber');
var phoneNumber = new PhoneNumber();

Wenn ich das Schema verwenden muss, dann PhoneNumber.schema

(Dies setzt voraus, dass wir vom Routenordner aus arbeiten und 1 Ebene nach oben und dann nach unten zu den Modellen gehen müssen.)


BEARBEITEN 4

Das Express-Wiki enthält eine Liste von Frameworks, die darauf aufbauen.

Ich denke, der Matador von Twitter ist ziemlich gut strukturiert. Wir haben tatsächlich einen sehr ähnlichen Ansatz verwendet, um Teile der App zu laden.

derby.js sieht auch sehr interessant aus. Es ist vergleichbar mit Meteor ohne den ganzen Hype und gibt tatsächlich Kredit, wo Kredit fällig ist (insbesondere Knoten und Express).


BEARBEITEN 3

Wenn Sie ein Fan von CoffeeScript sind (ich bin es nicht) und reeeeaaaaaally das L & F von Rails wollen, gibt es auch Tower.js .


BEARBEITEN 2

Wenn Sie mit Rails vertraut sind und sich nicht um das Ausbluten einiger Konzepte kümmern, gibt es Locomotive . Es ist ein leichtes Framework, das auf Express basiert. Es hat eine sehr ähnliche Struktur wie RoR und überträgt einige der rudimentäreren Konzepte (wie z. B. Routing).

Es lohnt sich, es sich anzusehen, auch wenn Sie nicht vorhaben, es zu verwenden.


BEARBEITEN 1

nodejs-express-mongoose-demo ist sehr ähnlich wie ich meine strukturiert habe. Hör zu.


2
Wohin geht die Geschäftslogik? Verwenden Sie jemals Helfer für Dinge wie die Authentifizierung?
Eric der Rote

@ErictheRed Wenn Sie mit dem MVC-Muster (Rails, Asp.Net MVC usw.) vertraut sind, betrachte ich meine Routen als meine Controller und danach passt alles zusammen. Geschäftslogik geht in die Modelle (obwohl ich Schwierigkeiten mit der Validierung und Mungo habe). Für Helfer verwende ich Exporte für eine einfache interne Util-Bibliothek, die ich für Dinge zusammenstelle, die ich wieder verwende.
Chance

Es wäre cool, ein Beispiel-Setup auf github hochzuladen, damit wir es uns ansehen können. Was geht in Routenordner / Dateien?
Chovy

1
@chovy Ich habe einen Link zu github.com/qed42/nodejs-express-mongoose-demo hinzugefügt , der eine sehr ähnliche Struktur hat
Chance

Ich empfehle, aufgeblähte Frameworks zu vermeiden, die auf Express
aufbauen

9

Warnung: Wenn ich auf Code verweise, den ich für das Knockout von Knoten zusammen gehackt habe, funktioniert das irgendwie, ist aber alles andere als elegant oder poliert.

Um genauer zu sein, habe app.jsich die folgende Datei app.js.

var express = require('express'),
    bootstrap = require('./init/bootstrap.js'),
    app = module.exports = express.createServer();

bootstrap(app);

Dies bedeutet im Grunde, dass ich mein gesamtes Bootstrapping in einer separaten Datei platziere und dann den Server bootstrap.

Was macht Bootstrap ?

var configure = require("./app-configure.js"),
    less = require("./watch-less.js"),
    everyauth = require("./config-everyauth.js"),
    routes = require("./start-routes.js"),
    tools = require("buffertools"),
    nko = require("nko"),
    sessionStore = new (require("express").session.MemoryStore)()

module.exports = function(app) {
    everyauth(app);
    configure(app, sessionStore);
    less();
    routes(app, sessionStore);
    nko('/9Ehs3Dwu0bSByCS');


    app.listen(process.env.PORT);
    console.log("server listening on port xxxx");
};

Nun, es teilt alle Server-Initialisierungs-Setups in schöne Teile auf. Speziell

  • Ich habe einen Block, der meine gesamte Remote-OAuth-Authentifizierung mit everyauth einrichtet.
  • Ich habe einen Block, der meine Anwendung konfiguriert (im Grunde genommen aufrufen app.configure)
  • Ich habe ein wenig Code, der weniger Punches enthält, sodass er zur Laufzeit alle meine weniger in CSS neu kompiliert.
  • Ich habe Code, der alle meine Routen einrichtet
  • Ich nenne dieses kleine nko-Modul
  • Schließlich starte ich den Server, indem ich einen Port abhöre.

Schauen wir uns zum Beispiel die Routing- Datei an

var fs = require("fs"),
    parseCookie = require('connect').utils.parseCookie;

module.exports = function(app, sessionStore) {
    var modelUrl = __dirname + "/../model/",
        models = fs.readdirSync(modelUrl),
        routeUrl = __dirname + "/../route/"
        routes = fs.readdirSync(routeUrl);

Hier lade ich alle meine Modelle und Routen als Arrays von Dateien.

Haftungsausschluss: readdirSync ist nur in Ordnung, wenn er aufgerufen wird, bevor Sie den http-Server starten (vorher .listen). Das Aufrufen synchroner Blockierungsaufrufe zur Serverstartzeit macht den Code nur lesbarer (es ist im Grunde ein Hack).

    var io = require("socket.io").listen(app);

    io.set("authorization", function(data, accept) {
        if (data.headers.cookie) {
            data.cookie = parseCookie(data.headers.cookie);

            data.sessionId = data.cookie['express.sid'];

            sessionStore.get(data.sessionId, function(err, session) {

                if (err) {
                    return accept(err.message, false);
                } else if (!(session && session.auth)) {
                    return accept("not authorized", false)
                }
                data.session = session;
                accept(null, true);
            });
        } else {
            return accept('No cookie', false);
        }
    });

Hier drücke ich socket.io, um die Autorisierung tatsächlich zu verwenden, anstatt Tom und Jack mit meinem socket.io-Server sprechen zu lassen

    routes.forEach(function(file) {
        var route = require(routeUrl + file),
            model = require(modelUrl + file);

        route(app, model, io);
    });
};

Hier beginne ich meine Routen, indem ich das entsprechende Modell an jedes aus der Routendatei zurückgegebene Routenobjekt übergebe.

Grundsätzlich geht es darum, dass Sie alles in nette kleine Module organisieren und dann einen Bootstrapping-Mechanismus haben.

Mein anderes Projekt (mein Blog) hat eine Init-Datei mit einer ähnlichen Struktur .

Haftungsausschluss: Der Blog ist kaputt und wird nicht erstellt. Ich arbeite daran.



0

Ich habe meine Apps auf dem Express-Generator-Tool aufgebaut. Sie können es installieren, indem Sie es npm install express-generator -gausführen und mit ausführen express <APP_NAME>.

Um Ihnen eine Perspektive zu geben, sah eine der Strukturen meiner kleineren Anwendung folgendermaßen aus:

~/
|~bin
| |-www
|
|~config
| |-config.json
|
|~database
| |-database.js
|
|~middlewares
| |-authentication.js
| |-logger.js
|
|~models
| |-Bank.js
| |-User.js
|
|~routes
| |-index.js
| |-banks.js
| |-users.js
|
|~utilities
| |-fiat-converersion.js
|
|-app.js
|-package.json
|-package-lock.json

Eine coole Sache, die ich an dieser Struktur mag, die ich letztendlich für jede von mir entwickelte Expressanwendung übernehme, ist die Art und Weise, wie die Routen organisiert sind. Ich mochte es nicht, jede Routendatei in die app.js und app.use()jede Route benötigen zu müssen , besonders wenn die Datei größer wird. Daher fand ich es hilfreich, alle meine app.use()Dateien in einer ./routes/index.js-Datei zu gruppieren und zu zentralisieren .

Am Ende wird meine app.js ungefähr so ​​aussehen:

...
const express = require('express');
const app = express();

...
require('./routes/index')(app);

und meine ./routes/index.js sehen ungefähr so ​​aus:

module.exports = (app) => {
  app.use('/users', require('./users'));
  app.use('/banks', require('./banks'));
};

Ich kann dies einfach, require(./users)weil ich die Benutzerroute mit express.Router () geschrieben habe, wodurch ich mehrere Routen "gruppieren" und dann gleichzeitig exportieren kann, um die Anwendung modularer zu gestalten.

Dies ist ein Beispiel dafür, was Sie auf meiner Route ./routers/users.js in Ordnung bringen würden:


const router = require('express').Router();

router.post('/signup', async (req, res) => {
    // Signup code here
});

module.exports = router;

Hoffentlich hat dies geholfen, Ihre Frage zu beantworten! Viel Glück!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.