Migración a Express 4
Express 4 es un cambio disruptivo respecto a Express 3. Esto significa que una aplicación Express 3 existente no funcionará si actualizas la versión de Express en sus dependencias.
Este artículo cubre:
- Cambios en Express 4.
- Un ejemplo de migración de una aplicación Express 3 a Express 4.
- Actualización al generador de apps de Express 4.
Cambios en Express 4
Hay varios cambios significativos en Express 4:
- Cambios en el núcleo de Express y el sistema de middleware. Se eliminaron las dependencias de Connect y el middleware integrado, por lo que debes añadir el middleware tú mismo.
- Cambios en el sistema de enrutamiento.
- Otros cambios diversos.
Ver también:
Cambios en el núcleo de Express y el sistema de middleware
Express 4 ya no depende de Connect, y elimina todo el middleware integrado
de su núcleo, excepto la función express.static. Esto significa que
Express es ahora un framework web independiente de enrutamiento y middleware, y
el versionado y los lanzamientos de Express no se ven afectados por las actualizaciones de middleware.
Sin middleware integrado, debes añadir explícitamente todo el middleware necesario para ejecutar tu app. Simplemente sigue estos pasos:
- Instala el módulo:
npm install --save <module-name> - En tu app, require el módulo:
require('module-name') - Usa el módulo según su documentación:
app.use( ... )
La siguiente tabla lista el middleware de Express 3 y sus equivalentes en Express 4.
| Express 3 | Express 4 |
|---|---|
express.bodyParser | |
express.compress | compression |
express.cookieSession | cookie-session |
express.cookieParser | cookie-parser |
express.logger | morgan |
express.session | express-session |
express.favicon | serve-favicon |
express.responseTime | response-time |
express.errorHandler | errorhandler |
express.methodOverride | method-override |
express.timeout | connect-timeout |
express.vhost | vhost |
express.csrf | csurf |
express.directory | serve-index |
express.static | serve-static |
Aquí está la lista completa del middleware de Express 4.
En la mayoría de los casos, puedes simplemente reemplazar el antiguo middleware de la versión 3 por su equivalente en Express 4. Para más detalles, consulta la documentación del módulo en GitHub.
app.use acepta parámetros
En la versión 4 puedes usar un parámetro variable para definir la ruta donde se cargan las funciones de middleware, y luego leer el valor del parámetro desde el manejador de ruta. Por ejemplo:
app.use('/book/:id', (req, res, next) => { console.log('ID:', req.params.id); next();});El sistema de enrutamiento
Las apps ahora cargan implícitamente el middleware de enrutamiento, por lo que ya no tienes que
preocuparte por el orden en que se carga el middleware con respecto al
middleware router.
La forma de definir rutas no ha cambiado, pero el sistema de enrutamiento tiene dos nuevas características para ayudar a organizar tus rutas:
- Un nuevo método,
app.route(), para crear manejadores de ruta encadenables para una ruta. - Una nueva clase,
express.Router, para crear manejadores de ruta modulares y montables.
Método app.route()
El nuevo método app.route() te permite crear manejadores de ruta encadenables
para una ruta. Como la ruta se especifica en una sola ubicación, crear rutas modulares es útil, ya que reduce la redundancia y los errores tipográficos. Para más
información sobre rutas, consulta la documentación de Router().
Aquí hay un ejemplo de manejadores de ruta encadenados definidos usando la función app.route().
app .route('/book') .get((req, res) => { res.send('Get a random book'); }) .post((req, res) => { res.send('Add a book'); }) .put((req, res) => { res.send('Update the book'); });Clase express.Router
La otra característica que ayuda a organizar las rutas es una nueva clase,
express.Router, que puedes usar para crear manejadores de ruta modulares y montables.
Una instancia de Router es un sistema completo de middleware y enrutamiento; por esta razón
se le suele llamar "mini-app".
El siguiente ejemplo crea un router como módulo, carga middleware en él, define algunas rutas, y lo monta en una ruta en la app principal.
Por ejemplo, crea un archivo de router llamado birds.js en el directorio de la app,
con el siguiente contenido:
var express = require('express');var router = express.Router();
// middleware specific to this routerrouter.use((req, res, next) => { console.log('Time: ', Date.now()); next();});// define the home page routerouter.get('/', (req, res) => { res.send('Birds home page');});// define the about routerouter.get('/about', (req, res) => { res.send('About birds');});
module.exports = router;import express from 'express';
const router = express.Router();
// middleware specific to this routerrouter.use((req, res, next) => { console.log('Time: ', Date.now()); next();});// define the home page routerouter.get('/', (req, res) => { res.send('Birds home page');});// define the about routerouter.get('/about', (req, res) => { res.send('About birds');});
export default router;Luego, carga el módulo router en la aplicación:
var birds = require('./birds');
// ...
app.use('/birds', birds);import birds from './birds';
// ...
app.use('/birds', birds);La app ahora podrá manejar peticiones a las rutas /birds y
/birds/about, y llamará al middleware timeLog
específico de la ruta.
Otros cambios
La siguiente tabla lista otros cambios pequeños pero importantes en Express 4:
| Objeto | Descripción |
|---|---|
| Node.js | Express 4 requiere Node.js 0.10.x o superior y ha dejado de soportar Node.js 0.8.x. |
http.createServer() | El módulo |
app.configure() | La función |
json spaces | La propiedad de aplicación |
req.accepted() | Usa |
res.location() | Ya no resuelve URLs relativas. |
req.params | Era un array; ahora es un objeto. |
res.locals | Era una función; ahora es un objeto. |
res.headerSent | Cambiado a res.headersSent. |
app.route | Ahora disponible como app.mountpath. |
res.on('header') | Eliminado. |
res.charset | Eliminado. |
res.setHeader('Set-Cookie', val) | La funcionalidad ahora se limita a establecer el valor básico de la cookie. Usa |
Migración de una app de ejemplo
Aquí hay un ejemplo de migración de una aplicación Express 3 a Express 4.
Los archivos de interés son app.js y package.json.
App versión 3
app.js
Considera una aplicación Express v.3 con el siguiente archivo app.js:
var express = require('express');var routes = require('./routes');var user = require('./routes/user');var http = require('http');var path = require('path');
var app = express();
// all environmentsapp.set('port', process.env.PORT || 3000);app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'pug');app.use(express.favicon());app.use(express.logger('dev'));app.use(express.methodOverride());app.use(express.session({ secret: 'your secret here' }));app.use(express.bodyParser());app.use(app.router);app.use(express.static(path.join(__dirname, 'public')));
// development onlyif (app.get('env') === 'development') { app.use(express.errorHandler());}
app.get('/', routes.index);app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port'));});import express from 'express';import routes from './routes';import user from './routes/user';import http from 'http';import path from 'path';
const app = express();
// all environmentsapp.set('port', process.env.PORT || 3000);app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'pug');app.use(express.favicon());app.use(express.logger('dev'));app.use(express.methodOverride());app.use(express.session({ secret: 'your secret here' }));app.use(express.bodyParser());app.use(app.router);app.use(express.static(path.join(__dirname, 'public')));
// development onlyif (app.get('env') === 'development') { app.use(express.errorHandler());}
app.get('/', routes.index);app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port'));});package.json
El archivo package.json de la versión 3 correspondiente podría verse
más o menos así:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "express": "3.12.0", "pug": "*" }}Proceso
Comienza el proceso de migración instalando el middleware necesario para la app de Express 4 y actualizando Express y Pug a sus respectivas últimas versiones con el siguiente comando:
npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --saveyarn add serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latestpnpm add serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latestbun add serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latestHaz los siguientes cambios en app.js:
-
Las funciones de middleware integradas de Express
express.favicon,express.logger,express.methodOverride,express.session,express.bodyParseryexpress.errorHandlerya no están disponibles en el objetoexpress. Debes instalar sus alternativas manualmente y cargarlas en la app. -
Ya no necesitas cargar la función
app.router. No es un objeto válido de la app Express 4, así que elimina el códigoapp.use(app.router);. -
Asegúrate de que las funciones de middleware se cargan en el orden correcto - carga
errorHandlerdespués de cargar las rutas de la app.
App versión 4
package.json
Ejecutar el comando de npm anterior actualizará package.json de la siguiente manera:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "body-parser": "^1.5.2", "errorhandler": "^1.1.1", "express": "^4.8.0", "express-session": "^1.7.2", "pug": "^2.0.0", "method-override": "^2.1.2", "morgan": "^1.2.2", "multer": "^0.1.3", "serve-favicon": "^2.0.1" }}app.js
Luego, elimina el código inválido, carga el middleware necesario, y haz otros
cambios según sea necesario. El archivo app.js se verá así:
var http = require('http');var express = require('express');var routes = require('./routes');var user = require('./routes/user');var path = require('path');
var favicon = require('serve-favicon');var logger = require('morgan');var methodOverride = require('method-override');var session = require('express-session');var bodyParser = require('body-parser');var multer = require('multer');var errorHandler = require('errorhandler');
var app = express();
// all environmentsapp.set('port', process.env.PORT || 3000);app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'pug');app.use(favicon(path.join(__dirname, '/public/favicon.ico')));app.use(logger('dev'));app.use(methodOverride());app.use( session({ resave: true, saveUninitialized: true, secret: 'uwotm8', }));app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));app.use(multer());app.use(express.static(path.join(__dirname, 'public')));
app.get('/', routes.index);app.get('/users', user.list);
// error handling middleware should be loaded after the loading the routesif (app.get('env') === 'development') { app.use(errorHandler());}
var server = http.createServer(app);server.listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port'));});import http from 'http';import express from 'express';import routes from './routes';import user from './routes/user';import path from 'path';import favicon from 'serve-favicon';import logger from 'morgan';import methodOverride from 'method-override';import session from 'express-session';import bodyParser from 'body-parser';import multer from 'multer';import errorHandler from 'errorhandler';
const app = express();
// all environmentsapp.set('port', process.env.PORT || 3000);app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'pug');app.use(favicon(path.join(__dirname, '/public/favicon.ico')));app.use(logger('dev'));app.use(methodOverride());app.use( session({ resave: true, saveUninitialized: true, secret: 'uwotm8', }));app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));app.use(multer());app.use(express.static(path.join(__dirname, 'public')));
app.get('/', routes.index);app.get('/users', user.list);
// error handling middleware should be loaded after the loading the routesif (app.get('env') === 'development') { app.use(errorHandler());}
const server = http.createServer(app);server.listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port'));});Nota
A menos que necesites trabajar directamente con el módulo http (socket.io/SPDY/HTTPS), cargarlo no es necesario, y la app puede iniciarse simplemente así:
app.listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port'));});Ejecutar la app
El proceso de migración está completo, y la app es ahora una app de Express 4. Para confirmarlo, inicia la app usando el siguiente comando:
$ node .Carga http://localhost:3000 y ve la página de inicio siendo renderizada por Express 4.
Actualización al generador de apps de Express 4
La herramienta de línea de comandos para generar una app de Express sigue siendo
express, pero para actualizar a la nueva versión, debes desinstalar
el generador de apps de Express 3 y luego instalar el nuevo
express-generator.
Instalación
Si ya tienes el generador de apps de Express 3 instalado en tu sistema, debes desinstalarlo:
npm uninstall -g expressyarn global remove expresspnpm remove --global expressbun remove --global expressDependiendo de cómo estén configurados los permisos de tus archivos y directorios,
es posible que necesites ejecutar este comando con sudo.
Ahora instala el nuevo generador:
npm install -g express-generatoryarn global add express-generatorpnpm add --global express-generatorbun add --global express-generatorDependiendo de cómo estén configurados los permisos de tus archivos y directorios,
es posible que necesites ejecutar este comando con sudo.
Ahora el comando express en tu sistema está actualizado al
generador de Express 4.
Cambios en el generador de apps
Las opciones y el uso del comando siguen siendo prácticamente los mismos, con las siguientes excepciones:
- Eliminada la opción
--sessions. - Eliminada la opción
--jshtml. - Añadida la opción
--hoganpara soportar Hogan.js.
Ejemplo
Ejecuta el siguiente comando para crear una app de Express 4:
$ express app4Si miras el contenido del archivo app4/app.js, notarás
que todas las funciones de middleware (excepto express.static) que son necesarias para
la app se cargan como módulos independientes, y el middleware router
ya no se carga explícitamente en la app.
También notarás que el archivo app.js es ahora un módulo de Node.js, en contraste con la app independiente que generaba el antiguo generador.
Después de instalar las dependencias, inicia la app usando el siguiente comando:
$ npm startSi miras el script npm start en el archivo package.json,
notarás que el comando real que inicia la app es
node ./bin/www, que solía ser node app.js
en Express 3.
Como el archivo app.js generado por el generador de Express 4
es ahora un módulo de Node.js, ya no puede iniciarse independientemente como una app
(a menos que modifiques el código). El módulo debe cargarse en un archivo de Node.js
y iniciarse a través de ese archivo. El archivo de Node.js es ./bin/www
en este caso.
Ni el directorio bin ni el archivo www sin extensión
son obligatorios para crear o iniciar una app de Express. Son
solo sugerencias del generador, así que siéntete libre de modificarlos según tus
necesidades.
Para deshacerte del directorio www y mantener las cosas "al estilo Express 3",
elimina la línea que dice module.exports = app; al final del
archivo app.js, luego pega el siguiente código en su lugar:
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), () => { debug('Express server listening on port ' + server.address().port);});Asegúrate de cargar el módulo debug al principio del archivo app.js usando el siguiente código:
var debug = require('debug')('app4');Luego, cambia "start": "node ./bin/www" en el archivo package.json por "start": "node app.js".
Ahora has movido la funcionalidad de ./bin/www de vuelta a
app.js. Este cambio no es recomendado, pero el ejercicio te ayuda
a entender cómo funciona el archivo ./bin/www, y por qué el archivo app.js
ya no se inicia por sí solo.