Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.

Este segundo artículo de nuestro Tutorial Express muestra cómo puede crear un "esqueleto" para un proyecto de sitio web que luego puede completar con rutas, plantillas/vistas, y llamadas a base de datos especifícas del sitio.

Prerequisitos: Configurar un entorno de desarrollo de Node. Revise el Tutorial Express.
Objetivo: Poder empezar sus nuevos proyectos web usando el Generador de Aplicaciones Express.

Visión General

Este artículo muestra cómo puede crear un sitio web "esqueleto"  usando la herramienta Generador de Aplicaciones Express, que luego puede completar con rutas, vistas/plantillas, y llamadas a base de datos especifícas del sitio.  En este caso usaremos la herramienta para crear el framework para nuestro  website Local Library, al que luego agregaremos todo el código que el sitio necesite.  El proceso es extremadamente simple, requiriendo sólo que se invoque el generador en la línea de comandos con un nombre para el nuevo proyecto, opcionalmente especificando también el motor de plantillas y el generador de CSS a utilizar.

Las siguientes secciones muestran como puede llamar al generador de aplicaciones, y proporcionan una pequeña explicación sobre las diferentes opciones para vistas y CSS.  También explicaremos como está estructurado el esqueleto del sitio web.  Al final, mostraremos como puede ejecutar el sitio web para verificar que funciona.

Nota: El Generador de Aplicaciones Express no es el único generador para aplicaciones Express, y el proyecto generado no es la única forma viable para estructurar sus archivos y directorios.  El sitio generado, sin embargo, tiene una estructura modular que es fácil de extender y comprender.  Para informacion sobre una mínima  aplicación Express, vea el Ejemplo Hello world  (Express docs).

Usando el generador de aplicaciones

Ya debe haber instalado el generador como parte de Configurar un entorno de desarrollo de Node. Como un rápido recordatorio, la herramienta generador se instala para todos los sitios usando el manejador de paquetes NPM, como se muestra:

npm install express-generator -g

El generador tiene un número de opciones, las cuales puede observar en la línea de comandos usando el comando --help (o bien  -h):

> express --help

  Usage: express [options] [dir]

  Options:

    -h, --help           output usage information
        --version        output the version number
    -e, --ejs            add ejs engine support
        --pug            add pug engine support
        --hbs            add handlebars engine support
    -H, --hogan          add hogan.js engine support
    -v, --view <engine>  add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git            add .gitignore
    -f, --force          force on non-empty directory

Simplemente puede especificar express para crear un proyecto dentro del directorio actual usando el motor de plantillas Jade y CSS plano (si especifica un nombre de directorio entonces el proyecto será creado en un subdirectorio con ese nombre).

express

También puede seleccionar el motor de plantillas para las vistas usando  --view y/o un motor generador de CSS usando --css.

Nota: Las otras opciones para elegir motores de plantillas (e.g. --hogan, --ejs, --hbs etc.) están descontinuadas. Use --view (o bien -v)!

¿Cuál motor de vistas debo usar?

El Generador de Aplicaciones Express le permite configurar un número de populares motores de plantillas, incluyendo EJS, Hbs, Pug (Jade), Twig, y Vash, aunque si no se especifica una opcion de vista, selecciona Jade por defecto. Express puede soportar un gran número de motores de plantillas aquí una lista.

Nota: Si quiere usar un motor de plantillas que no es soportado por el generador entonces vea el artículo  Usando motores de plantillas con Express (Express docs) y la documentación de su motor de plantillas.

Generalmente hablando debe seleccionar un motor de plantillas que le brinde toda la funcionalidad que necesite y le permita ser productivo rápidamente  — o en otras palabras, en la misma forma en que selecciona cualquier otro componente.  Alguna de las cosas a considerar cuando se comparan motores de plantillas:

  • Tiempo de productividad — Si su equipo ya tiene experiencia con un lenguaje de plantillas entonces  es probable que sean más productivos usando ese lenguaje.  Si no,  debería considerar la curva de aprendizaje relativa del motor de plantillas candidato. 
  • Popularidad y actividad — Revise la popularidad del motor y si tiene una comunidad activa.  Es importante obtener soporte para el motor cuando tenga problemas durante la vida útil del sitio web.
  • Estilo — Algunos motores de plantillas usan marcas específicas para indicar inserción de contenido dentro del HTML "ordinario", mientras que otros construyen el HTML usando una sintaxis diferente (por ejemplo, usando indentación (sangría) y nombres de bloque).
  • Tiempo Renderizado/desempeño.
  • Características — debe considerar si los motores que elija poseen las siguientes características disponibles:
    • Herencia del diseño: Le permite definir una plantilla base y luego "heredar" sólo las partes  que desea que sean diferentes para una página particular.  Típicamente esto es un mejor enfoque que construir plantillas incluyendo un número de componentes requeridos, contruyéndolas desde cero cada vez. 
    • Soporte para incluir: Le permite construir plantillas incluyendo otras plantillas.
    • Control consiso de la sintanxis de variables y ciclos.
    • Habilidad para filtrar valores de variables a nivel de las plantillas (e.g. convertir variables en mayúsculas, o darle formato a una fecha).
    • Habilidad para generar formatos de salida distintos al HTML (e.g. JSON o XML).
    • Soporte para operaciones asincrónas y de transmisión.
    • Pueden ser usadas tanto en el cliente como en el servidor. Si un motor de plantillas puede ser usado del lado del cliente esto da la posibilidad de servir datos y tener todo o la mayoría del renderizado del lado del cliente.

