Qué son los Workspaces de npm con los que puedes crear monorepositorios de una manera sencilla. En qué situaciones les podemos sacar partido y cómo configurar un proyecto con workspaces.
Hoy vamos a explicar qué son y cómo trabajar con workspaces de npm. Pero antes de comenzar, aclaremos que npm es el gestor de paquetes predeterminado para Node.js. Como seguramente sepas, corresponde con las siglas de "Node Package Manager". Aunque sea un gestor de paquetes creado para gestionar las dependencias de los proyectos en Node, se usa en Javascript en general para realizar también la gestión de dependencias en proyectos frontend.
Generalmente, cuando trabajamos con un proyecto donde se usa npm tenemos un único package.json a partir del que se gestiona la totalidad del proyecto, pero hay ocasiones en las que deseamos poder gestionar diversos proyectos relacionados, unidos en un mismo repositorio pero independientes entre sí y cada uno de ellos con sus propias dependencias.
Antes de que aparecieran los workspaces npm la gestión de estos varios pequeños proyectos en un mismo repositorio la teníamos que hacer con herramientas externas. Hoy podemos gestionar lo que llamamos "monorepositorios" gracias a los workspaces.
En el artículo Workspaces de npm encuentras los siguientes apartados de interés.
¿Qué son los workspaces de npm?
Los workspaces de npm son una funcionalidad integrada en npm (desde la versión 7) que permite gestionar múltiples paquetes JavaScript desde un solo repositorio raíz, facilitando el concepto del que puedes haber oído hablar: monorepositorios o "monorepos".
Los workspaces automatizan el enlace (symlinking) de paquetes locales durante npm install, eliminando la necesidad de comandos manuales como npm link, que a veces se hacen poco versátiles en el desarrollo del día a día.
Ventajas de los worspaces
Algunas ventajas de manejar repositorios en Workspaces se resumen en los siguientes puntos:
- Hace que puedas dividir el software en varios packages, pudiendo manejar las dependencias entre ellos de manera natural.
- Compartir
node_modulesraíz para ahorrar espacio y tiempo - Resolver dependencias internas vía symlinks, haciendo posible importar por el
namedelpackage.jsonde cada workspace, como lo harías si estuvieran publicados en npm. - Permite también desarrollar proyectos fullstack en un repositorio unificado, donde gestionas tus packages npm en el mismo proyecto que paquetes de otros frameworks backend.
En qué casos podemos querer workspaces
Gracias a los Workspaces optimizamos flujos de trabajo en proyectos con dependencias compartidas, como aplicaciones fullstack con backend y frontend en un mismo repo. Este sería un ejemplo clásico pero hay muchos más:
- Catálogos de componentes relacionados, donde queremos organizar los componentes en varios repositorios independientes dependiendo de la naturaleza de los componentes.
- Una biblioteca de código que depende de un proyecto pero que también puede tener vida propia, pudiendo reutilizarse a lo largo de otros proyectos.
- Repositorios donde tenemos varias patas, como una librería y el sitio de la documentación dirigido por un SSG
- Microservicios donde cada servicio se aloja en su propio package, formando parte de un mismo repositorio de código general.
Configuración básica de los workspaces en el package.json
Realmente trabajar con workspaces es mucho más fácil de lo que podría parecer. Simplemente teneos que agregar la propiedad workspaces en el package.json raíz, listando las carpetas donde tememos los distintos paquetes. Por ejemplo:
{
"name": "mi-proyecto",
"workspaces": ["packages/*"]
}
Esta configuración define un monorepo con npm workspaces. Es tan sencillo como eso:
- El campo name es el nombre de tu proyecto. Ten en cuenta que aquí irán todos los otros campos típicos del
package.json. - El campo
"workspaces": ["packages/*"]indica a npm que trate todas las subcarpetas dentro depackages/como paquetes independientes.
Eso quiere decir que en cada carpeta dentro de packages podremos tener un proyecto npm independiente, cada uno de ellos con su propio package.json.
Cómo trabajar con Workspaces
Dada la configuración de workspaces, ahora, al ejecutar npm install en la raíz:
- Se instalarán las dependencias de todos los workspaces en
node_modules. - Se crearán symlinks automáticos para que los paquetes se referencien por su
"name"(ej:@mi-proyecto/uidesdepackages/ui).
Otra cosa importante es que las dependencias serán compartidas. Esto quiere decir que si tenemos una dependencia en varios packages solo se instará una vez y será accesible desde cualquier workspace. Eso sí, si la vas a usar en el workspace la deberías declarar como dependencies o devDependencies en el package.json de ese workspace.
Ejecutar comandos npm sobre un Workspace
Cuando trabajas con workspaces de npm a veces necesitas ejecutar npm para realizar una acción sobre un workspace en particular. Para ello simplemente tienes que indicar --workspace=nombre_workspace o con el shortcut -w nombre_workspace.
Vamos a ver algunos ejemplos básicos que querrás usar en el día a día.
Inicializar un Workspace
Cuando quieras hacer el init de un workspace usa un comando con la ruta de tu workspace, como ves a continuación:
npm init -w ./packages/nuevo-paquete
Instalación de dependencias
Aparte de instalar dependencias globales para todo el repo puedes hacerlas específicas para un workspace con los flags mencionados --workspace o -w.
Si quieres instalar un package en raíz, compartido para todo el proyecto lo haces como estás acostumbrado:
npm install lit
Ahora bien, si lo que quieres es instalarlo de manera individual en un workspace en particular, lo haces así:
npm install @dile/ui -w utils
En este caso este package @dile/ui se instalará solamente en el paquete "utils".
Ejecución de scripts
En tu día a día también puedes necesitar ejecutar scripts en workspaces. Lo haces con los mismos flags comentados, con --workspaces (todos) o --workspace=nombre (específico):
npm run test --workspaces(ejecuta "test" en todos los workspaces del monorepositorio).npm run test --workspaces --if-present(lo mismo que el comando anterior, pero si en el workspace no existe ese comando, lo ignora)npm run build --workspace=utils(solo en el workspace utils).
Ejemplo de proyecto de desarrollo con Workspaces
Por si os apetece ver un proyecto real que está organizado como monorepositorio, con sus workspaces independientes, os podemos indicar que entréis a Dile Components en GitHub, que es el catálogo de componentes que desarrollamos en DesarrolloWeb.com y EscuelaIT.
En este repositorio veréis la configuración de workspaces en el package.json raíz y los distintos paquetes de componentes clasificados por ámbito en la carpeta packages/*. Cada package independiente en su workspace tiene su nombre y cuando se publica en npm se publica él solo. Como es un catálogo bastante extenso y hay componentes de todo tipo, para muchos casos de uso totalmente separados, a veces con dependencias bastante específicas para ciertos componentes, nos viene bien dividirlo en distintos packages.
Por ejemplo tienes @dile/ui para componentes de interfaz gráfica, @dile/crud para componentes para generar un CRUD o @dile/icons para componentes que permiten integrar iconos fácilmente, entre otros packages. Los desarrolladores que usan esos componentes solo necesitan instalar el package donde está el componente que requieren usar.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...