Cree un monorepository con espacios de trabajo de lerna e hilo

aprender e hilo

En los últimos años, el concepto de mono-repositorios se ha establecido con éxito, ya que puede simplificar significativamente el proceso de desarrollo de proyectos de software modular, como las infraestructuras basadas en microservicios. Las principales ventajas de este enfoque arquitectónico son obvias en la práctica, por lo tanto, propongo crear su propio mono-repositorio de prueba desde cero, al mismo tiempo que comprende los matices de trabajar con espacios de trabajo de hilo y lerna . Bueno, empecemos!

Considere la estructura de nuestro proyecto, que serán tres bibliotecas ubicadas en la carpeta paquetes / , así como package.json en el directorio raíz.

├── package.json └── packages ├── app │  ├── index.js │  └── package.json ├── first │  ├── index.js │  └── package.json └── second ├── index.js └── package.json 

Se entiende que tenemos dos bibliotecas independientes primero y segundo , así como una biblioteca de aplicaciones que importará funciones de las dos primeras. Por conveniencia, los tres paquetes se colocan en el directorio de paquetes . Puede dejarlos en la carpeta raíz o ponerlos en un directorio con cualquier otro nombre, pero para seguir las convenciones generalmente aceptadas, los colocaremos de esta manera.

Las bibliotecas primero y segundo para simplificar el experimento contendrán solo una función en index.js , cada una de las cuales devolverá una cadena de saludo en nombre del módulo. Para el primer ejemplo, se verá así:

 // packages/first/index.js const first = () => 'Hi from the first module'; module.exports = first; 

En el módulo de la aplicación , mostraremos el mensaje Hola desde la aplicación en la consola, así como saludos desde otros dos paquetes:

 // packages/app/index.js const first = require('@monorepo/first'); const second = require('@monorepo/second'); const app = () => 'Hi from the app'; const main = () => { console.log(app()); console.log(first()); console.log(second()); }; main(); module.exports = { app, main }; 

Para que el primero y el segundo estén disponibles en la aplicación , los denotamos como dependencias en dependencias .

Además, para cada biblioteca agregamos el prefijo @ monorepo / en el nombre del valor delante del nombre principal del paquete al paquete local.json .

 // packages/app/package.json { "name": "@monorepo/app", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@monorepo/first": "^1.0.0", "@monorepo/second": "^1.0.0" } } 

¿Por qué necesito un prefijo con un icono de perro delante del nombre del paquete npm (@ monorepo /)?
Agregar un prefijo es opcional, pero esta es exactamente la convención de denominación de paquetes a la que se adhieren muchos monorepositorios:
material ui , angular y otros. El hecho es que cada usuario u organización tiene su propio alcance en el sitio web npm , por lo que hay una garantía de que todos los módulos con @ somescope / postfix son creados por el equipo de somescope y no por los atacantes. Además, se hace posible llamar a los nombres de módulos que ya están en uso. Por ejemplo, no puede simplemente tomar y crear su propio módulo de utilidades , porque esa biblioteca ya existe . Sin embargo, agregando el postfix @ myscopename / podemos obtener nuestras utilidades ( @ myscopename / utils ) con blackjack y señoritas.

Un análogo de la vida real para nuestro proyecto de prueba puede ser varias bibliotecas para trabajar con datos, herramientas de validación, análisis o simplemente un conjunto de componentes de la interfaz de usuario. Si suponemos que vamos a desarrollar una aplicación web y móvil (por ejemplo, usando React y React Native, respectivamente), y tenemos parte de la lógica reutilizada, puede valer la pena ponerla en componentes separados, para su uso posterior en otros proyectos. Agregue a esto el servidor en Node.js y obtendrá un caso muy real de la vida.

Espacios de trabajo de hilo


El toque final antes de crear un repositorio mono completo será el diseño de package.json en la raíz de nuestro repositorio. Preste atención a la propiedad de espacios de trabajo : especificamos el valor de los paquetes / * , que significa "todas las subclaves en la carpeta de paquetes ". En nuestro caso, esta es la aplicación , primero , segundo .

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ] } 

Además, "private": true debe especificarse en package.json , ya que los espacios de trabajo solo están disponibles en proyectos privados.

Para que todo despegue, ejecute el comando yarn (de forma análoga a yarn install o npm install ) desde el directorio raíz. Dado que las dependencias que existen en el módulo de la aplicación se definen como espacios de trabajo en el paquete raíz.json , de hecho, no descargaremos nada de npm-Registry , sino que simplemente enlazaremos (" enlazaremos ") nuestros paquetes.

 yarn 

imagen

Ahora podemos ejecutar el comando del nodo. desde el directorio raíz que ejecutará el script desde el archivo packages / app / index.js .

 node . 

imagen

Veamos como funciona. Al llamar a yarn , creamos enlaces simbólicos en node_modules a nuestros directorios en la carpeta de paquetes .

imagen

Debido a esta relación en las dependencias, obtuvimos una gran ventaja: ahora, al cambiar en el primer y segundo módulo, nuestra aplicación recibirá la versión actual de estos paquetes sin reconstruirla. En la práctica, es muy conveniente, porque podemos llevar a cabo el desarrollo local de paquetes, aún definiéndolos como dependencias de terceros (que eventualmente se convierten).

La siguiente ventaja importante que puede obtener al trabajar con espacios de trabajo de hilo es la organización del almacenamiento de dependencias de terceros.

Obtenga más información sobre el almacenamiento de dependencias en el nivel superior.
Supongamos que queremos usar la biblioteca lodash en primer y segundo lugar . Al ejecutar el comando yarn add lodash desde los directorios apropiados, recibiremos una actualización del paquete local.json : la versión actual del paquete aparecerá en las dependencias .
 "dependencies": { "lodash": "^4.17.11" } 