Tip: En Internet hay muchos recursos que le ayudarán a comparar diferentes opciones. 

Para este proyecto usaremos el motor de plantillas Pug (este es el  recientemente renombrado motor Jade), ya que es de los más populares lenguajes de plantillas Express/JavaScript y es soportado por el generador por defecto.

¿Cuál motor de hojas de estilo CSS debería usar?

El Generador de Aplicaciones Express le permite crear un proyecto que puede usar los más comunes motores  de  hojas  de estilos CSS: LESS, SASS, Compass, Stylus.

Nota: CSS tiene  algunas  limitaciones  que  dificultan ciertas  tareas. Los  motores  de hojas de estilos  CSS le permiten usar una sintaxis más poderosa para definir su  CSS, y luego compilar la definición en texto  plano para  su uso  en los  navegadores .

Como los  motores  de plantillas, debería usar el motor CSS que le permita a su  equipo  ser más  productivo.  Para este proyecto  usaremos CSS ordinario (opción  por defecto) ya que nuestros requerimientos no son lo suficientemente complicados para justificar el uso de un motor CSS. 

¿Cuál base de datos  debería usar?

El código generado no usa o incluye ninguna base de datos.  Las aplicaciones Express pueden  usar cualquier mecanismo de bases  de datos soportado por  Node (Express por si  mismo no define ningún comportamiento o requerimiento para el manejo de bases de datos).

Discutiremos la integración con una base de datos en un posterior artículo.

Creando el proyecto

Para el ejemplo que vamos a crear la app Local Library, crearemos un proyecto llamado express-locallibrary-tutorial usando la librería de plantillas Pug y ningún motor CSS.

Primero navegue a donde quiera crear el proyecto y luego ejecute el Generador de Aplicaciones Express en la línea  de comandos como se muestra:

express express-locallibrary-tutorial --view=pug

El generador creará (y listará) los archivos del proyecto.

   create : express-locallibrary-tutorial
   create : express-locallibrary-tutorial/package.json
   create : express-locallibrary-tutorial/app.js
   create : express-locallibrary-tutorial/public/images
   create : express-locallibrary-tutorial/public
   create : express-locallibrary-tutorial/public/stylesheets
   create : express-locallibrary-tutorial/public/stylesheets/style.css
   create : express-locallibrary-tutorial/public/javascripts
   create : express-locallibrary-tutorial/routes
   create : express-locallibrary-tutorial/routes/index.js
   create : express-locallibrary-tutorial/routes/users.js
   create : express-locallibrary-tutorial/views
   create : express-locallibrary-tutorial/views/index.pug
   create : express-locallibrary-tutorial/views/layout.pug
   create : express-locallibrary-tutorial/views/error.pug
   create : express-locallibrary-tutorial/bin
   create : express-locallibrary-tutorial/bin/www

   install dependencies:
     > cd express-locallibrary-tutorial && npm install

   run the app:
     > SET DEBUG=express-locallibrary-tutorial:* & npm start

Al final de la lista el generador mostrará instrucciones sobre como instalar las dependencias necesarias (mostradas en el archivo package.json) y luego como ejecutar la aplicación (las instrucciones anteriores son para windows; en Linux/macOS serán ligeramente diferentes).

Ejecutando el esqueleto del sitio web

