CapÃtulo 5 - Inicializar proyectos de Node.js
Inicialización de un proyecto de Node.js
Normalmente, por cada proyecto de Node.js, se crea un directorio donde se almacenan todos los archivos y paquetes relacionados con el proyecto; No necesariamente un directorio debe estar en blanco para inicializarlo, por lo tanto, se continúa trabajando con el proyecto greeting
.
npm puede almacenar toda la meta información y administrar los paquetes requeridos, con sus respectivas versiones del proyecto, a través de un archivo de manifiesto. Una de las maneras para crear este archivo manifiesto es con el comando npm init
, que a su vez mostrará un asistente que guiará mediante preguntas con el fin de obtener la información necesaria para el proyecto y asà hasta finalizar el proceso: Pero una manera más rápida de hacer este proceso para crear el archivo manifiesto, con todas las opciones que trae por defecto, con el siguiente comando:
npm init -y
El resultado es un archivo de texto llamado package.json
, el cual contiene toda la información básica generada por defecto; estos valores se pueden cambiar solamente editando y guardando los cambios en el archivo. Lo más común y recomendado es que este archivo se encuentre en la raÃz del directorio del proyecto.
Opcionalmente, para no tener que cambiar la información del archivo manifiesto cada vez que se crea un nuevo proyecto, es posible establecer valores por defecto para cuando se ejecute el comando npm init
, como por ejemplo:
npm set init.author.name "Gustavo Morales"
npm set init.author.email "gustavo.morales@gmail.com"
npm set init.author.url "https://gmoralesc.me"
La otra opción es guardar estos valores en un archivo llamado .npmrc
en la raÃz del directorio del usuario o en la del directorio del proyecto, para ser más especÃfico. Más información acerca del archivo npmrc.
Más información:
Administración de paquetes y configuración con el archivo package.json
Instalación de dependencias
El archivo package.json
es muy importante, pues será el manifiesto de la aplicación. De ahora en adelante, para instalar un paquete como dependencia en el proyecto, añadimos la bandera -S
o --save
si queremos ser más explÃcitos.
Antes de instalar un paquete puede conocer toda la información acerca del mismo con el siguiente comando:
npm info colors
Instalar la dependencia en el proyecto con el siguiente comando:
npm install colors
En el archivo package.json
se ha añadido la siguiente sección:
"dependencies": {
"colors": "^1.4.0"
}
Indica el listado de dependencias del proyecto y la versión instalada de cada paquete. Si otra persona copiara este proyecto e instalará las dependencias (con el comando npm install
) tendrÃa la versión mÃnima del paquete colors
equivalente a 1.4.0
. El carácter ^
al inicio de la versión del paquete indica que se puede instalar cualquier upgrade o patch de la versión 1, pero no instalará ninguna versión con el mayor release 2; en otras palabras, podrá instalar 1.4.0 <= x < 2.0.0
. Esta nomenclatura es llamada semver y permite establecer las reglas para las versiones de los paquetes del proyecto.
Para listar todas las dependencias que tiene el proyecto con el siguiente comando:
npm list
O alguna en particular se agrega el nombre de la dependencia con el siguiente comando:
npm list colors
Instalación de paquetes para desarrollo
Existen paquetes que no son dependencias, pero son necesarias en el entorno local de desarrollo; por ejemplo, el paquete ESLint permite comprobar la sintaxis de los archivos JavaScript basado en un conjunto de reglas. Esto puede ser muy útil a la hora de estandarizar el código seleccionando o creando una guÃa de estilo. Para incluirla en el manifiesto como paquete de desarrollo se incluye la bandera -D
o --save-dev
.
npm install --save-dev eslint
Muchos subcomandos de npm tienen accesos directos, en el anterior se puede reemplazar
install
por la abreviacióni
, es decir:npm i -D eslint
Ahora, en el archivo package.json
, está incluida una nueva sección para los paquetes que se van a utilizar en el entorno de desarrollo; de esta manera es como npm distingue las dependencias necesarias a instalar en ambientes de producción.
"devDependencies": {
"eslint": "^8.56.0"
},
Configuración de git
Es muy importante tener en cuenta que si se está utilizando un sistema de control de versiones se debe ignorar el directorio de node_modules
, pues este no pertenece al código fuente del proyecto y además puede variar dependiendo de las versiones de los paquetes que se realice en cada instalación.
Si estamos utilizando git, se inicializa el repositorio si no lo está:
git init
En la raÃz del directorio del proyecto se crea un archivo llamado .gitignore
y se coloca las siguientes lÃneas:
node_modules/
.DS_Store
Thumbs.db
Con lo anterior, se establece que los archivos o directorios que cumplan con este patrón no serán incluidos en el repositorio de git. Aquà también se incluye los archivos como .DS_Store
en el caso de Mac OS o Thumbs.db
en el caso del sistema Windows, los cuales son archivos temporales para la generación de la vista previa (Thumbnails) de los directorios del sistema.
Si el proyecto se va a alojar en un repositorio público como Github, Gitlab o Bitbucket es muy recomendable crear un archivo llamado README.md
con la descripción del proyecto; ya que una vez publicado, el repositorio mostrará información preliminar de este mismo. La sintaxis con la que se escribe este archivo es Markdown.
Más información:
Configuración de npm scripts
Cuando estemos trabajando con el proyecto vamos a repetir una y otra vez los mismos comandos en la Terminal. Estos comandos se pueden crear para agilizar el trabajo, y npm lo hace a través de los scripts. En el contenido del archivo package.json
podrá observar la siguiente sección:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
En esta sección se pueden especificar los comandos que se desean utilizar en la Terminal. En el texto anterior está configurado para que el script test
imprima una cadena en la pantalla, indicando que aún no se han configurado las pruebas. Este script se puede ejecutar de la siguiente manera:
npm test
Scripts incorporados
npm tiene varios alias de scripts ya incorporados para trabajar, como por ejemplo test
, que vimos en la sección anterior. Asà como su nombre lo indica, se utiliza para ejecutar las pruebas del proyecto. Uno muy recomendado es el script start
que se ha convertido en una convención para iniciar los proyectos en Node.js, el cual se configurará más adelante.
Antes de agregar el script tenga en cuenta que en la llave main
del archivo package.json
está declarando cuál será el archivo de entrada por defecto del proyecto para ejecutarlo, este se llama index.js
.
Por convención, el archivo principal se llama
index.js
pero puede ser cualquier nombre e inclusive en otra ubicación, no necesariamente en la raÃz del proyecto.
Modificar la sección de scripts
del archivo package.json
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\"&& exit 1"
},
De ahora en adelante, para iniciar la aplicación de Node.js se ejecuta el siguiente comando:
npm start
Scripts personalizados
Es posible crear scripts personalizados para ejecutar diferentes tipos de tareas. En la sección anterior, se instalo y utilizo el paquete global ESLint, a continuación se un script personalizado que compruebe los archivos del proyecto:
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\"&& exit 1",
"lint": "eslint --no-eslintrc *.js"
},
Para ejecutar esta tarea personalizada, esta vez se añade el prefijo run
, pues no es un script incorporado:
npm run lint
Para listar todas las tareas que se pueden ejecutar con npm podemos ejecutar el siguiente comando:
npm run
Convenciones de un proyecto que incluyen npm
Normalmente, todos los proyectos que utilicen npm como administrador de paquetes y dependencias, utilizan la siguiente convención cada vez que se descarga o clona un proyecto:
npm install
npm start
Y si desea ejecutar las pruebas npm test
inclusive lo más recomendado es incluir estas instrucciones en el archivo README.md
.
Utilizando las dependencias y scripts
Se edita el archivo index.js
con el siguiente contenido:
const colors = require('colors/safe');
const args = process.argv.slice(2);
const [name = 'Friend'] = args;
const hour = new Date().getHours();
// Ask for hours range
if (hour >= 6 && hour < 12) {
console.log(colors.yellow(`Good morning ${name}`));
} else if (hour >= 12 && hour < 18) {
console.log(colors.green(`Good afternoon ${name}`));
} else if (hour >= 18 && hour < 23) {
console.log(colors.cyan(`Good evening ${name}`));
} else {
console.log(colors.blue(`Good night ${name}`));
}
Para ejecutar el programa se hace con el siguiente comando, esta vez para enviarle argumentos utilizamos un parámetro especial (--
) para que tome los argumentos de lÃnea de comando:
npm start -- Gustavo
Pre y pos scripts
Es posible tomar partida de la convención de los scripts de npm para ejecutar otros scripts antes y/o después de otro script por ejemplo:
"scripts": {
"postinstall": "npm test",
"prestart": "npm run lint",
"start": "node index.js",
"test": "echo \"Error: no test specified\"&& exit 1",
"lint": "eslint **.js"
},
En el ejemplo anterior se especifica que luego de ejecutar el script npm install
se ejecutarán automáticamente los comandos (no está limitado solo a ejecutar otros scripts) especificados en el script postinstall
. Y antes de ejecutar el script npm start
se ejecutarán automáticamente los comandos especificados en el script prestart
. No importa el orden en que se coloquen en el archivo package.json
dentro de la sección de scripts; lo importante es la nomenclatura.
Estandarizar argumentos de lÃnea de comandos
Cada vez que ejecutamos una aplicación de Node.js estamos enviando al menos un argumento al ejecutable de Node.js (node
), este argumento es el archivo de entrada de la aplicación (index.js
).
node index Gustavo
node index Gustavo Morales
node index "Gustavo Morales"
node index name=Gustavo
node index -n "Gustavo Morales"
Como se puede observar, Node.js separa los argumentos por el espacio y el orden de almacenamiento es el mismo orden de entrada; es decir, que para el segundo ejemplo serÃa incorrecto enviar el nombre separado por espacio, pues, serÃa interpretado como 2 argumentos. La manera correcta serÃa como está el tercer ejemplo.
Una forma de crear argumentos nombrados puede ser el cuarto ejemplo, luego tocarÃa separar la llave (key) del valor (value) y, por último, está la manera tradicional como se utilizan los argumentos nombrados, pero como podemos observar serÃa bastante trabajo tener que interpretar lo que queda almacenado en process.argv
, existen muchas librerÃas útiles para este caso, en el siguiente ejemplo se utilizará command-line-args
, se instala como una dependencia del proyecto con el siguiente comando:
npm i command-line-args
Se agrega el siguiente contenido al archivo index.js
:
const colors = require('colors/safe');
const commandLineArgs = require('command-line-args');
const params = [{ name: 'name', alias: 'n', type: String }];
const options = commandLineArgs(params);
const name = options.name || 'Friend';
const hour = new Date().getHours();
...
En la variable params
se ha indicado que argumentos y de qué tipo se esperan para que la librerÃa los procese y finalmente deje el resultado en la variable options
que es un objeto de llave / valor con cada uno de los argumentos declarados.
Ejecutar nuevamente la aplicación con los siguientes argumentos:
npm start -- -n Gustavo
Finalmente, tendrá el mismo resultado.
Es muy importante comprobar que los argumentos sean válidos, pues en este ejercicio, y en los siguientes de este tipo, se asume que el usuario ingresa los argumentos en forma correcta. Para practicar y profundizar puede hacer sus propias comprobaciones.
Más información: