javascript - ¿Cómo estructurar una aplicación express.js?
node.js modularity (3)
Para la organización de enrutamiento mantenible puede consultar este artículo sobre el módulo de nodo de ruta expresa y probarlo. Esta es la mejor solución para mí.
¿Existe una convención común para dividir y modularizar el archivo app.js
en una aplicación Express.js ? ¿O es común mantener todo en un solo archivo?
Tengo el mío dividido de la siguiente manera:
~/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
Yo uso Exportaciones para devolver lo relevante. Por ejemplo, en los modelos que hago:
module.exports = mongoose.model(''PhoneNumber'', PhoneNumberSchema);
y luego, si necesito crear un número de teléfono, es tan simple como:
var PhoneNumber = require(''../models/phoneNumber'');
var phoneNumber = new PhoneNumber();
si necesito usar el esquema, entonces PhoneNumber.schema
(lo cual supone que estamos trabajando desde la carpeta de rutas y necesitamos subir de nivel 1 y luego a modelos)
EDIT 4
La wiki expresa tiene una lista de marcos construidos sobre ella.
De esos, creo que el matador de Twitter está estructurado bastante bien. De hecho, utilizamos un enfoque muy similar a la forma en que cargan partes de la aplicación.
derby.js también se ve extremadamente interesante. Es similar a un meteor sin todo el bombo y en realidad da crédito donde se debe crédito (notablemente, nodo y expreso).
EDIT 3
Si eres un fanático de CoffeeScript (no lo soy) y quieres que reeeeaaaaaaalmente quieras el L & F de Rails, también está Tower.js .
EDIT 2
Si está familiarizado con Rails y no le importa el desbordamiento de algunos conceptos, existe Locomotive . Es un marco ligero construido en Express. Tiene una estructura muy similar a RoR y transmite algunos de los conceptos más rudimentarios (como el enrutamiento).
Vale la pena echarle un vistazo, incluso si no planea usarlo.
EDIT 1
nodejs-express-mongoose-demo es muy similar a como tengo estructurado el mío. Echale un vistazo.
Advertencia: al hacer referencia al código que pirateé para nodos knockout, funciona, pero está lejos de ser elegante o pulido.
Para ser más específico sobre la división de app.js
tengo el siguiente archivo app.js
var express = require(''express''),
bootstrap = require(''./init/bootstrap.js''),
app = module.exports = express.createServer();
bootstrap(app);
Esto básicamente significa que pongo todo mi bootstrapping en un archivo separado, luego reinicio el servidor.
Entonces, ¿qué hace 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");
};
Bueno, divide toda la configuración de inicialización del servidor en buenos trozos. Específicamente
- Tengo un fragmento que configura toda mi autenticación OAuth remota con everyauth.
- Tengo un fragmento que configura mi aplicación (básicamente llamando a
app.configure
) - Tengo un poco de código que perfora menos, así que vuelve a compilar cualquiera de mis archivos menos en CSS en tiempo de ejecución.
- Tengo un código que configura todas mis rutas
- Yo llamo a este pequeño módulo nko
- Finalmente, comienzo el servidor escuchando un puerto.
Solo por ejemplo, veamos el archivo de routing
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);
Aquí cargo todos mis modelos y rutas como matrices de archivos.
Descargo de responsabilidad: readdirSync
solo está bien cuando se llama antes de iniciar el servidor http (antes .listen
). Llamar a llamadas de bloqueo sincrónicas al inicio del servidor hace que el código sea más legible (básicamente es un truco)
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);
}
});
Aquí perforo socket.io para usar la autorización en lugar de permitir que tom y jack hablen con mi servidor socket.io
routes.forEach(function(file) {
var route = require(routeUrl + file),
model = require(modelUrl + file);
route(app, model, io);
});
};
Aquí empiezo mis rutas pasando el modelo relevante a cada objeto de ruta devuelto desde el archivo de ruta.
Básicamente, el problema es que organizas todo en pequeños módulos y luego tienes algún mecanismo de arranque.
Mi otro proyecto (mi blog) tiene un archivo init con una estructura similar .
Descargo de responsabilidad: el blog está roto y no se construye, estoy trabajando en ello.