Estructuración de proyectos
Cuando comencé a crear aplicaciones Node & Express, no sabía lo importante que era estructurar su aplicación. Express no viene con reglas o pautas estrictas para mantener la estructura del proyecto.
Eres libre de usar cualquier estructura que quieras. Cuando su código base crece, termina teniendo route
manejadores largos . Esto hace que su código sea difícil de entender y contiene errores potenciales.
Si está trabajando para una startup, la mayoría de las veces no tendrá tiempo para refractar su proyecto o modularizarlo. Puede terminar con un ciclo interminable de corrección de errores y parches.
Con el tiempo, mientras trabajaba con equipos pequeños y grandes, me di cuenta de qué tipo de estructura puede crecer con su proyecto y seguir siendo fácil de mantener.
Controlador de vista de modelo
El patrón MVC ayuda en un desarrollo rápido y paralelo. Por ejemplo, un desarrollador puede trabajar en la vista, mientras que otro puede trabajar en la creación de la lógica empresarial en el controlador.
Echemos un vistazo a un ejemplo de una aplicación CRUD de usuario simple.
project/ controllers/ users.js util/ plugin.js middlewares/ auth.js models/ user.js routes/ user.js router.js public/ js/ css/ img/ views/ users/ index.jade tests/ users/ create-user-test.js update-user-test.js get-user-test.js .gitignore app.js package.json
- controladores: defina los controladores de ruta de su aplicación y la lógica empresarial
- util: escribe aquí funciones de utilidad / ayuda que pueden ser utilizadas por cualquier controlador. Por ejemplo, puede escribir una función como
mergeTwoArrays(arr1, arr2)
. - middlewares: puede escribir middlewares para interpretar todas las solicitudes entrantes antes de pasar al controlador de ruta. Por ejemplo,
router.post('/login', auth, controller.login)
dondeauth
es una función de middleware definida enmiddlewares/auth.js
. - modelos: también una especie de middleware entre su controlador y la base de datos. Puede definir un esquema y realizar alguna validación antes de escribir en la base de datos. Por ejemplo, puede usar un ORM como Mongoose, que viene con excelentes funciones y métodos para usar en el esquema mismo.
- rutas: defina las rutas de su aplicación, con métodos HTTP. Por ejemplo, puede definir todo lo relacionado con el usuario.
router.post('/users/create', controller.create) router.put('/users/:userId', controller.update) router.get('/users', controller.getAll)
- público: almacena imágenes estáticas en
/img
archivos JavaScript personalizados y CSS/css
- vistas: Contiene plantillas para ser renderizadas por el servidor.
- tests: Aquí puede escribir todas las pruebas unitarias o pruebas de aceptación para el servidor API.
- app.js: actúa como el archivo principal del proyecto donde inicializa la aplicación y otros elementos del proyecto.
- package.json: se encarga de las dependencias, los scripts para ejecutar con el
npm
comando y la versión de su proyecto.
Excepciones y manejo de errores
Este es uno de los aspectos más importantes a tener en cuenta a la hora de crear cualquier proyecto con cualquier idioma. Veamos cómo manejar errores y excepciones con elegancia en una aplicación Express.
Usando promesas
Una de las ventajas de usar promesas sobre devoluciones de llamada es que pueden manejar excepciones / errores implícitos o explícitos en bloques de código asíncrono, así como para el código síncrono definido en .then()
una devolución de llamada de promesa.
Solo agregue .catch(next)
al final de la cadena de promesas. Por ejemplo:
router.post('/create', (req, res, next) => { User.create(req.body) // function to store user data in db .then(result => { // do something with result return result }) .then(user => res.json(user)) .catch(next) })
Usando try-catch
Try-catch es una forma tradicional de detectar excepciones en código asincrónico.
Echemos un vistazo a un ejemplo con la posibilidad de obtener una excepción:
router.get('/search', (req, res) => { setImmediate(() => { const jsonStr = req.query.params try { const jsonObj = JSON.parse(jsonStr) res.send('Success') } catch (e) { res.status(400).send('Invalid JSON string') } }) })
Evite el uso de código síncrono
Código síncrono también conocido como código de bloqueo, porque bloquea la ejecución hasta que se ejecutan.
Por lo tanto, evite el uso de funciones o métodos síncronos que pueden tardar milisegundos o microsegundos. Para un sitio web de alto tráfico, se agravará y puede conducir a una alta latencia o tiempo de respuesta de las solicitudes de la API.
No los use en producción especialmente :)
Muchos módulos de Node.js vienen con métodos .sync
y .async
, así que use async en producción.
Pero, si aún desea usar una API síncrona, use la --trace-sync-io
marca de línea de comandos. Imprimirá una advertencia y un seguimiento de la pila cada vez que su aplicación use una API síncrona.
Para obtener más información sobre los fundamentos del manejo de errores, consulte:
- Manejo de errores en Node.js
- Creación de aplicaciones de nodo robustas: manejo de errores (blog StrongLoop)
uncaughtException
evento, emitido cuando una excepción burbujea hasta el ciclo del evento. Generalmente no se prefiere su uso.
Registrando correctamente
El registro es esencial para la depuración y la actividad de la aplicación. Se utiliza principalmente con fines de desarrollo. Usamos console.log
y, console.error
pero estas son funciones sincrónicas.
Para fines de depuración
Puedes usar un módulo como debug. Este módulo le permite usar la variable de entorno DEBUG para controlar a qué mensajes de depuración se envían console.err()
, si corresponde.
Para la actividad de la aplicación
Una forma es escribirlos en la base de datos.
Consulte Cómo utilicé los complementos de mangosta para realizar auditorías de mi aplicación.
Another way is to write to a file OR use a logging library like Winston or Bunyan. For a detailed comparison of these two libraries, see the StrongLoop blog post Comparing Winston and Bunyan Node.js Logging.
require(“./../../../../../../”) mess
There are different workarounds for this problem.
If you find any module getting popular and if it has logical independence from the application, you can convert it to private npm module and use it like any other module in package.json.
OR
const path = require('path'); const HOMEDIR = path.join(__dirname,'..','..');
where __dirname
is the built-in variable that names the directory that contains the current file, and ..
,..
is the requisite number of steps up the directory tree to reach the root of the project.
From there it is simply:
const foo = require(path.join(HOMEDIR,'lib','foo')); const bar = require(path.join(HOMEDIR,'lib','foo','bar'));
to load an arbitrary file within the project.
Let me know in the comment below if you have better ideas :)
Set NODE_ENV to “production”
The NODE_ENV environment variable specifies the environment in which an application is running (usually, development or production). One of the simplest things you can do to improve performance is to set NODE_ENV
to “production.”
Setting NODE_ENV to “production” makes Express:
- Cache view templates.
- Cache CSS files generated from CSS extensions.
- Generate less verbose error messages.
Tests indicate that just doing this can improve app performance by a factor of three!
Using Process Manager
For production, you should not simply use node app.j
— if your app crashes, it will be offline until you restart it.
The most popular process managers for Node are:
- StrongLoop Process Manager
- PM2
- Forever
I personally use PM2.
For a feature-by-feature comparison of the three process managers, see //strong-pm.io/compare/. For a more detailed introduction to all three, see Process managers for Express apps.
Run your app in a cluster
In a multi-core system, you can increase the performance of a Node app by many times by launching a cluster of processes.
A cluster runs multiple instances of the app, ideally one instance on each CPU core. This distributes the load and tasks among the instances.
Using Node’s cluster module
Clustering is made possible with Node’s cluster module. This enables a master process to spawn worker processes. It distributes incoming connections among the workers.
However, rather than using this module directly, it’s far better to use one of the many tools out there that do it for you automatically. For example node-pm or cluster-service.
Using PM2
For pm2 you can use cluster directly through a command. For example,
# Start 4 worker processes pm2 start app.js -i 4 # Auto-detect number of available CPUs and start that many worker processes pm2 start app.js -i max
If you encounter any problems, feel free to get in touch or comment below.
I would be happy to help :)
Don’t hesitate to clap if you considered this a worthwhile read!
References: //expressjs.com/en/advanced/best-practice-performance.html
Originally published at 101node.io on September 30, 2018.