node.js - servidor - ExpressJS ¿Cómo estructurar una aplicación?
servidor con express node (18)
Estoy usando el framework web ExpressJS para NodeJS.
Las personas que usan ExpressJS ponen sus entornos (desarrollo, producción, prueba ...), sus rutas, etc. en app.js
Creo que no es una forma hermosa porque cuando tienes una aplicación grande, ¡app.js es demasiado grande!
Me gustaría tener esta estructura de directorio:
| my-application
| -- app.js
| -- config/
| -- environment.js
| -- routes.js
Aquí está mi código:
app.js
var express = require(''express'');
var app = module.exports = express.createServer();
require(''./config/environment.js'')(app, express);
require(''./config/routes.js'')(app);
app.listen(3000);
config / environment.js
module.exports = function(app, express){
app.configure(function() {
app.use(express.logger());
});
app.configure(''development'', function() {
app.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
});
app.configure(''production'', function() {
app.use(express.errorHandler());
});
};
config / route.js
module.exports = function(app) {
app.get(''/'', function(req, res) {
res.send(''Hello world !'');
});
};
Mi código funciona bien y creo que la estructura de los directorios es hermosa. Sin embargo, el código tuvo que ser adaptado y no estoy seguro de que sea bueno / hermoso.
¿Es mejor usar mi estructura de directorios y adaptar el código o simplemente usar un archivo (app.js)?
¡Gracias por tus consejos!
1) El sistema de archivos de su proyecto Express tal como:
/ ...
/lib
/node_modules
/public
/views
app.js
config.json
package.json
app.js - tu contenedor global de aplicaciones
2) Archivo principal del módulo (lib / mymodule / index.js):
var express = require(''express'');
var app = module.exports = express();
// and load module dependencies ...
// this place to set module settings
app.set(''view engine'', ''jade'');
app.set(''views'', __dirname + ''/views'');
// then do module staff
app.get(''/mymodule/route/'',function(req,res){ res.send(''module works!'') });
3) Conectar módulo en app.js principal
...
var mymodule = require(''mymodule'');
app.use(mymodule);
4) Lógica de muestra
lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
/api/
...
lib/
/admin/
/users/
/settings/
/groups/
...
- Lo mejor para probar
- Mejor para la escala
- Separa depende por módulo
- Agrupación de rutas por funcionalidad (o módulos).
dice / muestra en Vimeo una idea interesante de cómo modularizar la aplicación Express - Aplicaciones web modulares con Node.js y Express . Potente y simple.
Bien, ha pasado un tiempo y esta es una pregunta popular, así que seguí adelante y creé un repositorio de github de andamios con código JavaScript y un largo README sobre cómo me gusta estructurar una aplicación express.js de tamaño mediano.
focusaurus/express_code_structure es el repositorio con el último código para esto. Tire de las solicitudes de bienvenida.
Aquí hay una instantánea del archivo README ya que no le gustan las respuestas de solo un enlace. Haré algunas actualizaciones ya que este es un nuevo proyecto que continuaré actualizando, pero en última instancia, el repositorio de github será el lugar actualizado para esta información.
Estructura de código Express
Este proyecto es un ejemplo de cómo organizar una aplicación web express.js de tamaño mediano.
Actual al menos expreso v4.14 diciembre 2016
¿Qué tan grande es tu aplicación?
Las aplicaciones web no son todas iguales, y no hay, en mi opinión, una estructura de código única que deba aplicarse a todas las aplicaciones express.js.
Si su aplicación es pequeña, no necesita una estructura de directorios tan profunda como se ejemplifica aquí. Simplemente manténgalo simple y pegue un puñado de archivos .js
en la raíz de su repositorio y listo. Voilà.
Si su aplicación es enorme, en algún momento deberá dividirla en distintos paquetes npm. En general, el enfoque de node.js parece favorecer a muchos paquetes pequeños, al menos para las bibliotecas, y debe crear su aplicación utilizando varios paquetes npm, ya que esto comienza a tener sentido y justifica la sobrecarga. Entonces, a medida que su aplicación crece y alguna parte del código se vuelve claramente reutilizable fuera de su aplicación o es un subsistema claro, muévalo a su propio repositorio git y conviértalo en un paquete npm independiente.
Así que el enfoque de este proyecto es ilustrar una estructura viable para una aplicación de tamaño mediano.
¿Cuál es su arquitectura en general?
Hay muchos enfoques para construir una aplicación web, como
- Server Side MVC a la Ruby on Rails
- Estilo de aplicación de una sola página a la MongoDB / Express / Angular / Node (MEAN)
- Sitio web básico con algunas formas.
- El estilo de Modelos / Operaciones / Vistas / Eventos a la MVC está muerto, es hora de MOVERSE
- y muchos otros tanto actuales como históricos.
Cada uno de estos encaja perfectamente en una estructura de directorio diferente. Para los propósitos de este ejemplo, es solo un andamio y no una aplicación que funcione completamente, pero asumo los siguientes puntos clave de la arquitectura:
- El sitio tiene algunas páginas / plantillas estáticas tradicionales.
- La parte de "aplicación" del sitio se desarrolla como un estilo de aplicación de una sola página.
- La aplicación expone una API de estilo REST / JSON al navegador
- La aplicación modela un dominio empresarial simple, en este caso, es una aplicación de concesionario de automóviles.
¿Y qué pasa con Ruby on Rails?
Será un tema a lo largo de este proyecto que muchas de las ideas incorporadas en Ruby on Rails y las decisiones de la "Convención sobre la Configuración" que han adoptado, aunque son ampliamente aceptadas y utilizadas, no son realmente útiles y, a veces, son lo contrario de lo que este repositorio recomienda.
Mi punto principal aquí es que existen principios subyacentes para organizar el código, y en base a esos principios, las convenciones de Ruby on Rails tienen sentido (en su mayoría) para la comunidad de Ruby on Rails. Sin embargo, el mero hecho de imitar esas convenciones pierde el sentido. Una vez que haya asimilado los principios básicos, TODOS sus proyectos estarán bien organizados y claros: scripts de shell, juegos, aplicaciones móviles, proyectos empresariales, incluso su directorio principal.
Para la comunidad de Rails, desean poder tener un solo desarrollador de Rails que cambie de aplicación en aplicación y estar familiarizado y cómodo con él cada vez. Esto tiene mucho sentido si tiene 37 señales o Pivotal Labs, y tiene beneficios. En el mundo de JavaScript del lado del servidor, el espíritu general es mucho más salvaje del oeste, y no tenemos ningún problema con eso. Así es como nosotros lo hacemos. Estamos acostumbrados a ello. Incluso dentro de Express.js, es un pariente cercano de Sinatra, no de Rails, y tomar convenciones de Rails generalmente no ayuda en nada. Incluso diría Principios sobre la Convención sobre la Configuración .
Principios y Motivaciones Subyacentes
- Ser mentalmente manejable
- El cerebro solo puede tratar y pensar en un pequeño número de cosas relacionadas al mismo tiempo. Por eso utilizamos directorios. Nos ayuda a lidiar con la complejidad al concentrarnos en pequeñas porciones.
- Sea del tamaño apropiado
- No cree "Directorios de Mansion" donde solo hay 1 archivo de solo 3 directorios hacia abajo. Puede ver que esto sucede en Ansible Best Practices, que confunde proyectos pequeños para crear más de 10 directorios con capacidad para más de 10 archivos cuando 1 directorio con 3 archivos sería mucho más apropiado. No conduzca un autobús para ir al trabajo (a menos que sea un conductor de autobús, pero incluso entonces está manejando un autobús para NO trabajar), así que no cree estructuras de sistemas de archivos que no estén justificadas por los archivos reales que contienen. .
- Ser modular pero pragmático.
- La comunidad de nodos en general prefiere pequeños módulos. Cualquier cosa que se pueda separar completamente de su aplicación debe extraerse en un módulo para uso interno o publicarse públicamente en npm. Sin embargo, para las aplicaciones de tamaño mediano que son el alcance aquí, la sobrecarga de esto puede agregar tedio a su flujo de trabajo sin un valor proporcional. Por lo tanto, para el momento en que tenga algún código que se haya factorizado pero no sea suficiente para justificar un módulo npm completamente independiente, simplemente considérelo un " proto-módulo " con la expectativa de que cuando se cruce un umbral de tamaño, se extraerá.
- Algunas personas como @hij1nx incluso incluyen un directorio
app/node_modules
y tienen archivospackage.json
en los directorios de proto-módulos para facilitar esa transición y actuar como un recordatorio.
- Ser fácil de localizar código
- Dada una característica para construir o un error para corregir, nuestro objetivo es que un desarrollador no tenga problemas para localizar los archivos de origen involucrados.
- Los nombres son significativos y precisos
- El código crufty se elimina completamente, no se deja en un archivo huérfano o simplemente se comenta
- Ser amigable con las búsquedas
- todo el código fuente de la primera parte está en el directorio de la
app
, de modo que puede hacercd
ejecutar run / grep / xargs / ag / ack / etc y no ser distraído por coincidencias de terceros
- todo el código fuente de la primera parte está en el directorio de la
- Use nombres simples y obvios
- npm ahora parece requerir nombres de paquetes en minúsculas. Lo encuentro en su mayoría terrible, pero debo seguir la manada, por lo tanto, los nombres de archivos deben usar
kebab-case
, aunque el nombre de la variable para JavaScript debe sercamelCase
porque-
es un signo menos en JavaScript. - el nombre de la variable coincide con el nombre base de la ruta del módulo, pero con
kebab-case
transformado acamelCase
- npm ahora parece requerir nombres de paquetes en minúsculas. Lo encuentro en su mayoría terrible, pero debo seguir la manada, por lo tanto, los nombres de archivos deben usar
- Agrupar por acoplamiento, no por función
- Esta es una salida importante de la convención de
app/views
,app/controllers
,app/models
Ruby on Rails, etc. - Las características se agregan a una pila completa, por lo que quiero centrarme en una pila completa de archivos que son relevantes para mi característica. Cuando agrego un campo de número de teléfono al modelo de usuario, no me importa ningún controlador que no sea el controlador de usuario, y no me importa ningún otro modelo que no sea el modelo de usuario.
- Entonces, en lugar de editar 6 archivos que están en su propio directorio e ignorar toneladas de otros archivos en esos directorios, este repositorio está organizado de tal manera que todos los archivos que necesito para construir una característica están colocados
- Por la naturaleza de MVC, la vista de usuario está acoplada al controlador de usuario que está acoplado al modelo de usuario. Entonces, cuando cambio el modelo de usuario, esos 3 archivos a menudo cambian juntos, pero el controlador de transacciones o el controlador del cliente están desacoplados y, por lo tanto, no están involucrados. Lo mismo se aplica a los diseños que no son MVC por lo general también.
- El estilo MVC o MOVE se desacopla en términos de qué código va en qué módulo aún se recomienda, pero la distribución de los archivos MVC en directorios de hermanos es una molestia.
- Así, cada uno de mis archivos de rutas tiene la porción de las rutas que posee. Un archivo de
routes.rb
estiloroutes.rb
es muy útil si desea obtener una visión general de todas las rutas en la aplicación, pero cuando en realidad está creando características y corrigiendo errores, solo le interesan las rutas relevantes para la pieza que está cambiando.
- Esta es una salida importante de la convención de
- Almacenar las pruebas junto al código.
- Esto es solo una instancia de "agrupar por acoplamiento", pero quería llamarlo específicamente. He escrito muchos proyectos en los que las pruebas se realizan bajo un sistema de archivos paralelo llamado "pruebas" y ahora que comencé a colocar mis pruebas en el mismo directorio que su código correspondiente, nunca volveré. Esto es más modular y mucho más fácil de trabajar en los editores de texto y alivia un montón de tonterías "../../ ..". Si tiene dudas, pruébelo en algunos proyectos y decida usted mismo. No voy a hacer nada más allá de esto para convencerte de que es mejor.
- Reducir el acoplamiento transversal con los eventos.
- Es fácil pensar "OK, cada vez que se crea un nuevo acuerdo, deseo enviar un correo electrónico a todos los vendedores", y luego simplemente coloque el código para enviar esos correos electrónicos en la ruta que crea acuerdos.
- Sin embargo, este acoplamiento eventualmente convertirá tu aplicación en una bola de barro gigante.
- En su lugar, DealModel debería simplemente disparar un evento "crear" y no ser consciente de qué otra cosa podría hacer el sistema en respuesta a eso.
- Cuando se codifica de esta manera, es mucho más posible colocar todo el código relacionado con el usuario en la
app/users
porque no hay un nido de lógica de negocios acoplada en todo el lugar que contamina la pureza de la base del código de usuario.
- El flujo de código es seguir
- No hagas cosas mágicas. No cargue automáticamente archivos desde directorios mágicos en el sistema de archivos. No seas rieles. La aplicación comienza en
app/server.js:1
y puedes ver todo lo que carga y ejecuta siguiendo el código. - No hagas DSL para tus rutas. No hagas una metaprogramación tonta cuando no se requiere.
- Si su aplicación es tan grande que hacer
magicRESTRouter.route(somecontroller, {except: ''POST''})
es una gran victoria para usted sobre 3app.get
básica,app.put
,app.del
, llamadas, probablemente esté construyendo una aplicación monolítica que es demasiado grande para trabajar con eficacia. Disfrute de las grandes ganancias, no para convertir 3 líneas simples en 1 línea compleja.
- No hagas cosas mágicas. No cargue automáticamente archivos desde directorios mágicos en el sistema de archivos. No seas rieles. La aplicación comienza en
Usa nombres de archivo de kebabs inferiores
- Este formato evita problemas de sensibilidad de mayúsculas y minúsculas en el sistema de archivos en todas las plataformas
- npm prohíbe mayúsculas en los nuevos nombres de paquetes, y esto funciona bien con eso
específicos de express.js
No utilice
app.configure
. Es casi completamente inútil y simplemente no lo necesitas. Está en un montón de repetitivo debido a copypasta sin sentido.- LA ORDEN DE MIDDLEWARE Y LAS RUTAS EN MATERIA EXPRESA !!!
- Casi todos los problemas de enrutamiento que veo en son middleware express fuera de orden
- En general, usted desea que sus rutas estén desacopladas y que no confíen tanto en el pedido.
- No use
app.use
para su aplicación completa si realmente solo necesita ese middleware para 2 rutas (lo estoy viendo,body-parser
) - Asegúrese de que cuando todo esté dicho y hecho tenga EXACTAMENTE este orden:
- Cualquier middleware de aplicación super importante
- Todas sus rutas y middlewares de rutas variadas.
- ENTONCES manejadores de errores
- Lamentablemente, al estar inspirado en sinatra, express.js generalmente asume que todas sus rutas estarán en
server.js
y quedará claro cómo se ordenan. Para una aplicación de tamaño mediano, dividir las cosas en módulos de rutas separadas es bueno, pero sí implica un peligro de middleware fuera de orden
La aplicación del enlace simbólico truco
Hay muchos enfoques descritos y discutidos en detalle por la comunidad en el gran sentido local. Mejor requiere () rutas para Node.js. Es posible que pronto decida preferir "simplemente tratar con un montón de ../../../ .." o usar el requireFrom requireFrom. Sin embargo, en este momento, he estado usando el truco del enlace simbólico que se detalla a continuación.
Por lo tanto, una forma de evitar las necesidades internas del proyecto con rutas relativas molestas como require("../../../config")
es usar el siguiente truco:
- crea un enlace simbólico bajo node_modules para tu aplicación
- cd node_modules && ln -nsf ../app
- añada solo el enlace simbólico node_modules / app , no toda la carpeta node_modules, a git
- git add -f node_modules / app
- Sí, todavía debe tener "node_modules" en su archivo
.gitignore
- No, no debes poner "node_modules" en tu repositorio de git. Algunas personas te recomendarán que hagas esto. Son incorrectos
- Ahora puede requerir módulos dentro del proyecto usando este prefijo
-
var config = require("app/config");
-
var DealModel = require("app/deals/deal-model")
;
-
- Básicamente, esto hace que el trabajo dentro del proyecto requiera un trabajo muy similar al requerido para los módulos npm externos.
- Lo sentimos, los usuarios de Windows, deben atenerse a las rutas relativas del directorio principal.
Configuración
Generalmente, los módulos de código y las clases esperan que solo se pase un objeto de options
JavaScript básico. Solo app/server.js
debe cargar el módulo app/config.js
. A partir de ahí, puede sintetizar pequeños objetos de options
para configurar subsistemas según sea necesario, pero el acoplamiento de cada subsistema a un gran módulo de configuración global lleno de información adicional es un mal acoplamiento.
Intente centralizar la creación de conexiones de base de datos y transfiéralas a los subsistemas en lugar de pasar parámetros de conexión y hacer que los subsistemas realicen las conexiones salientes.
NODE_ENV
Esta es otra idea atractiva pero terrible transmitida desde Rails. Debe haber exactamente 1 lugar en su aplicación, app/config.js
que NODE_ENV
la variable de entorno NODE_ENV
. Todo lo demás debería tomar una opción explícita como un argumento de constructor de clase o parámetro de configuración del módulo.
Si el módulo de correo electrónico tiene una opción sobre cómo enviar correos electrónicos (SMTP, iniciar sesión en stdout, poner en cola, etc.), debería elegir una opción como {deliver: ''stdout''}
pero no debería verificar NODE_ENV
.
Pruebas
Ahora guardo mis archivos de prueba en el mismo directorio que su código correspondiente y uso las convenciones de nombres de extensión de nombre de archivo para distinguir las pruebas del código de producción.
-
foo.js
tiene el módulo "foo" código de -
foo.tape.js
tiene las pruebas basadas en nodos para foo y vive en el mismo directorio -
foo.btape.js
puede usarse para pruebas que deben ejecutarse en un entorno de navegador
Yo uso globs del sistema de archivos y el find . -name ''*.tape.js''
find . -name ''*.tape.js''
para obtener acceso a todas mis pruebas según sea necesario.
Cómo organizar el código dentro de cada archivo de módulo .js
El alcance de este proyecto es principalmente acerca de dónde van los archivos y directorios, y no quiero agregar otro alcance, pero solo mencionaré que organizo mi código en 3 secciones distintas.
- El bloque de apertura de CommonJS requiere llamadas a dependencias estatales
- Bloque de código principal de JavaScript puro. No hay contaminación de CommonJS aquí. No haga referencia a exportaciones, módulo, o requiera.
- Bloque de cierre de CommonJS para configurar exportaciones.
Bueno, puse mis rutas como un archivo json, que leí al principio, y en un bucle for en app.js configuré las rutas. Route.json incluye a qué vista debe llamarse y la clave para los valores que se enviarán a la ruta.
Esto funciona para muchos casos simples, pero tuve que crear manualmente algunas rutas para casos especiales.
Creo que es una gran manera de hacerlo. No se limita a expresar, pero he visto bastantes proyectos de node.js en github haciendo lo mismo. Se eliminan los parámetros de configuración + los módulos más pequeños (en algunos casos, cada URI) se factorizan en archivos separados.
Recomendaría ir a través de proyectos expresos específicos en github para tener una idea. OMI, la forma en que estás haciendo es correcta.
Esto puede ser de interés:
https://github.com/flatiron/nconf
Configuración jerárquica de node.js con archivos, variables de entorno, argumentos de línea de comandos y fusión de objetos atómicos.
Ha pasado bastante tiempo desde la última respuesta a esta pregunta y Express también lanzó recientemente la versión 4, que agregó algunas cosas útiles para organizar la estructura de la aplicación.
A continuación se encuentra una publicación de blog actualizada sobre las mejores prácticas sobre cómo estructurar su aplicación Express. http://www.terlici.com/2014/08/25/best-practices-express-structure.html
También hay un repositorio de GitHub que aplica el consejo en el artículo. Siempre está al día con la última versión Express.
https://github.com/terlici/base-express
He escrito un post exactamente sobre este asunto. Básicamente hace uso de un routeRegistrar
que recorre los archivos en la carpeta /controllers
llaman a su función init
. La función init
toma la variable de app
Express como un parámetro para que pueda registrar sus rutas de la forma que desee.
var fs = require("fs");
var express = require("express");
var app = express();
var controllersFolderPath = __dirname + "/controllers/";
fs.readdirSync(controllersFolderPath).forEach(function(controllerName){
if(controllerName.indexOf("Controller.js") !== -1){
var controller = require(controllersFolderPath + controllerName);
controller.init(app);
}
});
app.listen(3000);
La siguiente es la respuesta literal de Peter Lyons, transferida a vanilla JS de Coffeescript, según lo solicitado por varios otros. La respuesta de Peter es muy capaz, y cualquiera que vote mi respuesta también debería votar la suya.
Config
Lo que estás haciendo está bien. Me gusta tener mi propio espacio de nombres de configuración configurado en un archivo config.js
nivel config.js
con un espacio de nombres anidado como este.
// Set the current environment to true in the env object
var currentEnv = process.env.NODE_ENV || ''development'';
exports.appName = "MyApp";
exports.env = {
production: false,
staging: false,
test: false,
development: false
};
exports.env[currentEnv] = true;
exports.log = {
path: __dirname + "/var/log/app_#{currentEnv}.log"
};
exports.server = {
port: 9600,
// In staging and production, listen loopback. nginx listens on the network.
ip: ''127.0.0.1''
};
if (currentEnv != ''production'' && currentEnv != ''staging'') {
exports.enableTests = true;
// Listen on all IPs in dev/test (for testing from other machines)
exports.server.ip = ''0.0.0.0'';
};
exports.db {
URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"
};
Esto es amigable para la edición sysadmin. Entonces cuando necesito algo, como la información de conexión de DB, es
require(''./config'').db.URL
Rutas / Controladores
Me gusta dejar mis rutas con mis controladores y organizarlos en un subdirectorio de app/controllers
. Luego puedo cargarlos y dejar que agreguen las rutas que necesiten.
En mi app/server.js
archivo javascript hago:
[
''api'',
''authorization'',
''authentication'',
''domains'',
''users'',
''stylesheets'',
''javascripts'',
''tests'',
''sales''
].map(function(controllerName){
var controller = require(''./controllers/'' + controllerName);
controller.setup(app);
});
Así que tengo archivos como:
app/controllers/api.js
app/controllers/authorization.js
app/controllers/authentication.js
app/controllers/domains.js
Y, por ejemplo, en mi controlador de dominios, tengo una función de setup
como esta.
exports.setup = function(app) {
var controller = new exports.DomainController();
var route = ''/domains'';
app.post(route, controller.create);
app.put(route, api.needId);
app.delete(route, api.needId);
route = ''/domains/:id'';
app.put(route, controller.loadDomain, controller.update);
app.del(route, controller.loadDomain, function(req, res){
res.sendJSON(req.domain, status.OK);
});
}
Puntos de vista
Poner vistas en la app/views
está convirtiendo en el lugar habitual. Lo planteo así.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Archivos estáticos
Ir en un subdirectorio public
.
Github / Semver / NPM
Coloque un archivo de rebajas README.md en su raíz de git repo para github.
Coloque un archivo package.json con un número de versión semántica en su raíz de git repo para NPM.
Me gusta usar una "aplicación" global, en lugar de exportar una función, etc.
Mi pregunta se introdujo en abril de 2011, es bastante viejo. Durante este tiempo, podría mejorar mi experiencia con Express.js y cómo crear una arquitectura de una aplicación escrita con esta biblioteca. Entonces, comparto aquí mi experiencia.
Aquí está mi estructura de directorio:
├── app.js // main entry
├── config // The configuration of my applications (logger, global config, ...)
├── models // The model data (e.g. Mongoose model)
├── public // The public directory (client-side code)
├── routes // The route definitions and implementations
├── services // The standalone services (Database service, Email service, ...)
└── views // The view rendered by the server to the client (e.g. Jade, EJS, ...)
App.js
El objetivo del archivo app.js
es arrancar la aplicación expressjs. Carga el módulo de configuración, el módulo de registrador, espera la conexión de la base de datos, ... y ejecuta el servidor Express.
''use strict'';
require(''./config'');
var database = require(''./services/database'');
var express = require(''express'');
var app = express();
module.exports = app;
function main() {
var http = require(''http'');
// Configure the application.
app.configure(function () {
// ... ... ...
});
app.configure(''production'', function () {
// ... ... ...
});
app.configure(''development'', function () {
// ... ... ...
});
var server = http.createServer(app);
// Load all routes.
require(''./routes'')(app);
// Listen on http port.
server.listen(3000);
}
database.connect(function (err) {
if (err) {
// ...
}
main();
});
rutas /
El directorio de rutas tiene un archivo index.js
. Su objetivo es introducir un tipo de magia para cargar todos los demás archivos dentro del directorio de routes/
. Aquí está la implementación:
/**
* This module loads dynamically all routes modules located in the routes/
* directory.
*/
''use strict'';
var fs = require(''fs'');
var path = require(''path'');
module.exports = function (app) {
fs.readdirSync(''./routes'').forEach(function (file) {
// Avoid to read this current file.
if (file === path.basename(__filename)) { return; }
// Load the route file.
require(''./'' + file)(app);
});
};
Con ese módulo, crear una nueva definición de ruta e implementación es realmente fácil. Por ejemplo, hello.js
:
function hello(req, res) {
res.send(''Hello world'');
}
module.exports = function (app) {
app.get(''/api/hello_world'', hello);
};
Cada módulo de ruta es independiente .
No creo que sea un buen enfoque para agregar rutas a la configuración. Una mejor estructura podría ser algo como esto:
application/
| - app.js
| - config.js
| - public/ (assets - js, css, images)
| - views/ (all your views files)
| - libraries/ (you can also call it modules/ or routes/)
| - users.js
| - products.js
| - etc...
Por lo tanto, products.js y users.js contendrán todas sus rutas dentro de las cuales toda la lógica.
ahora es Finales de 2015 y después de desarrollar mi estructura durante 3 años y en proyectos pequeños y grandes. ¿Conclusión?
No hagas un MVC grande, sino que lo separas en módulos
Asi que...
¿Por qué?
Por lo general, uno trabaja en un módulo (por ejemplo, Productos), que puede cambiar de forma independiente.
Eres capaz de reutilizar módulos
Eres capaz de probarlo por separado
Eres capaz de reemplazarlo por separado
Tienen interfaces claras (estables).
-A más tardar, si hubiera varios desarrolladores trabajando, la separación de módulos ayuda
El proyecto nodebootstrap tiene un enfoque similar a mi estructura final. ( github )
¿Cómo se ve esta estructura?
Módulos pequeños, encapsulados , cada uno con MVC separado
Cada módulo tiene un package.json
Pruebas como parte de la estructura (en cada módulo)
Configuración global , bibliotecas y servicios.
Docker integrado, Cluster, para siempre
Folderoverview (ver carpeta lib para módulos):
http://locomotivejs.org/ proporciona una forma de estructurar una aplicación creada con Node.js y Express.
Desde el sitio web:
"Locomotive es un marco web para Node.js. Locomotive admite patrones MVC, rutas RESTful y convención sobre la configuración, al tiempo que se integra a la perfección con cualquier base de datos y motor de plantillas. Locomotive se basa en Express, conservando la potencia y la simplicidad que espera. desde el nodo ".
ACTUALIZACIÓN (2013-10-29) : Por favor, vea también mi otra respuesta, que tiene JavaScript en lugar de CoffeeScript por demanda popular, así como un repositorio de github y un README extenso que detalla mis últimas recomendaciones sobre este tema.
Config
Lo que estás haciendo está bien. Me gusta tener mi propio espacio de nombres de configuración configurado en un archivo config.coffee
nivel config.coffee
con un espacio de nombres anidado como este.
#Set the current environment to true in the env object
currentEnv = process.env.NODE_ENV or ''development''
exports.appName = "MyApp"
exports.env =
production: false
staging: false
test: false
development: false
exports.env[currentEnv] = true
exports.log =
path: __dirname + "/var/log/app_#{currentEnv}.log"
exports.server =
port: 9600
#In staging and production, listen loopback. nginx listens on the network.
ip: ''127.0.0.1''
if currentEnv not in [''production'', ''staging'']
exports.enableTests = true
#Listen on all IPs in dev/test (for testing from other machines)
exports.server.ip = ''0.0.0.0''
exports.db =
URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"
Esto es amigable para la edición sysadmin. Entonces cuando necesito algo, como la información de conexión de DB, es
require(''./config'').db.URL
Rutas / Controladores
Me gusta dejar mis rutas con mis controladores y organizarlos en un subdirectorio de app/controllers
. Luego puedo cargarlos y dejar que agreguen las rutas que necesiten.
En mi app/server.coffee
coffeescript archivo que hago:
[
''api''
''authorization''
''authentication''
''domains''
''users''
''stylesheets''
''javascripts''
''tests''
''sales''
].map (controllerName) ->
controller = require ''./controllers/'' + controllerName
controller.setup app
Así que tengo archivos como:
app/controllers/api.coffee
app/controllers/authorization.coffee
app/controllers/authentication.coffee
app/controllers/domains.coffee
Y, por ejemplo, en mi controlador de dominios, tengo una función de setup
como esta.
exports.setup = (app) ->
controller = new exports.DomainController
route = ''/domains''
app.post route, controller.create
app.put route, api.needId
app.delete route, api.needId
route = ''/domains/:id''
app.put route, controller.loadDomain, controller.update
app.del route, controller.loadDomain, exports.delete
app.get route, controller.loadDomain, (req, res) ->
res.sendJSON req.domain, status.OK
Puntos de vista
Poner vistas en la app/views
está convirtiendo en el lugar habitual. Lo planteo así.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Archivos estáticos
Ir en un subdirectorio public
.
Github / Semver / NPM
Coloque un archivo de rebajas README.md en su raíz de git repo para github.
Coloque un archivo package.json con un número de versión semántica en su raíz de git repo para NPM.
Así es como se ve la mayor parte de mi estructura de directorios de proyectos Express.
Por lo general hago una express dirname
para inicializar el proyecto, perdona mi pereza, pero es muy flexible y extensible. PD: necesitas obtener express-generator
eso (para aquellos que lo buscan sudo npm install -g express-generator
, sudo porque lo estás instalando globalmente)
|-- bin
|-- www //what we start with "forever"
|-- bower_components
|-- models
|-- database.js
|-- model1.js //not this exact name ofcourse.
|-- .
|-- node_modules
|-- public
|-- images
|-- javascripts
|-- controllers
|-- directives
|-- services
|-- app.js
|-- init.js //contains config and used for initializing everything, I work with angular a lot.
|-- stylesheets
|-- routes
|-- some
|-- hierarchy
.
.
|-- views
|-- partials
|-- content
|-- .env
|-- .env.template
|-- app.js
|-- README.md
Usted debe preguntarse por qué archivos .env? ¡Porque funcionan! ¡Utilizo el dotenv
módulo en mis proyectos (mucho recientemente) y funciona! Pop en estas 2 declaraciones en app.js
owww
var dotenv = require(''dotenv'');
dotenv.config({path: path.join(__dirname + "/.env")});
Y otra línea para configurar rápidamente /bower_components
para servir contenido estático bajo el recurso/ext
app.use(''/ext'', express.static(path.join(__dirname, ''bower_components'')));
Probablemente puede ser adecuado para las personas que buscan utilizar Express y Angular juntas, o simplemente expresar sin esa javascripts
jerarquía, por supuesto.
Estoy dando la estructura de carpetas de estilo MVC, por favor encontrar a continuación.
Utilizamos la siguiente estructura de carpetas para nuestras aplicaciones web grandes y medianas.
myapp
|
|
|____app
| |____controllers
| | |____home.js
| |
| |____models
| | |___home.js
| |
| |____views
| |___404.ejs
| |___error.ejs
| |___index.ejs
| |___login.ejs
| |___signup.ejs
|
|
|_____config
| |___auth.js
| |___constants.js
| |___database.js
| |___passport.js
| |___routes.js
|
|
|____lib
| |___email.js
|
|____node_modules
|
|
|____public.js
| |____css
| | |__style.css
| |
| |____js
| | |__script.js
| |
| |____img
| | |__img.jpg
| |
| |
| |____uploads
| |__img.jpg
|
|
|
|_____app.js
|
|
|
|_____package.json
He creado un módulo npm para el estructurador de carpetas mvc de express express.
Por favor, busque el siguiente https://www.npmjs.com/package/express-mvc-generator
Solo pasos simples para generar y usar estos módulos.
i) instalar el módulo npm install express-mvc-generator -g
ii) comprobar opciones express -h
iii) Generar estructura express mvc express myapp
iv) Instalar dependencias npm install
:
v) Abra su config / database.js, configure su db mongo.
vi) Ejecutar la aplicación node app
onodemon app
vii) Revisar la URL http://localhost:8042/signup O http://yourip:8042/signup
Recientemente he adoptado módulos como mini-aplicaciones independientes.
|-- src
|--module1
|--module2
|--www
|--img
|--js
|--css
|--#.js
|--index.ejs
|--module3
|--www
|--bower_components
|--img
|--js
|--css
|--#.js
|--header.ejs
|--index.ejs
|--footer.ejs
Ahora para cualquier módulo de enrutamiento (# .js), las vistas (* .ejs), js, css y los activos están uno al lado del otro. El enrutamiento de submódulos se configura en el # .js principal con dos líneas adicionales
router.use(''/module2'', opt_middleware_check, require(''./module2/#''));
router.use(express.static(path.join(__dirname, ''www'')));
De esta manera, incluso los sub-submódulos son posibles.
No te olvides de configurar la vista en el directorio src
app.set(''views'', path.join(__dirname, ''src''));
Mi estructura expresa 4. https://github.com/odirleiborgert/borgert-express-boilerplate
Paquetes
View engine: twig
Security: helmet
Flash: express-flash
Session: express-session
Encrypt: bcryptjs
Modules: express-load
Database: MongoDB
ORM: Mongoose
Mongoose Paginate
Mongoose Validator
Logs: winston + winston-daily-rotate-file
Nodemon
CSS: stylus
Eslint + Husky
Estructura
|-- app
|-- controllers
|-- helpers
|-- middlewares
|-- models
|-- routes
|-- services
|-- bin
|-- logs
|-- node_modules
|-- public
|-- components
|-- images
|-- javascripts
|-- stylesheets
|-- views
|-- .env
|-- .env-example
|-- app.js
|-- README.md