En cuanto al paquete lodash en sí , físicamente la biblioteca se instalará en node_modules en el nivel raíz una vez.
Si la versión requerida del paquete externo (en nuestro caso lodash ) es diferente para el primero y el segundo (por ejemplo, primero necesita lodash v3.0.0 , y en el segundo v4.0.0 ), entonces un paquete con una versión inferior ( 3.0.0 ) llegará a la raíz node_modules , y la versión lodash para el segundo módulo se almacenará en paquetes locales / second / node_modules .
Además de las ventajas, este enfoque puede tener desventajas menores, que el hilo permite evitar con la ayuda de banderas adicionales. Puede leer más sobre tales matices en la documentación oficial .

Añadir Lerna


El primer paso para trabajar con lerna es instalar el paquete. Por lo general, realizan una instalación global ( yarn global add lerna o npm i -g lerna ), pero si no está seguro de si desea usar esta biblioteca, puede usar la llamada usando npx .

Inicializaremos lerna desde el directorio raíz:

 lerna init 

imagen

De hecho, realizamos varias acciones a la vez con la ayuda de un comando: creamos un repositorio git (si no se había inicializado antes), creamos un archivo lerna.json y actualizamos nuestro paquete raíz.json .

Ahora en el archivo lerna.json recién creado , agregue dos líneas: “npmClient”: “yarn” y “useWorkspaces”: true . La última línea dice que ya usamos espacios de trabajo de hilo y no hay necesidad de crear la carpeta app / node_modules con enlaces simbólicos a primero y segundo .

 // lerna.json { "npmClient": "yarn", "packages": [ "packages/*" ], "version": "1.0.0", "useWorkspaces": true } 

Pruebas con Lerna


Para mostrar la conveniencia de trabajar con lerna, agregue pruebas para nuestras bibliotecas.
Desde el directorio raíz, instalamos el paquete para probar - jest . Ejecute el comando:

 yarn add -DW jest 

¿Por qué necesito la bandera -DW?
El indicador -D (- dev) es necesario para que el paquete jest se instale como una dependencia de desarrollo, y el indicador -W (- ignore-workspace-root-check) permite la instalación en el nivel raíz (que necesitamos).

El siguiente paso es agregar un archivo de prueba a nuestro paquete. Para la conveniencia de nuestro ejemplo, haremos todas las pruebas similares. Para el primer ejemplo, el archivo de prueba se verá así:

 // packages/first/test.js const first = require('.'); describe('first', () => { it('should return correct message', () => { const result = first(); expect(result).toBe('Hi from the first module'); }); }); 

También necesitamos agregar un script para ejecutar pruebas en package.json de cada una de nuestras bibliotecas:

 // packages/*/package.json ... "scripts": { "test": "../../node_modules/.bin/jest --colors" }, ... 

El toque final será actualizar el paquete raíz.json . Agregue un script de prueba que llame a lerna run test --stream . El parámetro que sigue a lerna run define el comando que se llamará en cada uno de nuestros paquetes desde los paquetes / carpeta, y el indicador --stream nos permitirá ver la salida de los resultados en el terminal.

Como resultado, package.json del directorio raíz se verá así:

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } } 

Ahora, para ejecutar las pruebas, solo necesitamos ejecutar el comando desde la raíz de nuestro proyecto:

 yarn test 

imagen

Actualización de versión con Lerna


La próxima tarea popular, con la que lerna puede hacer frente a la calidad, será actualizar las versiones del paquete. Imagine que después de implementar las pruebas, decidimos actualizar nuestras bibliotecas de 1.0.0 a 2.0.0. Para hacer esto, simplemente agregue la línea "update: version": "lerna version --no-push" al campo de scripts del paquete raíz.json , y luego ejecute yarn update: version desde el directorio raíz. El indicador --no-push se agrega para que después de actualizar la versión los cambios no se envíen al repositorio remoto, lo que lerna hace por defecto (sin este indicador).

Como resultado, nuestro paquete raíz.json se verá así:

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream", "update:version": "lerna version --no-push" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } } 

Ejecute el script de actualización de versión:

 yarn update:version 

A continuación, se nos pedirá que seleccionemos la versión a la que queremos cambiar:

imagen

Al hacer clic en Entrar , obtenemos una lista de paquetes en los que se actualiza la versión.

imagen

Confirmamos la actualización ingresando y y recibimos un mensaje sobre la actualización exitosa.

imagen

Si tratamos de ejecutar el comando git status , no recibimos nada para confirmar, trabajando en árbol limpio , porque La versión lerna no solo actualiza las versiones del paquete, sino que también crea un git commit y una etiqueta que indica la nueva versión (v2.0.0 en nuestro caso).

Características de trabajar con el equipo de la versión lerna
Si agrega la línea "versión": "versión lerna --no-push" en lugar de "actualización: versión": "versión lerna --no-push" en el campo de los scripts del paquete raíz.json , lo más probable es que encuentre un comportamiento inesperado y consola roja El hecho es que npm-scripts por defecto llama al comando de versión (script reservado) inmediatamente después de actualizar la versión del paquete, lo que conduce a una llamada recursiva a la versión lerna . Para evitar esta situación, es suficiente darle al script un nombre diferente, por ejemplo, actualización: versión , como se hizo en nuestro ejemplo.

Conclusión


Estos ejemplos muestran una centésima parte de todas las posibilidades que lerna tiene en conjunción con espacios de trabajo de hilo . Desafortunadamente, hasta ahora no he encontrado instrucciones detalladas para trabajar con monorepositorios en ruso, ¡así que podemos suponer que se ha comenzado!

Enlace al repositorio del proyecto de prueba.

Source: https://habr.com/ru/post/448766/


All Articles