introducción a npm

Introducción al instalador de paquetes npm... y algún bonus.

Madeleine Von Foerster

archivado en: JavaScript / 11 enero, 2016

Ya me tocaba hablar en The Bit Jazz Band de npm, una herramienta fundamental en el desarrollo web de hoy en día, así que aprovecho unos cursos que estoy dando para poner en negro sobre blanco algunas ideas sobre el tema.

¿Qué es npm?

Salvo sus creadores, no hay quien sepa qué significa npm. Entre las definiciones que dan en la propia página web podemos leer expresiones como:

  • nanoscale parts manufacturing
  • november perfect moustache
  • no painful merges
  • notable peru mariachis

que es una manera simpática de decir que esas tres letras no significan nada en concreto. El caso es que ya sea por casualidad o de forma intencionada, las tres letras se ajustan a lo que es: un instalador de paquetes que corre bajo node, en inglés, un «node package manager». Node no necesita presentación alguna, pero ¿qué es exactamente un paquete?

Según los creadores,

«A package is:

  • a) a folder containing a program described by a package.json file
  • b) a gzipped tarball containing (a)
  • c) a url that resolves to (b)
  • d) a <name>@<version> that is published on the registry with (c)
  • e) a <name>@<tag> that points to (d)
  • f) a <name> that has a "latest" tag satisfying (e)
  • g) a git url that, when cloned, results in (a)».

Es decir: es un programa alojado en git que se puede descargar mediante npm al cumplir una serie de requisitos formales de empaquetado y definición. Y esto abarca en el momento de escribir estas líneas unos 224.303 paquetes, una cifra que desde luego no está nada mal.

La consola

Node es un programa que se ejecuta por consola. Esto quiere decir que, una vez instalado -y ahora es muy fácil porque viene por defecto en la instalación de node-, para que funcione debemos escribir determinadas instrucciones, comandos, en alguna consola, como la que viene con git por ejemplo.

No hay que tenerle miedo a la consola, en cuanto le coges el tranquillo, amigo que llevas años con windows, resulta más o al menos igual de cómoda que un programa con interfaz gráfica

La instrucción más habitual que usaremos con npm es la que permite instalar packages:

npm install nombre-del-paquete

Otras otro par sentencias que nos pueden venir bien entre varias más que existen son:

npm uninstall nombre-del-paquete // desinstala

npm updated nombre-del-paquete // actualiza

Además, estas instrucciones se pueden complementar y matizar mediante flags, que en este contexto son una serie de términos precedidos por guiones que se añaden después de la sentencia principal. Por ejemplo, así indicaríamos que queremos instalar algo de forma global, en el equipo, para que esté disponible en cualquier momento, y no en el proyecto en concreto en el que estamos.

npm install nombre-del-paquete -g

Salvo algún que otro programa que usemos de forma muy habitual y del que tengamos controladas las actualizaciones, como gulp o grunt, no conviene instalarlos de forma global.

package.json

La piedra angular de un proyecto relacionado con npm, incluido en el que estamos instalando los packages, es un archivo de configuración denominado package.json, el cual debe guardarse en el directorio raíz.

La configuración mínima del package.json debe incluir:

name: El nombre del proyecto, en minúscula y sin espacios.

version: La versión con un etiquetado semántico, que en esencia consiste en una secuencia de tres números separados por puntos, en la que:

  • se sube el tercero cuando se apaña un bug resuelve una incidencia.
  • se sube el segundo cuando se añade una nueva funcionalidad.
  • se sube el primero cuando se cambia tanto el core, el cogollo de la aplicación / proyecto, que casi es como si fuera uno nuevo, compatible o no con las versiones anteriores.

Por ejemplo:

{

"name": "conversor-unidades",

"version": "2.1.2"

}

Los packages de npm suelen empezar por 1.* al considerar que las 0.* son versiones en desarrollo.

A continuación se suelen añadir estos campos descriptivos:

description: una descripción breve del proyecto.

author: el autor principal y un correo (opcional).

contributors: un array con el nombre, y opcionalmente, el correo de las personas que han colaborado.

keywords: un array con palabras clave para que luego se localice mejor en la página de npm y similares.

...

"description": "convierte unidades del sistema métrico internacional al anglosajón",

