Editar en GitHub

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

Hay varios cambios significativos en Express 4:

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:

  1. Instala el módulo: npm install --save <module-name>
  2. En tu app, require el módulo: require('module-name')
  3. 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 3Express 4
express.bodyParser

body-parser + multer

express.compresscompression
express.cookieSessioncookie-session
express.cookieParsercookie-parser
express.loggermorgan
express.sessionexpress-session
express.faviconserve-favicon
express.responseTimeresponse-time
express.errorHandlererrorhandler
express.methodOverridemethod-override
express.timeoutconnect-timeout
express.vhostvhost
express.csrfcsurf
express.directoryserve-index
express.staticserve-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:

birds.cjs
var express = require('express');
var router = express.Router();
// middleware specific to this router
router.use((req, res, next) => {
console.log('Time: ', Date.now());
next();
});
// define the home page route
router.get('/', (req, res) => {
res.send('Birds home page');
});
// define the about route
router.get('/about', (req, res) => {
res.send('About birds');
});
module.exports = router;

Luego, carga el módulo router en la aplicación:

index.cjs
var birds = require('./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:

ObjetoDescripción
Node.jsExpress 4 requiere Node.js 0.10.x o superior y ha dejado de soportar Node.js 0.8.x.
http.createServer()

El módulo http ya no es necesario, a menos que necesites trabajar directamente con él (socket.io/SPDY/HTTPS). La app puede iniciarse usando la función app.listen().

app.configure()

La función app.configure() ha sido eliminada. Usa process.env.NODE_ENV o la función app.get('env') para detectar el entorno y configurar la app en consecuencia.

json spaces

La propiedad de aplicación json spaces está deshabilitada por defecto en Express 4.

req.accepted()

Usa req.accepts(), req.acceptsEncodings(), req.acceptsCharsets(), y req.acceptsLanguages().

res.location()Ya no resuelve URLs relativas.
req.paramsEra un array; ahora es un objeto.
res.localsEra una función; ahora es un objeto.
res.headerSentCambiado a res.headersSent.
app.routeAhora disponible como app.mountpath.
res.on('header')Eliminado.
res.charsetEliminado.
res.setHeader('Set-Cookie', val)

La funcionalidad ahora se limita a establecer el valor básico de la cookie. Usa res.cookie() para funcionalidad adicional.

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:

index.cjs
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 environments
app.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 only
if (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:

Ventana de terminal
npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save

Haz los siguientes cambios en app.js:

  1. Las funciones de middleware integradas de Express express.favicon, express.logger, express.methodOverride, express.session, express.bodyParser y express.errorHandler ya no están disponibles en el objeto express. Debes instalar sus alternativas manualmente y cargarlas en la app.

  2. 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ódigo app.use(app.router);.

  3. Asegúrate de que las funciones de middleware se cargan en el orden correcto - carga errorHandler despué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í:

index.cjs
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 environments
app.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 routes
if (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'));
});

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:

Ventana de terminal
$ 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:

Ventana de terminal
npm uninstall -g express

Dependiendo 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:

Ventana de terminal
npm install -g express-generator

Dependiendo 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 --hogan para soportar Hogan.js.

Ejemplo

Ejecuta el siguiente comando para crear una app de Express 4:

Ventana de terminal
$ express app4

Si 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:

Ventana de terminal
$ npm start

Si 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.