npm es el gestor de paquetes de Node.js, y con el tiempo se ha convertido en la herramienta indispensable de casi todos los programadores, y desde luego de los desarrolladores web Front-End, pues ya hace mucho que dejó de ser coto exclusivo de los que trabajan con Node.js.
npm te permite gestionar dependencias de tus proyectos, tanto para desarrollo como para producción, y también se ha convertido en el task runner más utilizado, desplazando a herramientas como Grunt (casi desaparecido en combate) y Gulp (aunque este resiste mejor el embate).
Aún así no está exento de problemas, fundamentalmente dos: es lento, y el orden de instalación de las dependencias no era predecible. Estos no son realmente problemas importantes en proyectos pequeños, pero sí lo son cuando manejas proyectos de gran tamaño entre muchas personas.
Yarn al rescate
Por este motivo Facebook lanzó Yarn el año pasado: para solventar estos dos problemas con sus propios proyectos, algunos de los cuales son muy grandes. Esto hacía que el uso de npm ralentizara enormemente la puesta en marcha y además provocase algunos conflictos debido a la falta de predictibilidad a la hora de instalar paquetes.
La falta de predictibilidad es importante puesto que la estructura de archivos que hay en la carpeta donde se guardan los paquetes (node_modules
) puede variar a medida que aparecen dependencias duplicadas y se añaden sobre las existentes, sobre todo si es el mismo paquete pero con diferentes versiones. Como npm instala las dependencias de forma "no determinista", es decir, que en cada instalación el orden de cada paquete y sus dependencias puede ser diferente, esto puede provocar que dos desarrolladores del mismo proyecto, haciendo un npm install
sobre el mismo archivo package.json
, obtengan dos carpetas node_modules
diferentes. En ciertos casos esto puede provocar que un mismo código funcione en la máquina de un programador pero no en la de otro, y localizar el motivo es algo muy difícil en estos casos.
Yarn ofrecía varias ventajas sobre npm:
- Eliminaba esa falta de predictibilidad, para lo cual generaba en la primera instalación un archivo
yarn.lock
que determinaba para el resto de los desarrolladores el orden apropiado de la misma.
- Es mucho más rápido a la hora de instalar los paquetes, incluso sin caché. Estamos hablando del orden de 2 a 3 veces más rápido en promedio. A veces más. Muy interesante y motivo por el cual muchos lo utilizamos.
- Ofrece opciones por defecto más sensatas: por ejemplo, en npm si te olvidas de especificar la opción
--save
o --save-dev
al instalar un paquete, éste se copia pero no queda guardado en modo alguno dentro de package.json
. Por lo tanto la instalación no te vale de mucho, puesto que otros programadores de tu equipo no tienen forma de saber que ese paquete se ha instalado. Y tú puede que tardes mucho en darte cuenta de que te falta la referencia ya que la tienes instalada en local 😖 Con Yarn esto no pasa. Cuando haces un yarn add nombre_paquete
no te hace falta indicar que estás instalando ni que debes guardarlo: es el comportamiento por defecto, lo cual tiene todo el sentido del mundo.
A mi Yarn me enamoró inmediatamente. Al ser 100% compatible con npm pero con mejores características, utilizarlo es una decisión muy sencilla.
npm se ha puesto las pilas
Fíjate en que en la lista anterior, algunos de los elementos están en tiempo pasado. Esto es así porque Yarn supuso un revulsivo para el equipo de npm, puesto que les marcó el camino a seguir y, por eso, el pasado 25 de mayo lanzaron npm v5. Esta nueva versión sigue la estela marcada por Yarn para solucionar la mayor parte de estos problemas.
Determinismo
A partir de la versión 5 de npm, se ha añadido un archivo package-lock.json
que hace la misma función que el de Yarn, es decir: conseguir instalaciones de paquetes "reproducibles". De este modo todos los programadores que se bajen el proyecto y ejecuten npm install
para descargar los paquetes referenciados en package.json
, obtendrán exactamente los mismos.
Ahora bien, la estrategia para conseguir el determinismo es diferente en ambas herramientas. En el caso de Yarn se necesitan tanto el archivo package.json
como el yarn.lock
para reproducir la instalación, mientras que en npm llega tan solo con el package-lock.json
.
Los formatos de archivo son también diferentes, pues Yarn usa un archivo de texto plano y npm, como se deduce de la extensión, utiliza JSON estándar.
Nota: si te estás preguntando si los archivos de lock, tanto de Yarn como de npm, es necesario almacenarlos en los repositorios de código... la repuesta está implícita en lo que acabamos de explicar y es lógicamente un rotundo sí. Son necesarios para conseguir esta reproductibilidad a la hora de instalar los paquetes.
Otro punto importante a tener en cuenta es que Yarn reproduce la instalación de los paquetes si todos los programadores están usando exactamente la misma versión de Yarn. En el caso de npm, mientras sea posterior a la 5.0.0, da igual que no todos tengan la más actualizada y siempre lo reproducirá bien.
En este sentido, npm 5 ha superado a Yarn.
Puedes ver los detalles en un post que lanzó Facebook sobre este tema unos días después.
Ganador: npm
Velocidad
La versión 5 de npm ha acelerado mucho la descarga e instalación de paquetes, pero no rivaliza todavía con Yarn.
Para comprobarlo he hecho una prueba sencilla para instalar los siguientes paquetes:
- babel-core
- babel-loader
- babel-plugin-syntax-dynamic-import
- babel-preset-es2015
- css-loader
- extract-text-webpack-plugin
- file-loader
- jquery
- purecss
- rimraf
- style-loader
- uglify-js
- url-loader
- webpack
- webpack-dev-server
que con sus dependencias suman 739 paquetes con un tamaño total de 40,9 MB. Vamos, una configuración bastante convencional de paquetes para trabajar con Webpack.
He instalado los paquetes desde cero (sin tener nada en caché y sin haber archivos de lock ni de Yarn ni de npm), para ver cuánto tardaban en instalarlos. Luego he repetido la prueba dejando ya la caché pero borrando los archivos de lock. Y finalmente con todo: caché y archivos de lock.
|
npm 5.3.0 |
Yarn 0.27.5 |
Sin caché, desde cero |
82.779s |
38.62s |
Con caché, sin arch. lock |
78.094s |
31.17s |
Con caché, con arch. lock |
53.402s |
23.88s |
Los resultados no son muy científicos porque los tiempos varían un poco de una ejecución a otra, y debería repetirlos varias veces, pero nos dan una idea grosso modo de las diferencias, en grandes números.
Pero, como podemos comprobar, Yarn sigue siendo bastante más rápido (más del doble) incluso con las mejoras de npm y su completa reescritura de la caché, gracias a la forma de procesar los paquetes que tiene Yarn, por fases y en paralelo.
Ganador: Yarn
Parámetros por defecto
Ahora npm instala los paquetes con la opción --save
por defecto, es decir, que sin indicar nada nos lo guarda en package.json
como una dependencia de la aplicación. Eso ya lo hacía Yarn antes y personalmente era una de las cosas que más me gustaba... Hoy en día con Webpack no es tan útil puesto que con esta herramienta casi todas tus dependencias son de tiempo de desarrollo, por lo que en ambos casos debes especificar --save-dev
al instalar de todos modos. O, como me gusta más a mí y uso siempre, con la opción abreviada -D
, que es más corta (y soy vago).
Ganador: empate
Cosas que tiene uno que no tiene el otro
Yarn tiene algunos comandos de los que no dispone npm, y que a mí personalmente me gustan mucho.
Por ejemplo, si ves las cientos de subcarpetas de tu carpeta nodemodules y quieres saber por qué exactamente uno de esos paquetes está ahí, en Yarn puedes escribir:
yarn why nombrePaquete
y te lo dirá inmediatamente:
Otro muy útil es:
yarn licenses generate-disclaimer > Licencias.txt
que genera de manera automática un texto con todas las licencias que estemos utilizando en nuestro proyecto.
y por fin:
yarn upgrade-interactive
que nos permite actualizar paquetes escogiendo qué queremos hacer con cada uno, no todos o uno por uno como ocurre en npm.
Ganador: Yarn
Conclusiones
Como acabamos de ver npm ha pegado un salto muy importante en la dirección adecuada con el lanzamiento de su versión 5.x, con todas las mejoras que hemos visto. La mayoría se han hecho precisamente para responder a Yarn y tratar de resolver los problemas existentes sin que los usuarios tengan que recurrir a otra herramienta.
Aún así, en mi opinión, Yarn sigue siendo una estupenda opción. De hecho en la mayor parte de los proyectos no habrá demasiada diferencia entre usar uno u otro. No obstante, y dado que Yarn es más rápido y tiene algunos detalles de los que carece de momento npm, yo sigo usando Yarn, y me consta que muchos programadores de todo el mundo también. Otra cosa que personalmente me gusta más y me hace preferirlo, es que su salida por la consola es mucho más limpia, usando barras de progreso y no miles de nombres de archivos que pasan a toda velocidad.
Al final, ahora es casi una opción de gusto personal.
Eso sí, uses uno u otro no te olvides de actualizar npm a la última versión. Para ello, si estás en Windows, recuerda que la mejor manera de hacerlo si no quieres problemas es la siguiente.
¡Espero que te sea útil!