"author": "Hercio Martínez hercio@correo.com",

"contributors": [

{"name": "Foo", "email": "foo@fooilandia.com"},

{"name": "Bar", "email": "bar@baarilandia.com"},

],

keywords: [

"conversor",

"units"

]

...

Más campos descriptivos que se suelen definir:

bin: cuando el package contiene módulos que se pueden ejecutar por consola, se define aquí un jasonako con el nombre del módulo a ejecutar en la clave y la ruta al mismo en el valor.

main: el punto de entrada para los require de node (si esto te suena a chino, es que no lo necesitas).

repository: un jasonako con dos valores, type para indicar el tipo de repositorio, y la url al mismo.

bugs: la url para las issues.

private: true o false para indicar si es un proyecto privado o público.

license: el tipo de licencia a la que está sujeta el package.

...

"bin":  {

"conversor-total": "./bin/conversor-total"

},

"main": "tasks/conversor.js",

"repository": {

"type": "git",

"url": "git+https://github.com/mi-git/mi-repo.git"

},

"bugs": {

"url": "https://github.com/mi-git/mi-repo/issues"

},

"private": false,

"license": "MIT"

...

Bueno, me dejo algún tipo de dato de este tipo descriptivo por mencionar, como "maintainers", las personas que mantienen en la actualidad el proyecto, pero con los dichos baste para esta introducción. Vamos ahora con dos muy importantes: las dependencias y los scripts.

Se puede usar un asistente de npm para generar el package.json escribiendo por consola el comando init.

npm init

Dependencias

Se denomina dependencias a los programas, frameworks, librerías, plugins, lo-que-sea de los que depende un proyecto para funcionar, como puede ser grunt, bootstrap, angular, jquery, etcétera. Las dependencias se agrupan en dos grandes conjuntos:

Las que son necesarias en tiempos de desarrollo (develop), es decir, mientras estamos preparando las cosas, como pueden ser grunt o gulp.

Y las se necesitan cuando el proyecto está en producción (production), cuando está corriendo en un navegador o lo que sea, como puede ser angular.

Para instalar algo basta con escribir npm install y el nombre de ese algo.

npm install bootstrap

Con el flag --S, indicamos que, además de instalar algo, debe escribir esa dependencia en el package.json:

"dependencies": {

"bootstrap": "^3.3.6"

}

Y con el flag --D, que la escriba entre las dependencias develop.

"devDependencies": {

"bootstrap": "^3.3.6"

}

Npm tira de los packages publicados en su sitio, pero también podemos instalar cualquier cosa directamente de git escribiendo la url si está bien preparada con su archivo package.json. Por ejemplo, así instalaríamos desde git el frame js backbone.

npm install https://github.com/jashkenas/backbone.git

scripts

Además de instalar packages, npm tambien sirve para ejecutar programas que se trabajan desde la consola con comandos (cli), como grunt o babel. Por ejemplo, así podríamos hacer que se ejecutase babel, que es un traductor de ecmaScript 6 a ecmaScript 5 (entre otras cosas) cuando se ejecutase npm.

"scripts": {

"build": "babel --presets es2015 src/ -d lib/ --watch"

},

Veamos otro ejemplo más claro con el analizador de código eslint, que instalamos como ya sabemos con npm.

npm install eslint --S --D

Ahora podríamos lanzar el programa eslint directamente desde la consola para analizar el contenido de foo, que se encuentra en el directorio js.

eslint js/foo.js

Otra manera de ejecutar este programa sería definir la tarea entre los scripts del package.json:

"scripts": {

"eslint": "js/foo.js"

},

...

Y luego ejecutar por consola:

npm run eslint

Sin embargo, a mí no me gusta utilizar npm para ejecutar tareas por dos razones:

  1. En windows da problemas.
  2. Soy un firme defensor del principio de responsabilidad única llevado más allá de la programación orientada a objetos. En este contexto esto significa que creo que es mejor utilizar programas específicos para cada cosa, entre otras razones porque lo harán mejor, por lo que me parece mejor utilizar grunt o gulp como automatizadores de tareas. (Hablaré de estos dos programas en la siguiente entrada).

Por lo tanto, no profundizo más en este aspecto de npm y remito al lector interesado a un artículo de Keith Cirkel titulado How to Use npm as a Build Tool.

