Gestión de paquetes en Monorepos

Rate this content
Bookmark

Hablaremos sobre algunos de los puntos problemáticos y exploraremos recetas para una gestión de paquetes efectiva en Monorepos.
Discutiremos cómo funciona la gestión de paquetes con npm, pnpm y Yarn. Además, te mostraré una nueva herramienta que es menos conocida pero mejora mucho la experiencia del desarrollador.

Zoltan Kochan
Zoltan Kochan
19 min
15 Feb, 2024

Comments

Sign in or register to post your comment.

Video Summary and Transcription

Esta charla aborda los puntos problemáticos y la gestión de paquetes efectiva en Monorepos, incluido el uso de diseños hoisted o aislados y los desafíos de trabajar con dependencias entre pares. Presenta la herramienta Bit, que aborda estos problemas y maneja la gestión de dependencias y el control de versiones. Bit permite la instalación y gestión automática de dependencias, admite múltiples versiones de una dependencia entre pares y actualiza los componentes de manera transparente en diferentes entornos.

Available in English

1. Introducción a la Gestión de Paquetes en Monorepos

Short description:

Mi nombre es Zoltan Koçan. Hablaré sobre los puntos problemáticos y compartiré recetas para una gestión efectiva de paquetes en monorepos. Me encargo de la gestión de dependencias en Bit y soy el principal mantenedor del proyecto pnpm. La historia de las herramientas de monorepo para proyectos JS comienza con Babel y Lerna. Para el año 2017, pnpm, Yarn y npm ya ofrecían soporte para monorepos. Los gestores de paquetes pueden organizar las dependencias en diseños hoisted o aislados, siendo pnpm el que utiliza el diseño aislado de módulos de nodos.

Mi nombre es Zoltan Koçan. En mi presentación, quiero hablar sobre la gestión de paquetes en monorepos. Discutiré algunos de los puntos problemáticos y compartiré recetas para una gestión efectiva de paquetes en monorepos.

Actualmente, trabajo en Bit, donde me encargo de las tareas relacionadas con la gestión de dependencias. También soy el principal mantenedor del proyecto de código abierto pnpm, que es un gestor de paquetes JS. Antes de Bit, trabajé en JustAnswer. En JustAnswer teníamos un monorepo enorme con cientos de componentes. La instalación con npm llevaba 30 minutos en ese monorepo. Esa fue la principal razón por la que empecé a contribuir a una alternativa más rápida, pnpm. Con pnpm, pudimos reducir el tiempo de instalación a unos 90 segundos.

Veamos brevemente la historia de las herramientas de monorepo para proyectos JS. Babel fue uno de los proyectos más influyentes en el ecosistema de JavaScript y probablemente fue uno de los primeros proyectos JS de código abierto populares que utilizó un monorepositorio. Los creadores de Babel crearon Lerna en 2015. Lerna podía instalar dependencias en un monorepo utilizando npm-cli bajo el capó. Dicho esto, la instalación con Lerna era terriblemente lenta, por decir lo menos. Todos sabían que los gestores de paquetes deberían implementar la instalación en monorepos de forma nativa. Para el año 2017, tanto pnpm como Yarn habían lanzado soporte para monorepos. Yarn llamó a esta característica instalación de workspaces, mientras que pnpm utilizó el término singular workspace. En un par de años, npm también lanzó soporte para workspaces. A día de hoy, hay tres gestores de paquetes maduros y populares de Node.js con soporte integrado para monorepos.

Existen dos formas en que los gestores de paquetes pueden organizar las dependencias en un monorepo: hoisted e aislado. Los tres gestores de paquetes admiten ambos diseños. Por defecto, Yarn y npm utilizan un enfoque hoisted. Con este enfoque, todas las dependencias directas e indirectas se colocan en el directorio raíz no-modules. Si hay varias versiones de las mismas dependencias, una de las versiones se anida. Como puedes ver en esta diapositiva, hay dos versiones diferentes de lodash. Por lo tanto, una de las versiones se anida en la raíz del monorepo, mientras que la otra se anida dentro de app2. pnpm utiliza un diseño diferente llamado módulos de nodos aislados. Con los módulos de nodos aislados, las dependencias de cada paquete se anidan. La ventaja de este enfoque es que los paquetes solo tienen acceso a sus propias dependencias.

2. Gestión de Dependencias en Monorepos

Short description:

Mientras que con el diseño hoisted, todos los proyectos tendrían acceso al paquete cookie. Es realmente fácil desordenar las dependencias en un monorepo. Main.js en app1 está utilizando lodash que se encuentra en las dev.dependencies. Trabajar con dependencias entre pares en monorepos es un desafío. Es crucial utilizar una única versión de la dependencia entre pares en todos los paquetes del espacio de trabajo. Solo Yarn admite actualmente la sincronización de versiones de dependencias de forma nativa. pnpm tiene planes de introducir esta función a través de los catálogos del espacio de trabajo. pnpm ofrece una función para admitir múltiples versiones de una dependencia entre pares conocida como dependencias inyectadas.

Mientras que con el diseño hoisted, todos los proyectos tendrían acceso al paquete cookie, con un diseño de módulos de nodo aislado, los proyectos solo tienen acceso a sus propias dependencias. Por lo tanto, en este caso, solo app1 podrá requerir cookie.

Creo que la mayoría de las personas están de acuerdo en que los monorepos brindan una experiencia de desarrollo superior. A pesar de esto, es realmente fácil desordenar las dependencias en un monorepo. Como se puede ver en este ejemplo, la aplicación está utilizando una cookie pero no la lista en sus dependencias. Este código funcionará localmente porque la cookie se encuentra en el directorio de módulos de nodo de un directorio padre. Sin embargo, se romperá cuando alguien instale app1 fuera del monorepo.

Otro problema en este ejemplo es que main.js en app1 está utilizando lodash. Main.js es código de producción, pero lodash está listado en las dev.dependencies. Esto significa que este código funcionará localmente, pero se romperá en producción donde no se instalan las dev.dependencies. Para detectar estos dos problemas específicos, puedes utilizar una regla especial en eslint, la regla de noextraneous dependencies del complemento de importación. Si configuras esta regla de linting, eslint te notificará las dependencias que se importan pero no se declaran en package.json. En este ejemplo, recibirás un error sobre el uso de cookie en app1. eslint también te notificará que lodash es una dev.dependency. Puedes evitarlo si se utiliza en código de producción.

Trabajar con dependencias entre pares en monorepos es un desafío. Es crucial que las dependencias entre pares sean únicas durante la ejecución. Si es posible, debes intentar utilizar una única versión de la dependencia entre pares en todos los paquetes del espacio de trabajo. Como se puede ver en este ejemplo, tanto card como button hacen referencia a la misma versión de React. Esto funcionará bien. Ya sea que estés lidiando con dependencias entre pares o no, es preferible utilizar la misma versión de una dependencia en todos tus proyectos. Hacerlo puede ayudarte a evitar problemas relacionados con las dependencias entre pares y reducir el tamaño de tus paquetes. Hasta donde yo sé, solo Yarn admite actualmente la sincronización de versiones de dependencias de forma nativa utilizando restricciones. pnpm tiene planes de introducir esta función a través de los catálogos del espacio de trabajo. También es posible utilizar herramientas de terceros para encontrar duplicados de versiones. Varios herramientas de terceros actúan como linters para verificar la inconsistencia de versiones. Una de estas herramientas es Syncpack. En monorepos grandes, a veces puede resultar desafiante evitar tener múltiples versiones de una dependencia entre pares. Entre npm, yarn y pnpm, solo pnpm ofrece una función para admitir múltiples versiones de una dependencia entre pares. Esta función se conoce como dependencias inyectadas.

3. Dependencias Inyectadas e Introducción a Bit

Short description:

Cuando se habilitan las dependencias inyectadas, los paquetes del espacio de trabajo se copian, lo que les permite ejecutarse con diferentes versiones del par. Después de discutir los desafíos asociados con los monorepos, me gustaría presentar otra herramienta que aborda estos problemas de manera integral. El nombre de la herramienta es Bit. Es una cadena de herramientas diseñada para construir software componible. Un espacio de trabajo de Bit se asemeja a un espacio de trabajo de pnpm, pero no hay paquetes en archivos en un espacio de trabajo de Bit. Todas las dependencias para todos los componentes se declaran en un solo manifiesto ubicado en la raíz del espacio de trabajo.

