Jak strukturovat aplikaci express.js?

Já jsem ten svůj rozdělil následovně:

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

Používám exporty k vrácení toho, co je relevantní. Například v modelech, které dělám:

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

a pak, když potřebuji vytvořit telefonní číslo, je to stejně jednoduché jako:

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

pokud potřebuji použít schéma, pak PhoneNumber.schema

(což předpokládá, že pracujeme ze složky tras a potřebujeme přejít o 1 úroveň výš a pak dolů k modelům)

UPRAVIT 4

Expresní wiki má nad sebou postavený seznam rámců.

Z nich si myslím, že Twitter je matador je strukturován docela dobře. Ve skutečnosti jsme použili velmi podobný přístup k tomu, jak načítají části aplikace.

derby.js také vypadá velmi zajímavě. Podobá se to meteoru bez veškerého humbuku a ve skutečnosti dává zásluhy tam, kde je třeba ocenit (zejména node a express).

UPRAVIT 3

Pokud jste fanouškem CoffeeScriptu (já nejsem) a chcete L&F of Rails, existuje také Tower.js .

UPRAVIT 2

Pokud znáte Rails a nevadí vám přetékání některých konceptů, je tu Lokomotiva . Je to lehký framework postavený na Express. Má velmi podobnou strukturu jako RoR a přenáší některé ze základních pojmů (jako je směrování).

Stojí za to se podívat, i když to neplánujete používat.

UPRAVIT 1

nodejs-express-mongoose-demo je velmi podobný tomu, jak mám strukturovaný můj. Podívejte se na to.


Upozornění: odkazující kód, který jsem společně hacknul pro vyřazení uzlu, funguje, ale není ani zdaleka elegantní ani uhlazený.

Abychom byli konkrétnější o rozdělení app.js Mám následující soubor app.js

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

bootstrap(app);

To v podstatě znamená, že umístím všechny své bootstrappingy do samostatného souboru a pak zavedu server.

Co tedy bootstrap dělá?

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

Dobře to rozděluje veškeré nastavení inicializace serveru na pěkné kousky. Konkrétně

  • Mám blok, který nastavuje veškeré mé vzdálené ověřování OAuth pomocí everyauth.
  • Mám blok, který konfiguruje moji aplikaci (v podstatě volá app.configure )
  • Mám trochu kódu, který se méně razí, takže za běhu znovu zkompiluje všechny mé méně do css.
  • Mám kód, který nastavuje všechny mé trasy
  • Nazývám tento malý modul nko
  • Nakonec spustím server poslechem portu.

Podívejme se například na směrovací soubor

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

Zde načtu všechny své modely a trasy jako pole souborů.

Odmítnutí odpovědnosti: readdirSync je v pořádku pouze při volání před spuštěním http serveru (před .listen ). Volání synchronního blokování hovorů v době spuštění serveru jen činí kód čitelnějším (je to v podstatě 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);
        }
    });

Zde kliknu na socket.io, abych skutečně použil autorizaci, než abych nechal jakéhokoli Toma a Jacka mluvit s mým socket.io serverem

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

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

Zde začínám své trasy předáním příslušného modelu do každého objektu trasy vráceného ze souboru trasy.

V podstatě jde o to, že vše uspořádáte do pěkných malých modulů a pak máte nějaký bootstrapovací mechanismus.

Můj další projekt (můj blog) má init soubor s podobnou strukturou.

Odmítnutí odpovědnosti: blog je nefunkční a nestaví se, pracuji na tom.