npm vs bower

Como es sabido en el mundo front, existe otro gran instalador de packages denominado bower. Su mayor diferencia, creo, respecto a npm es la manera en que gestiona las dependencias profundas, esto es, las dependencias de las que cosas que vamos instalando. Imaginemos por ejemplo el siguiente escenario:

La librería A funciona con jQuery.

La librería B también funciona con jQuery.

npm instala A y B y, además, instala dos veces jQuery, mientras que bower se supone que solo instala A y B y una sola vez jQuery, ya que está optimizado para instalar cosas que van directamente a producción, a la versión final.

Ya sea por esta razón, por inercia, por los paquetes que había en un instalador u otro o por cualquier otra razón, el caso es que esta diferenciación todavía hoy sigue vigente... más o menos. Por ejemplo, el package de angular de yeoman, otra herramienta de la que hablaré después, trabaja con los dos instaladores. En los node_modules que baja con el npm están todas las herramientas que necesitamos en desarrollo, como el grunt o el karma para los test.

"devDependencies": {

"autoprefixer-core": "^5.2.1",

"grunt": "^0.4.5",

"grunt-angular-templates": "^0.5.7",

"grunt-concurrent": "^1.0.0",

"grunt-contrib-clean": "^0.6.0",

"grunt-contrib-concat": "^0.5.0",

...

"karma-jasmine": "*",

"karma-phantomjs-launcher": "*"

}

En cambio, en bower_components se instalan todas las cosas que necesitará la aplicación para estar operativa cuando se esté ejecutando al final, como la propia librería angular y sus dependencias habituales o el bootstrap.

"dependencies": {

"angular": "^1.4.0",

"bootstrap": "^3.2.0",

"angular-animate": "^1.4.0",

"angular-aria": "^1.4.0",

"angular-cookies": "^1.4.0",

"angular-messages": "^1.4.0",

Sin embargo, como hemos visto, con npm podemos diferenciar entre dependencias develop y normales y, en general, es fácil controlar las dependencias comunes, por lo que da un poco igual que se repita durante la instalación tal o cual cosa porque luego no las enlazaremos desde el index. Y, por añadidura, en determinadas arquitecturas que explicaré algún día, como las que tiran de browserify y similares todo va con el npm, todo lo cual está favoreciendo cierta tendencia a decantarse por el npm en detrimento del bower; sin embargo, dado que polymer está tirando de este último instalador, es de esperar que cobre de nuevo impulso.

En cualquier caso, personalmente esta diferenciación me sigue pareciendo útil en muchos casos y bower me sigue pareciendo una herramienta viva, pero bueno, pá gustos los colores, que reza el dicho popular.

Para el lector interesado en bower, recomiendo el artículo Crear un package en Bower de Miguel Ángel Álvarez.

yeoman

Mención aparte en esta entrada sobre npm y los instaladores en general merece yeoman, un proyecto desarrollado por titanes la talla de Addy Osmani, Eric Bidelman o Paul Irish.

Yeoman va más allá y no solo instala tal o cual cosa, sino el scaffolding entero que puede necesitar una aplicación. Esto es: todas las dependencias, de desarrollo y producción, pero además la estructura básica y los archivos de configuración que se suelen necesitar, como el que usan los editores, el grunt, el git, etcétera. Es la bomba. En apenas unos minutos, según la conexión, podemos tener un proyecto de la complejidad de angular funcionando. Y para que nos hagamos una idea de lo que significa complejidad, estoy hablando de más de 30.000 archivos.

Tengo pendiente una entrada específica hablando de esta gran herramienta, así que de momento me limito a decir que no es una alternativa a npm, sino un complemento y que para determinados proyectos, como los que corren en angular, es fundamental.

 

|| Tags: , ,

valoración de los lectores sobre introducción a npm

  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • estrellica valoración positiva
  • 5 sobre 5 (3 votos)

¿Te ha parecido útil o interesante esta entrada?
dormido, valoración 1 nadapensativo, valoración 2 un poco sonrisa, valoración 3 a medias guiño, valoración 4 bastante aplauso, valoración 5 mucho

Tú opinión es muy importante, gracias por compartirla!

Los comentarios están cerrados.