NPM

<< AJAX / Fetch Vite >>

NPM (Node Package Manager) es una herramienta que facilita la integración de librerías y herramientas de desarrollo realizadas por terceros en nuestros proyectos. En los repositorios de NPM encontraremos algunas de las librerías más populares, frameworks y herramientas como jQuery, Angular, React, Express, ESLint, Sass, Browserify, Bootstrap, o Ionic, entre otras muchas.

Además, NPM nos proporciona un completo sistema de automatización de tareas basado en scripts

Instalación de NPM

Para utilizar NPM, necesitamos instalar primero Node.js, ya que NPM forma parte de Node. Node permite la ejecución de aplicaciones JavaScript en el servidor usando el motor v8 (mismo que Chrome), por lo que podemos crear aplicaciones tanto de cliente como de servidor con un único lenguaje → JavaScript.

Aquí están los enlaces para descargar Node:

Instalador Windows y Mac
Instrucciones Debian y Ubuntu
Otros sistemas

Lo más recomendable es instalar la versión LTS (Long Term Support) más actual, ya que es más estable que una versión no LTS y con mejor soporte por parte de librerías y frameworks. Más información: Guía de versiones de Node.js.

Se puede comprobar la correcta instalación ejecutando en la consola el comando npm --version que debería imprimir la versión actual de NPM. O node --version para la versión de Node.

Podemos consultar la ayuda de npm mediante los comandos:

  • npm -h → Muestra la ayuda rápida y una lista con los comandos típicos de npm
  • npm comando -h → Muestra una ayuda rápida con información específica sobre el comando npm (npm install -h)
  • npm help comando → Se abre una página en el navegador o el man de Linux, mostrando ayuda sobre un determinado comando
  • npm help-search lista de palabras → Nos devuelve una lista de ayuda de aquellos comandos que contienen la palabra(s) buscada(s) (separadas por espacios)

Creación de un proyecto NPM

Un proyecto NPM es un directorio que contiene un archivo llamado package.json (además del resto de archivos), donde se especifica el autor, la versión, las depedencias externas, tareas automatizadas, etc. del proyecto. En esta sección vamos a ver cómo instalar, actualizar, o eliminar dependencias de nuestro proyecto (o de forma global en nuestro sistema).

Para crear el archivo package.json en nuestro proyecto, simplemente nos moveremos al directorio principal de nuestro proyecto (no hace falta que esté vacío) y ejecutamos npm init. Nos preguntará algunas cosas sobre nuestro proyecto y creará el archivo package.json basado en esas preguntas. Podemos dejar muchos de los valores por defecto o vacíos presionando enter.

Instalar dependencias

El comando para instalar un paquete en nuestro proyecto es npm install nombre-paquete . Si ejecutamos este comando por primera vez, veremos que creará un directorio llamado node_modules dentro del directorio de proyecto. Este directorio contendrá todos los paquetes instalados mediante npm (incluyendo a su vez las dependencias de dichos paquetes). Vamos a probar con Day.js.

npm i dayjs

Esto instalará por defecto la última versión estable de la librería Day.js (manejo de fechas) dentro del directorio node_modules. A partir de ahora podremos utilizarla en nuestro código:

La importación de la librería en el código es todavía algo incómoda, ya que tenemos que buscar el archivo que contiene la librería, y básicamente estamos utilizándola como si la incluyéramos a mano en el HTML. Más adelante, veremos como optimizar esto con herramientas como Vite.

Tipos de dependencias

Por defecto, cuando instalamos una dependencia se instala como dependencia de ejecución. Una dependencia de ejecución es aquella que necesita el programa para poder ejecutarse en el navegador. Normalmente hablamos de una librería de JavaScript cuando nos referimos a esto. Existen también las dependencias de desarrollo, que son herramientas que únicamente utilizará el programador, como pueden ser compiladores (de TypeScript a JavaScript), empaquetadores como Webpack, ofuscadores de código, librerías de testing, etc.

Para instalar un paquete como dependencia de desarrollo usamos la opción -D o --save-dev:

npm i -D uglify-js

Ahora podemos ver como en el archivo package.json, tenemos registradas tanto las dependencias de ejecución (dependencies), como las de desarrollo (devDependencies):

Reinstalar dependencias en un proyecto