Cuando se habilitan las dependencias inyectadas, los paquetes del espacio de trabajo se copian, lo que les permite ejecutarse con diferentes versiones del par. Como se puede ver en este ejemplo, el componente Button utiliza la versión 17 de React, pero el componente Card utiliza la versión 16 de React. Cuando ejecutamos pruebas para el componente Button, queremos utilizar la versión 17 de React. En cambio, cuando ejecutamos el componente Button desde dentro del componente Card, queremos que Button utilice la misma versión de React que Card. Por lo tanto, se instala la versión 17 de React en el directorio node_modules de Button. Mientras tanto, Card no hace referencia directamente a Button desde el espacio de trabajo, sino desde un subdirectorio oculto donde se alinea con la versión 16 de React. Esta configuración significa que hay dos instancias del componente Button en el espacio de trabajo, una con la versión 17 de React y otra, una copia dentro del directorio node_modules.pnpm con la versión 16 de React. La única desventaja de este enfoque es que una vez que se modifica el componente Button, es necesario volver a ejecutar el proceso de instalación para que pnpm pueda actualizar los archivos con el componente Button en las instancias copiadas.

Después de discutir los desafíos asociados con los monorepos, me gustaría presentar otra herramienta que aborda estos problemas de manera integral. El nombre de la herramienta es Bit. Si bien Bit no es un gestor de paquetes, la gestión de paquetes es una de sus principales responsabilidades. Entonces, ¿qué es exactamente Bit? Es una cadena de herramientas diseñada para construir software componible. Puedes conceptualizarlo como una alternativa a Git, GitHub, el registro de npm y varios clientes de npm. Al utilizar Bit, sirve como tu sistema de control de versiones, administra tus dependencias y publica tus paquetes. Para esta presentación, nos centraremos únicamente en la gestión de paquetes, por lo que solo discutiré el aspecto de instalación de Bit.

De muchas maneras, un espacio de trabajo de Bit se asemeja a un espacio de trabajo de pnpm. Es una colección de paquetes o componentes. Sin embargo, hay una diferencia distintiva, ya que no hay paquetes en archivos en un espacio de trabajo de Bit. En su lugar, todas las dependencias para todos los componentes se declaran en un solo manifiesto ubicado en la raíz del espacio de trabajo. Además, no hay un campo separado para las dependencias de desarrollo. Este enfoque simplificado es factible porque Bit realiza un análisis de código de los componentes dentro del espacio de trabajo. Identifica automáticamente qué componentes utilizan qué dependencias y distingue si una dependencia en particular es para producción o desarrollo para un componente dado. Permíteme mostrarte ahora una demostración rápida de un espacio de trabajo de Bit. Para la demostración, utilizaré VS Code con la extensión de Bit instalada. Como puedes ver, ya lo tengo instalado en mi computadora. Vamos a la sección de Bit y comencemos un nuevo espacio de trabajo. Bit ha creado un manifiesto de espacio de trabajo para mí. Ahora generemos algunos componentes nuevos utilizando la herramienta de línea de comandos de Bit. Crearé dos nuevas aplicaciones de nodo, app1 y app2. Aquí están los directorios de mis componentes de aplicaciones recién creados.

4. Gestión de Dependencias con Bit

Short description:

Como puedes ver, ni app1 ni app2 contienen paquetes en archivos. Bit ejecuta pnpm install para instalar las dependencias. Añadamos nuevas declaraciones de importación para lodash y ramda. Bit añadirá automáticamente las nuevas dependencias al espacio de trabajo. Después de la instalación, las nuevas dependencias son visibles en los detalles del componente. Bit también maneja el control de versiones. Los cambios en las dependencias pueden ser gestionados fácilmente. Bit detecta automáticamente los cambios en los tipos de dependencia.

Como puedes ver, ni app1 ni app2 contienen paquetes en archivos. Bit crea dinámicamente los paquetes en archivos al publicar. En el fondo, Bit ejecuta pnpm install para instalar cualquier dependencia. Como puedes ver, aquí está la salida de pnpm. Ahora instala algunas dependencias que están presentes de forma predeterminada en los componentes de la aplicación de nodo.

Volvamos al menú de Bit. Aquí podemos ver la lista de nuestros componentes. Como puedes ver en los detalles del componente, las dependencias del componente. Añadamos algunas nuevas declaraciones de importación. Añadiré lodash a app1 y ramda a app2. Como puedes ver, estas dependencias actualmente faltan. En un espacio de trabajo de pnpm, ejecutarías algo como pnpm add para la dependencia de app1 lodash y add para la dependencia de app2 ramda. Ahora con Bit, es más fácil. Solo necesitas ejecutar bit install add missing deps y Bit realizará un análisis de código, encontrará cualquier nueva declaración de importación con dependencias que aún no estén instaladas en el espacio de trabajo y automáticamente añadirá estas nuevas dependencias al espacio de trabajo.