En este punto tenemos un esqueleto completo de nuestro proyecto.  El sitio web  no hace mucho actualmente, pero es bueno ejecutarlo para ver como funciona.

  1. Primero instale las dependencias (el comando install recuperará todas las dependencias listadas e el archivo package.json del proyecto).
    cd express-locallibrary-tutorial
    npm install
  2. Luego ejecute la aplicación.
    • En Windows, use este  comando:
      SET DEBUG=express-locallibrary-tutorial:* & npm start
    • En macOS o Linux, use este comando:
      DEBUG=express-locallibrary-tutorial:* npm start
      
  3. Luego carge en su navegador http://localhost:3000/ para acceder a la aplicación.

Debería ver una página parecida a esta:

Browser for default Express app generator website

Tiene una aplicación Express funcional, ejecutandose en localhost:3000.

Nota: También podría ejecutar la app usando el comando npm start. Especificado la variable DEBUG como se muestra habilita el logging/debugging por consola. Por ejemplo, cuando visite la página mostrada arriba verá la información de depuración como esta:

>SET DEBUG=express-locallibrary-tutorial:* & npm start

> express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial
> node ./bin/www

  express-locallibrary-tutorial:server Listening on port 3000 +0ms
GET / 200 288.474 ms - 170
GET /stylesheets/style.css 200 5.799 ms - 111
GET /favicon.ico 404 34.134 ms - 1335

Habilite el reinicio del servidor cuando los archivos sean modificados

Cualquier cambio que le haga a su sitio web Express no será visible hasta que reinicie el servidor. Rapidamente, tener que detener y reiniciar el servidor cada vez que hacemos un cambio, se vuelve irritante, así que es beneficioso tomarse un tiempo y automátizar el reinicio del servidor cuando sea necesario.

Una de las herramientas más sencillas para este propósito es nodemon. Éste usualmente se instala globalmente (ya que es una "herramienta"), pero aquí lo instalaremos y usaremos localmente como una dependencia de desarrollo, así cualquier desarrollador que esté trabajando con el proyecto lo obtendrá automáticamente cuando instale la aplicación. Use el siguiente comando en el directorio raíz del esqueleto del proyecto:

npm install --save-dev nodemon

Si abre el archivo package.json de su proyecto verá una nueva sección con esta dependencia:

  "devDependencies": {
    "nodemon": "^1.14.11"
  }

Debido a que la herramienta no fue instalada globalmente no podemos ejecutarla desde la línea de comandos (a menos que la agreguemos a la ruta) pero podemos llamarla desde un script NPM porque NPM sabe todo sobre los paquetes instalados. Busque la sección scripts de su package.json. Inicialmente contendrá una línea, la cual comienza con "start". Actualicela colocando una coma al final de la línea, y agregue la línea "devstart" mostrada abajo:

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },

Ahora podemos iniciar el servidor casi exactamente como antes, pero especificando el comando devstart:

  • En Windows, use este comando:
    SET DEBUG=express-locallibrary-tutorial:* & npm run devstart
  • En macOS or Linux, use este comando:
    DEBUG=express-locallibrary-tutorial:* npm run devstart
    

Nota: Ahora si modifica cualquier archivo del proyecto el servidor se reiniciará  (o lo puede reiniciar rs en la consola de comandos en cualquier momento). Aún necesitará recargar el navegador para refrescar la página.

Ahora tendremos que llamar "npm run <nombre del script>" en vez de npm start, porque "start" es actualmente un comando NPM que es mapeado al nombre del script. Podríamos haber reemplazado el comando en el script start pero sólo queremos usar nodemon durante el desarrollo, así que tiene sentido crear un nuevo script para este comando.

El proyecto generado

Observemos el proyecto que hemos creado.

Estructura del directorio

El proyecto generado, ahora que ha instalado las dependencias, tiene la siguiente estructura de archivos (los archivos son los elementos que no están precedidos con "/"). El archivo package.json fdefine las dependencias de la aplicación y otra información. También define un script de inicio que es el punto de entrada de la aplicación,  el archivo JavaScript /bin/www. Éste establece algunos de los manejadores de error de la aplicación y luego carga el archivo app.js para que haga el resto del trabajo.  Las rutas se almacenan en módulos separados en el directorio /routes. las plantillas se almacenan en el directorio /views.

/express-locallibrary-tutorial
    app.js
    /bin
        www
    package.json
    /node_modules
        [about 4,500 subdirectories and files]
    /public
        /images
        /javascripts
        /stylesheets
            style.css
    /routes
        index.js
        users.js
    /views
        error.pug
        index.pug
        layout.pug
    

Las siguientes secciones describen los archivos con más detalle. 

package.json

El archivo package.json define las dependencias de la aplicación y otra información: 