El directorio node_modules se puede borrar en cualquier momento. De hecho, en los repositorios de código (Github por ejemplo), nunca se sube este directorio. Para volver a instalar las dependencias en cualquier momento, tanto para producción como para desarrollo, que aparecen en package.json, simplemente ejecutamos npm install.

Podemos instalar solo las dependencias de producción o solo las dependencias de desarrollo con npm install --only=prod, o npm install --only=dev.

Instalar paquetes globales

Ciertas herramientas o frameworks, como Angular o Nest, requieren la instalación de herramientas en el sistema para poder crear proyectos. Estos son paquetes globales que se instalan con la opción -g (ejemplo: npm i -g @angular/cli) Para saber donde se instalan estos paquetes ejecuta npm root -g.

Los paquetes globales contienen ejecutables (archivos JavaScript ejecutados bajo Node) que se registran para todo el sistema. Es decir, se pueden ejecutar desde la consola independientemente del directorio donde nos encontremos.

El comando npx

Para ejecutar la herramienta instalada localmente en el proyecto donde nos encontramos, bien sea porque queremos ejecutar la versión local en lugar de la global, o porque no la tenemos instalada de forma global, basta con poner el comando npx delante. Si no está instalada, la descargará y ejecutará. Ejemplo: npx uglify-js -mc archivo.js.

Listar paquetes instalados

Para poder ver los paquetes instalados en el directorio npm_modules escribiremos npm list. Si queremos ver en formato árbol, los paquetes que hay instalados y las dependencias que tiene cada uno de ellos, tenemos la opción --depth nivel. Donde nivel es la profundidad de dependencias a la que queremos descender.

Otra opciones bastante útil es incluir --include dev (lista sólo los paquetes en desarrollo), --include prod (solo los paquetes en producción), --long (muestra una descripción de cada paquete), o --global (lista paquetes globales).

Gestión de versiones

Por defecto, cuando instalamos un paquete, se instalará la última versión estable. Pero a veces, nuestro proyecto necesita incluir una versión anterior, por ejemplo, para soportar navegadores antiguos.

Las versiones de los paquetes normalmente tienen tres números X.Y.Z. La mayoría de paquetes siguen las reglas SemVer (Semantic Versioning) para aplicar la numeración. Las reglas son las siguientes:

  • Cuando la Z es incrementada, significa que un bug o problema ha sido solucionado, pero no se añade ninguna funcionalidad nueva.
  • Cuando la Y es incrementada, significa que nuevas funcionalidades han sido añadidas, pero que esto no afecta al código de las versiones previas (siempre que se mantenga la X). Por ejemplo, una aplicación hecha con la versión 2.2 debería seguir funcionando con la versión 2.5 (pero al revés no tiene por qué).
  • El número X se incrementará sólo si han habido suficientes cambios de forma que no se garantiza que las aplicaciones que utilicen versiones anteriores funcionen compatibles con la nueva. Por tanto debemos tener cuidado cuando hagamos una migración y vigilar los cambios que se han producido en la librería o framework.

Si queremos instalar una versión específica de una librería en lugar de la última versión, especificaremos la versión después del nombre del paquete: paquete@x.y.z. Ejemplos de posibilidades que tenemos:

  • npm i libreria@"2.5.3" → Instala la versión 2.5.3
  • "<2.0.0" → Instala la versión justo anterior a la 2.0.0
  • "*" ó "x" → Instala la última versión de un paquete (cuidado con los cambios que pueda tener esa versión y cómo nos puede afectar…).
  • "3" ó "3.x", ó "3.x.x" → Esto instala la última versión de un paquete siempre que sea 3.x.x (no se actualizará a la versión 4.x.x).
  • "^3.3.5" → Instalará la última versión 3 (3.x.x) de un paquete, pero como mínimo deberá ser la versión 3.3.5 (el carácter ^ significa que sólo el primer número, 3, debe respetarse). Este es el comportamiento por defecto de NPM
  • "3.3" ó "3.3.x" → Instalará la última versión 3.3.x de un paquete (nunca se actualizará a 3.4.x o posterior).
  • "~3.3.5" → Instalará la última versión de 3.3 (no actualizará a la 3.4 o superior) pero como mínimo deberá ser la versión 3.3.5 (el carácter ~ significa que los 2 primeros números, 3.3, deben respetarse). Equivale a "3.3.x".
  • latest → Instala la última versión estable.
  • next → Instala la que será la próxima versión estable, aunque todavía no lo es (beta, RC)