Una vez que la instalación finalice, debemos poder ver las nuevas dependencias en los detalles del componente. Así que sí, aquí está. Ahora lodash está en las dependencias de app1 y ramda está en las dependencias de app2. También podemos ver que estos nuevos paquetes aparecieron en el manifiesto del espacio de trabajo aquí y se instalaron en node_modules ramda lodash. Ahora hagamos commit a nuestros cambios. Usaré Bit para hacer el commit de los cambios porque Bit también es un sistema de control de versiones. También puedes usar Bit con git, no hay problema. Ahora hagamos algunos cambios en las dependencias nuevamente. Así que ahora eliminaré lodash de app1 TS y lo moveré a appspec TS. Ahora se convierte en una dependencia de desarrollo. Y también eliminemos completamente ramda de app2. Ahora ejecutemos la instalación. En un espacio de trabajo de pnpm, después de hacer estos cambios, tendrías que actualizar manualmente los paquetes en app1. Tendrías que eliminar lodash de la sección de dependencias y ponerlo en la sección de dependencias de desarrollo. Con Bit esto no es necesario. Detecta automáticamente que el tipo de la dependencia ha cambiado.

5. Gestión Avanzada de Dependencias con Bit

Short description:

Con Bit, no es necesario eliminar manualmente las dependencias. Bit maneja automáticamente los cambios en los tipos de dependencia. Bit también facilita la compilación de paquetes, permitiendo el soporte de múltiples versiones de una dependencia entre pares. Los componentes se cargan desde entornos separados según sus dependencias. Bit actualiza los componentes de manera transparente en todos los entornos.

Y también con pnpm tendrías que eliminar manualmente ramda de las dependencias de app2. Pero con Bit esto no es necesario. Como puedes ver aquí en los detalles del componente, ramda no está en las dependencias de app2. Y en app1, lodash ahora es una dependencia de desarrollo, no una dependencia de producción. Esto sucedió automáticamente bajo el capó. No se requirió ninguna acción por parte del usuario. Si revisamos los cambios, también podemos ver cualquier cambio en las dependencias. Y podemos ver que en app1, lodash cambió de una dependencia de tiempo de ejecución o producción a una dependencia de desarrollo. Y en app2, ramda se eliminó por completo.

Además de gestionar las dependencias, Bit también maneja la compilación de paquetes dentro del espacio de trabajo. Esto facilita considerablemente el soporte de múltiples versiones de una dependencia entre pares en comparación con pnpm. Como se ilustra en esta diapositiva, nuestro espacio de trabajo contiene cuatro componentes. Dos páginas, un botón y una tarjeta. Queremos usar dos versiones de React en este espacio de trabajo. Entonces Bit crea dos entornos de ejecución separados para los componentes. Uno con React v16 y otro con React v17. Los componentes que dependen de React v16 se cargan desde el entorno correspondiente junto con todas sus dependencias. De manera similar, los componentes que dependen de React v17 se cargarán desde el otro entorno. Todas sus dependencias utilizarán React v17. Si hay algún cambio en un componente, Bit actualizará ese componente de manera transparente en todos los entornos.

Eso es todo lo que quería compartir con ustedes hoy. Gracias a todos. Adiós.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Levelling up Monorepos with npm Workspaces
DevOps.js Conf 2022DevOps.js Conf 2022
33 min
Levelling up Monorepos with npm Workspaces
Top Content
Learn more about how to leverage the default features of npm workspaces to help you manage your monorepo project while also checking out some of the new npm cli features.
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm
The Zen of Yarn
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
The Zen of Yarn
In the past years Yarn took a spot as one of the most common tools used to develop JavaScript projects, in no small part thanks to an opinionated set of guiding principles. But what are they? How do they apply to Yarn in practice? And just as important: how do they benefit you and your projects?
In this talk we won't dive into benchmarks or feature sets: instead, you'll learn how we approach Yarn’s development, how we explore new paths, how we keep our codebase healthy, and generally why we think Yarn will remain firmly set in our ecosystem for the years to come.
End the Pain: Rethinking CI for Large Monorepos
DevOps.js Conf 2024DevOps.js Conf 2024
25 min
End the Pain: Rethinking CI for Large Monorepos
Scaling large codebases, especially monorepos, can be a nightmare on Continuous Integration (CI) systems. The current landscape of CI tools leans towards being machine-oriented, low-level, and demanding in terms of maintenance. What's worse, they're often disassociated from the developer's actual needs and workflow.Why is CI a stumbling block? Because current CI systems are jacks-of-all-trades, with no specific understanding of your codebase. They can't take advantage of the context they operate in to offer optimizations.In this talk, we'll explore the future of CI, designed specifically for large codebases and monorepos. Imagine a CI system that understands the structure of your workspace, dynamically parallelizes tasks across machines using historical data, and does all of this with a minimal, high-level configuration. Let's rethink CI, making it smarter, more efficient, and aligned with developer needs.
Yarn 4 - Modern Package Management
JSNation 2022JSNation 2022
28 min
Yarn 4 - Modern Package Management
Top Content
Yarn 4 is the next major release of your favourite JavaScript package manager, with a focus on performance, security, and developer experience. All through this talk we'll go over its new features, major changes, and share our long-term plans for the project.If you only heard about Yarn without trying it yet, if you're not sure why people make such a fuss over package managers, if you wonder how your package manager can make your work simpler and safer, this is the perfect talk for you!
Federated Microfrontends at Scale
React Summit 2023React Summit 2023
31 min
Federated Microfrontends at Scale
Top Content
The talk will be a story of how Personio went from rendering through a Monolithical PHP architecture, to a microfrontend oriented Next JS app, powered by Module Federation and the NX monorepo toolchain.

