Jak stworzyć strukturę aplikacji express.js?


102

Czy istnieje wspólna konwencja podziału i modularyzacji app.jspliku w aplikacji Express.js ? A może często trzyma się wszystko w jednym pliku?


3
Byli ludzie, dzieląc je na trasy. Możesz również zapoznać się z zasobami ekspresowymi.
BRampersad,

@Brandon_R Czy próbowałeś zasobów? Spojrzałem na to i pomyślałem, że wygląda schludnie, po prostu jeszcze nie kopnąłem opon.
Szansa na

1
Trochę późno, ale niedawno otworzyłem router dla ekspresu, który pozwala ładnie rozbić app.js kontrolery intro + widoki itp. Zobacz: github.com/kishorenc/road
jeffreyveon

Odpowiedzi:


82

Mój rozpadł się w następujący sposób:

~/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

Korzystam z eksportu, aby zwrócić to, co jest istotne. Na przykład w modelach, które wykonuję:

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

a jeśli muszę utworzyć numer telefonu, jest to tak proste, jak:

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

jeśli muszę użyć schematu, to PhoneNumber.schema

(co zakłada, że ​​pracujemy z folderu tras i musimy przejść 1 poziom w górę, a następnie w dół do modeli)


EDYCJA 4

Express wiki ma listę struktur zbudowanych na wierzchu.

Spośród nich myślę, że matador na Twitterze ma całkiem dobrą strukturę. W rzeczywistości zastosowaliśmy bardzo podobne podejście do sposobu ładowania części aplikacji.

derby.js również wygląda niezwykle interesująco. Jest to podobne do meteor bez całego szumu i faktycznie przypisuje kredyt tam, gdzie należy się kredyt (zwłaszcza węzeł i ekspres).


EDYCJA 3

Jeśli jesteś fanem CoffeeScript (ja nie jestem) i naprawdę chcesz L&F Railsów, jest też Tower.js .


EDYCJA 2

Jeśli jesteś zaznajomiony z Railsami i nie przeszkadza ci wykrwawianie niektórych koncepcji, to jest Lokomotywa . Jest to lekki framework oparty na Express. Ma bardzo podobną strukturę jak RoR i przenosi niektóre z bardziej podstawowych pojęć (takich jak routing).

Warto to sprawdzić, nawet jeśli nie planujesz z niego korzystać.


EDYCJA 1

nodejs-express-mongoose-demo jest bardzo podobne do mojej struktury. Sprawdź to.


2
Gdzie idzie logika biznesowa? Czy kiedykolwiek korzystałeś z pomocników do rzeczy takich jak uwierzytelnianie?
Eric the Red

@ErictheRed Jeśli znasz wzorzec MVC (szyny, Asp.Net mvc itp.), To uważam, że moje trasy są moimi kontrolerami i wszystko w pewnym sensie układa się na swoim miejscu. Logika biznesowa idzie w modelach (chociaż mam problemy z walidacją i mangustą). Dla pomocników używam Eksporty w prostej wewnętrznej bibliotece narzędzi, którą przygotowuję dla siebie do rzeczy, których ponownie używam.
Szansa na

Fajnie byłoby przesłać przykładową konfigurację na github, abyśmy mogli ją obejrzeć. Co znajduje się w folderze / plikach Routes?
chovy

1
@chovy Dodałem link do github.com/qed42/nodejs-express-mongoose-demo, który ma bardzo podobną strukturę
Chance

Zalecam unikanie rozbudowanych frameworków
opartych na ekspresie

9

Ostrzeżenie: odnośnik do kodu, który zhakowałem razem w celu usunięcia węzłów, trochę działa, ale nie jest elegancki ani dopracowany.

Aby być bardziej szczegółowym na temat podziału, app.jsmam następujący plik app.js

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

bootstrap(app);

Zasadniczo oznacza to, że umieszczam cały proces ładowania początkowego w osobnym pliku, a następnie uruchamiam serwer.

Więc co robi 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");
};

Cóż, dzieli całą konfigurację inicjalizacji serwera na ładne fragmenty. konkretnie

  • Mam fragment, który konfiguruje całe moje zdalne uwierzytelnianie OAuth przy użyciu everyauth.
  • Mam fragment, który konfiguruje moją aplikację (w zasadzie wywołanie app.configure)
  • Mam trochę kodu, który mniej dziurkuje, więc w czasie wykonywania ponownie kompiluje wszystkie moje pliki less do css.
  • Mam kod, który konfiguruje wszystkie moje trasy
  • Nazywam ten mały moduł nko
  • Wreszcie uruchamiam serwer nasłuchując portu.

Spójrzmy na przykład na plik routingu

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);

Tutaj ładuję wszystkie moje modele i trasy jako tablice plików.

Zastrzeżenie: readdirSync jest ok tylko wtedy, gdy zostanie wywołane przed uruchomieniem serwera http (wcześniej .listen). Wywołanie synchronicznych wywołań blokujących w czasie uruchamiania serwera sprawia, że ​​kod jest bardziej czytelny (jest to w zasadzie 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);
        }
    });

Tutaj uderzam socket.io, aby faktycznie używał autoryzacji, a nie pozwalając jakiemukolwiek tomowi i jackowi rozmawiać z moim serwerem socket.io

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

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

Tutaj rozpoczynam moje trasy od przekazania odpowiedniego modelu do każdego obiektu trasy zwróconego z pliku trasy.

Zasadniczo chodzi o to, że organizujesz wszystko w ładne małe moduły, a następnie masz pewien mechanizm ładowania początkowego.

Mój inny projekt (mój blog) ma plik init o podobnej strukturze .

Zastrzeżenie: blog jest zepsuty i nie tworzy się, pracuję nad tym.



0

Moje aplikacje są tworzone w oparciu o narzędzie ekspresowego generatora. Możesz go zainstalować, uruchamiając npm install express-generator -gi uruchamiając za pomocą express <APP_NAME>.

Aby dać ci perspektywę, jedna ze struktur mojej mniejszej aplikacji wyglądała następująco:

~/
|~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

Jedną fajną rzeczą, którą lubię w tej strukturze, którą ostatecznie dostosowuję do każdej rozwijanej przeze mnie aplikacji ekspresowej, jest sposób organizacji tras. Nie podobało mi się, że muszę wymagać plików tras w pliku app.js i app.use()każdej trasy, zwłaszcza gdy plik się powiększa. W związku z tym uznałem za pomocne zgrupowanie i scentralizowanie wszystkich moich app.use()plików w pliku ./routes/index.js.

Ostatecznie mój plik app.js będzie wyglądał mniej więcej tak:

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

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

a mój ./routes/index.js będzie wyglądał mniej więcej tak:

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

Jestem w stanie to zrobić po prostu require(./users)dlatego, że napisałem trasy użytkowników przy użyciu express.Router (), który pozwala mi „grupować” wiele tras, a następnie eksportować je jednocześnie, w celu uczynienia aplikacji bardziej modułową.

To jest przykład tego, co możesz dobrze na mojej trasie ./routers/users.js:


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

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

module.exports = router;

Mamy nadzieję, że pomogło to odpowiedzieć na Twoje pytanie! Powodzenia!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.