Actualizar paquetes

Para actualizar todas las dependencias de un proyecto ejecutaremos npm update . Mirará en el archivo package.json para ver a qué versiones se permite actualizar (por ejemplo, si la versión instalada es ^3.1.0 podrá actualizar a la 3.2.0 pero no a la 4.0.0). Para actualizar un paquete en concreto utilizaremos npm update paquete .

Si queremos instalar una versión más actual que la permitida en package.json, podemos volver a reinstalar el paquete con npm install (ejemplo: npm install paquete@latest), que instalará la versión especificada y actualizará el archivo package.json.

Eliminar paquetes

Para eliminar un paquete de nuestro proyecto teclearemos npm uninstall package . En lugar de uninstall podemos usar remove, rm, un, r o unlink para hacer lo mismo. Para desinstalar un paquete global usaremos la opción -g.

Automatización de tareas

En nuestro archivo package.json, además de administrar las dependencias, podemos crear algunos scripts útiles para nuestro proyecto (ejecutar un servidor web, testear nuestra aplicación, minificar y empaquetar código, etc.). Estos scripts son comandos y todos tienen un nombre que les identifica. Debemos poner estas tareas dentro de la sección "script". La sintaxis del script será: "nombre-script": "Comando a ejecutar", donde el comando podrá ser un comando del sistema (no será multiplatafoma), o cualquier herramienta ejecutable que hayamos instalado con NPM en el proyecto (sin necesidad de usar npx). Para ejecutar un script usaremos: npm run nombre-script.

Script de inicio

Hay algunos nombres de scripts muy utilizados como start, o test que se pueden ejecutar sin la necesidad de escribir run. El script start normalmente se usa para ejecutar un servidor web, para poder probar nuestra aplicación (requerido por ejemplo cuando usamos módulos: <script type="module">).

Por ejemplo, podemos instalar lite-server, un servidor ligero de desarrollo para probar nuestra aplicación cuando ejecutemos npm start. Además, este servidor detecta cuando hay cambios en los archivos y recarga automáticamente la aplicación. Lo instalamos con npm i -D lite-server.

Script de test

En un proyecto real, lo normal es tener una batería de pruebas para la aplicación hechas con algún framework de testing como Jest, Jasmine, Karma, ... Es buena idea lanzar estas pruebas con el script test.

Para simplificar el ejemplo, vamos a utilizar un linter, en este caso ESLint, que sirve para forzar un estilo y buenas prácticas con el código de la aplicación. Es muy útil de cara a tener un código bien estructurado y homogéneo en proyectos donde, sobre todo, participan varios programadores.

Hay paquetes que se pueden instalar y configurar con el comando init. Para instalar ESLint, ejecutaremos npm init @eslint/config.

Se creará un archivo de configuración con las opciones elegidas llamado .eslintrc.js. Podemos añadir, quitar, o cambiar algunas de las reglas, por ejemplo en lugar de mostrar un error, que muestre un warning (cambiando “error” por “warn”):

Ahora podemos poner el comando en nuestro package.json, para que cuando ejecutemos npm test, ejecute eslint sobre los ficheros que queramos:

Para ayudarnos con los errores de ESLint, tenemos una extensión para Visual Studio Code, que automáticamente nos detectará los errores y warnings en el editor, dandonos la opción de corrección automática siempre que sea posible.

Tareas pre y post-script

Algunas tareas pueden requerir varios pasos, como por ejemplo, minimizar nuestros archivos JavaScript y CSS antes de ejecutar la aplicación (script de inicio). Para ejecutar más de una tarea o comando, podemos enlazarlos con && (y). Esos comandos se ejecutarán en orden, hasta que uno de ellos falle.

Sin embargo, resulta más limpio si utilizamos los hooks predefinidos de NPM (prefijos) pre y post. Simplemente crea un script con uno de estos prefijos y se ejecutará antes (pre) o después (post) del script principal que queremos ejecutar. En este ejemplo, crearemos un script pretest.

Ahora, si ejecutamos npm start, se ejecutarán prestart y start en ese orden. Si un script falla, el siguiente no se ejecutará, por lo que si la aplicación no pasa los test, no se lanzará el servidor de desarrollo.

<< AJAX / Fetch Vite >>