Workshops on related topic

React at Scale with Nx
React Summit 2023React Summit 2023
145 min
React at Scale with Nx
Top Content
Featured WorkshopFree
Isaac Mann
Isaac Mann
We're going to be using Nx and some its plugins to accelerate the development of this app.
Some of the things you'll learn:- Generating a pristine Nx workspace- Generating frontend React apps and backend APIs inside your workspace, with pre-configured proxies- Creating shared libs for re-using code- Generating new routed components with all the routes pre-configured by Nx and ready to go- How to organize code in a monorepo- Easily move libs around your folder structure- Creating Storybook stories and e2e Cypress tests for your components
Table of contents: - Lab 1 - Generate an empty workspace- Lab 2 - Generate a React app- Lab 3 - Executors- Lab 3.1 - Migrations- Lab 4 - Generate a component lib- Lab 5 - Generate a utility lib- Lab 6 - Generate a route lib- Lab 7 - Add an Express API- Lab 8 - Displaying a full game in the routed game-detail component- Lab 9 - Generate a type lib that the API and frontend can share- Lab 10 - Generate Storybook stories for the shared ui component- Lab 11 - E2E test the shared component
Node Monorepos with Nx
Node Congress 2023Node Congress 2023
160 min
Node Monorepos with Nx
Top Content
WorkshopFree
Isaac Mann
Isaac Mann
Multiple apis and multiple teams all in the same repository can cause a lot of headaches, but Nx has you covered. Learn to share code, maintain configuration files and coordinate changes in a monorepo that can scale as large as your organisation does. Nx allows you to bring structure to a repository with hundreds of contributors and eliminates the CI slowdowns that typically occur as the codebase grows.
Table of contents:- Lab 1 - Generate an empty workspace- Lab 2 - Generate a node api- Lab 3 - Executors- Lab 4 - Migrations- Lab 5 - Generate an auth library- Lab 6 - Generate a database library- Lab 7 - Add a node cli- Lab 8 - Module boundaries- Lab 9 - Plugins and Generators - Intro- Lab 10 - Plugins and Generators - Modifying files- Lab 11 - Setting up CI- Lab 12 - Distributed caching
Finding, Hacking and fixing your NodeJS Vulnerabilities with Snyk
JSNation 2022JSNation 2022
99 min
Finding, Hacking and fixing your NodeJS Vulnerabilities with Snyk
WorkshopFree
Matthew Salmon
Matthew Salmon
npm and security, how much do you know about your dependencies?Hack-along, live hacking of a vulnerable Node app https://github.com/snyk-labs/nodejs-goof, Vulnerabilities from both Open source and written code. Encouraged to download the application and hack along with us.Fixing the issues and an introduction to Snyk with a demo.Open questions.
Build Web3 apps with React
React Summit 2022React Summit 2022
51 min
Build Web3 apps with React
WorkshopFree
Shain Dholakiya
Shain Dholakiya
The workshop is designed to help Web2 developers start building for Web3 using the Hyperverse. The Hyperverse is an open marketplace of community-built, audited, easy to discover smart modules. Our goal - to make it easy for React developers to build Web3 apps without writing a single line of smart contract code. Think “npm for smart contracts.”
Learn more about the Hyperverse here.
We will go over all the blockchain/crypto basics you need to know to start building on the Hyperverse, so you do not need to have any previous knowledge about the Web3 space. You just need to have React experience.