{
  "name": "express-locallibrary-tutorial",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.18.2",
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.2",
    "morgan": "~1.9.0",
    "pug": "~2.0.0-rc.4",
    "serve-favicon": "~2.4.5"
  },
  "devDependencies": {
    "nodemon": "^1.14.11"
  }
}

Las dependencias incluyen el paquete express y los paquetes para el motor de plantillas elegido (pug). Adicionalmente, tenemos los siguientes paquetes que son útiles en muchas aplicaciones web: 

  • body-parser: This parses the body portion of an incoming HTTP request and makes it easier to extract different parts of the contained information. For example, you can use this to read POST parameters.
  • cookie-parser: Used to parse the cookie header and populate req.cookies (essentially provides a convenient method for accessing cookie information).
  • debug: A tiny node debugging utility modelled after node core's debugging technique.
  • morgan: An HTTP request logger middleware for node.
  • serve-favicon: Node middleware for serving a favicon (this is the icon used to represent the site inside the browser tab, bookmarks, etc.).

The scripts section defines a "start" script, which is what we are invoking when we call npm start to start the server. From the script definition you can see that this actually starts the JavaScript file ./bin/www with node. It also defines a "devstart" script, which we invoke when calling npm run devstart instead. This starts the same ./bin/www file, but with nodemon rather than node.

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },

www file

The file /bin/www is the application entry point! The very first thing this does is require() the "real" application entry point (app.js, in the project root) that sets up and returns the express() application object.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');

Note: require() is a global node function that is used to import modules into the current file. Here we specify app.js module using a relative path and omitting the optional (.js) file extension.

The remainder of the code in this file sets up a node HTTP server with app set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.

app.js

This file creates an express application object (named app, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:

var express = require('express');
var app = express();
...
module.exports = app;

Back in the www entry point file above, it is this module.exports object that is supplied to the caller when this file is imported.

Lets work through the app.js file in detail. First we import some useful node libraries into the file using require(), including express, serve-favicon, morgan, cookie-parser and body-parser that we previously downloaded for our application using NPM; and path, which is a core Node library for parsing file and directory paths.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

Then we require() modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.

var index = require('./routes/index');
var users = require('./routes/users');

Note: At this point we have just imported the module; we haven't actually used its routes yet (this happens just a little bit further down the file).

Next we create the app object using our imported express module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First we set the 'views' value to specify the folder where the templates will be stored (in this case the sub folder /views). Then we set the 'view engine' value to specify the template library (in this case "pug").

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

The next set of functions call app.use() to add the middleware libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the express.static middleware to get Express to serve all the static files in the /public directory in the project root.

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different parts of the site:

app.use('/', index);
app.use('/users', users);

Note: The paths specified above ('/' and '/users') are treated as a prefix to routes defined in the imported files. So for example if the imported users module defines a route for /profile, you would access that route at /users/profile. We'll talk more about routes in a later article.

The last middleware in the file adds handler methods for errors and HTTP 404 responses.

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by /bin/www).

module.exports = app;

Routes

The route file /routes/users.js is shown below (route files share a similar structure, so we don't need to also show index.js). First it loads the express module, and uses it to get an express.Router object. Then it specifies a route on that object, and lastly exports the router from the module (this is what allows the file to be imported into app.js).

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

The route defines a callback that will be invoked whenever an HTTP GET request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('/users') plus whatever is defined in this file ('/'). In other words, this route will be used when an URL of /users/ is received.

Tip: Try this out by running the server with node and visiting the URL in your browser: http://localhost:3000/users/. You should see a message: 'respond with a resource'.

One thing of interest above is that the callback function has the third argument 'next', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the next argument, it may be useful in the future if you want to add multiple route handlers to the '/' route path.

Views (templates)

The views (templates) are stored in the /views directory (as specified in app.js) and are given the file extension .pug. The method Response.render() is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from /routes/index.js you can see how that route renders a response using the template "index" passing the template variable "title".

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'Express' });
});

The corresponding template for the above route is given below (index.pug). We'll talk more about the syntax later. All you need to know for now is that the title variable (with value 'Express') is inserted where specified in the template.

extends layout

block content
  h1= title
  p Welcome to #{title}

Challenge yourself

Create a new route in /routes/users.js that will display the text "You're so cool" at URL /users/cool/. Test it by running the server and visiting http://localhost:3000/users/cool/ in your browser

Summary

You have now created a skeleton website project for the Local Library and verified that it runs using node. Most important, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.

Next we'll start modifying the skeleton so that works as a library website.

See also

 

In this module

 

Etiquetas y colaboradores del documento

Colaboradores en esta página: maringenio, mimz2563
Última actualización por: maringenio,