Saltar al contenido principal

Pub workspaces (soporte para monorepos)

Aprende más sobre los pub workspaces, una forma de gestionar monorrepositorios de paquetes.

Cuando trabajas en un proyecto, es posible que desarrolles múltiples paquetes de Dart en el mismo repositorio de control de versiones (un monorrepositorio).

Por ejemplo, podrías tener un diseño de directorios como:

  • /
    • packages/
      • shared/
        • pubspec.yaml
        • pubspec.lock
        • .dart_tool/
          • package_config.json
      • client_package/
        • pubspec.yaml
        • pubspec.lock
        • .dart_tool/
          • package_config.json
      • server_package/
        • pubspec.yaml
        • pubspec.lock
        • .dart_tool/
          • package_config.json

Hay algunas desventajas en esta configuración:

  • Necesitas ejecutar dart pub get una vez para cada paquete.
  • Corres el riesgo de terminar con diferentes versiones de dependencias para cada paquete, lo que genera confusión al cambiar de contexto entre los paquetes.
  • Si abres la carpeta raíz en tu IDE, el dart analyzer creará contextos de análisis separados para cada paquete, lo que aumentará el uso de memoria.

Pub te permite organizar tu repositorio como un espacio de trabajo (workspace) utilizando una única resolución compartida para todos tus paquetes. El uso de espacios de trabajo para repositorios grandes reduce la cantidad de memoria requerida para el análisis, mejorando así el rendimiento.

Para crear un espacio de trabajo (workspace):

  • Agrega un pubspec.yaml en el directorio raíz del repositorio con una entrada workspace que enumere las rutas a los paquetes del repositorio (los paquetes del espacio de trabajo):

    yaml
    name: _
    publish_to: none
    environment:
      sdk: ^3.6.0
    workspace:
      - packages/shared
      - packages/client_package
      - packages/server_package
    
  • Para cada uno de los archivos pubspec.yaml existentes, asegúrate de que su restricción de SDK sea al menos ^3.6.0 y añade una entrada resolution:

    yaml
    environment:
      sdk: ^3.6.0
    resolution: workspace
    
  • Ejecuta dart pub get en cualquier parte del repositorio. Esto:

    • Creará un único archivo pubspec.lock al lado del pubspec.yaml raíz que contiene la resolución de todas las dependencies y dev_dependencies de todos los paquetes del espacio de trabajo.
    • Creará un único archivo .dart_tool/package_config.json compartido que asigna los nombres de los paquetes a las ubicaciones de los archivos.
    • Eliminará cualquier otro archivo pubspec.lock y .dart_tool/package_config.json existente al lado de los paquetes del espacio de trabajo.

Ahora la estructura de archivos se ve así:

  • /
    • packages/
      • shared/
        • pubspec.yaml
      • client_package/
        • pubspec.yaml
      • server_package/
        • pubspec.yaml
    • pubspec.yaml
    • pubspec.lock
    • .dart_tool/
      • package_config.json

Soporte para patrones glob

#

La entrada workspace admite patrones glob para incluir paquetes automáticamente:

yaml
workspace:
  - packages/*

Esto incluye todos los subdirectorios en packages/ que contienen un archivo pubspec.yaml, eliminando la necesidad de listar manualmente cada paquete. Esto es especialmente útil para monorrepositorios grandes o en frecuente crecimiento.

En lugar de:

yaml
workspace:
  - packages/shared
  - packages/client_package
  - packages/server_package

Puedes usar un patrón glob que detecte automáticamente los paquetes nuevos.

Espacios de trabajo (workspaces) anidados

#

Puedes anidar espacios de trabajo para organizar los paquetes jerárquicamente en repositorios grandes. Un miembro del espacio de trabajo puede declarar su propio campo workspace, al igual que el pubspec.yaml raíz.

Por ejemplo, si un paquete server divide su implementación en los subpaquetes auth y api, enuméralos en el campo workspace del paquete server:

packages/server/pubspec.yaml
yaml
name: server

resolution: workspace
environment:
  sdk: ^3.6.0

workspace:
  - auth
  - api

Luego marca cada subpaquete como que usa la resolución del espacio de trabajo:

packages/server/auth/pubspec.yaml
yaml
name: auth

resolution: workspace
environment:
  sdk: ^3.6.0

El pubspec.yaml raíz solo necesita enumerar packages/server. Pub descubre auth y api a través de la entrada workspace del paquete server y los incluye en la única resolución de dependencias compartida.

Archivos extraviados

#

Cuando migras un monorrepositorio existente para usar Pub workspaces, habrá archivos pubspec.lock y .dart_tool/package_config.json "extraviados" adyacentes a cada pubspec. Estos eclipsan los archivos pubspec.lock y .dart_tool/package_config.json colocados junto a la raíz.

Por lo tanto, pub get eliminará cualquier archivo pubspec.lock y .dart_tool/package_config.json ubicado en directorios entre la raíz e (incluyendo) cualquier paquete del espacio de trabajo.

  • /
    • packages/
      • foo/
        • pubspec.yaml # Miembro del espacio de trabajo
        • pubspec.lock # Eliminado por pub get
        • .dart_tool/package_config.json# Eliminado por pub get
      • pubspec.lock # Eliminado por pub get
      • .dart_tool/package_config.json# Eliminado por pub get
    • pubspec.yaml # Raíz

Si algún directorio entre la raíz del espacio de trabajo y un paquete del espacio de trabajo contiene un archivo pubspec.yaml "extraviado" que no es miembro del espacio de trabajo, pub get reportará un error y no resolverá las dependencias. Esto se debe a que resolver dicho archivo pubspec.yaml crearía un archivo .dart_tool/package_config.json que eclipsa al que está en la raíz.

Por ejemplo:

  • /
    • packages/
      • foo/
        • pubspec.yaml # Miembro del espacio de trabajo
      • pubspec.yaml # No es miembro del espacio de trabajo => error
    • pubspec.yaml # Raíz workspace: ['packages/foo']

Interdependencias entre paquetes del espacio de trabajo

#

Si alguno de los paquetes del espacio de trabajo depende de otro, se resolverán automáticamente al que está en el espacio de trabajo, independientemente del origen.

Por ej., packages/client_package/pubspec.yaml podría depender de shared:

yaml
dependencies:
  shared: ^2.3.0

Al resolverse dentro del espacio de trabajo, se utilizará la versión local de shared.

Sin embargo, la versión local de shared aún tendría que coincidir con la restricción (^2.3.0).

But when the package is consumed as a dependency without being part of the workspace, the original source (here implicitly hosted) is used.

Entonces, si client_package se publica en pub.dev y alguien depende de él, obtendrán la versión alojada de shared como una dependencia transitiva.

Anulaciones de dependencias (dependency overrides) en un espacio de trabajo

#

Se respetan todas las secciones dependency_overrides en los paquetes del espacio de trabajo. También puedes colocar un archivo pubspec_overrides.yaml junto a cualquiera de los archivos pubspec.yaml del espacio de trabajo.

Solo puedes anular un paquete una vez en el espacio de trabajo. Para mantener organizadas las anulaciones, es preferible conservar dependency_overrides en el pubspec.yaml raíz.

Ejecutar un comando en un paquete del espacio de trabajo específico

#

Algunos comandos de pub, como dart pub add y dart pub publish operan sobre un paquete "actual". Puedes cambiar el directorio o bien usar -C para apuntar pub a un directorio:

dart pub -C packages/client_package publish
# Same as
cd packages/client_package ; dart pub publish ; cd -

Resolver temporalmente un paquete fuera de su espacio de trabajo:

#

A veces es posible que desees resolver un paquete del espacio de trabajo por sí solo, por ejemplo para validar sus restricciones de dependencia.

Una forma de hacer esto es crear un archivo pubspec_overrides.yaml que restablezca la configuración de resolution, así:

yaml
# packages/client_package/pubspec_overrides.yaml
resolution:

Ahora, al ejecutar dart pub get dentro de packages/client_package se creará una resolución independiente.

Listar todos los paquetes del espacio de trabajo

#

Puedes ejecutar dart pub workspace list para listar los paquetes de un espacio de trabajo.

dart pub workspace list
Package         Path
_               ./
client_package  packages/client_package/
server_package  packages/server_package/
shared          packages/shared/