Resumen

Optimiza un monorepo con Nx usando tags y constraints para asegurar una arquitectura limpia, sin dependencias circulares y con control desde el linter. Aquí verás cómo etiquetar proyectos en project.json, definir reglas en nx.json y replicarlas en la configuración de ESLint para que todo se verifique automáticamente.

¿Cómo usar tags en Nx para clasificar proyectos?

Asignar tags por scope a cada proyecto permite identificar su función y controlar dependencias. Se edita cada project.json dentro de packages y se agrega el arreglo de etiquetas.

  • App1: scope app.
  • App2: scope app.
  • Server: scope API.
  • UI shared: scope UI.
  • Utils common: scope utils.

Ejemplo mínimo en un project.json de una app:

{
  "name": "app1",
  "tags": ["scope app"]
}

Ejemplo para UI shared:

{
  "name": "ui-shared",
  "tags": ["scope UI"]
}

Y para utils common:

{
  "name": "utils-common",
  "tags": ["scope utils"]
}

¿Qué reglas de dependencia definen las constraints en nx.json?

En nx.json se agregan las constraints para limitar qué puede depender de qué. Así se evitan dependencias circulares y cada capa mantiene su responsabilidad. El control lo aplica el linter cuando analiza los proyectos.

  • Utils: solo depende de utils.
  • UI: puede depender de utils y UI.
  • API: solo depende de utils.
  • App: puede depender de utils, UI y API.

Fragmento conceptual de nx.json:

{
  "projects": {
    "app1": { "tags": ["scope app"] },
    "app2": { "tags": ["scope app"] },
    "server": { "tags": ["scope API"] },
    "ui-shared": { "tags": ["scope UI"] },
    "utils-common": { "tags": ["scope utils"] }
  },
  "constraints": [
    { "source": "scope utils", "onlyDependOn": ["scope utils"] },
    { "source": "scope UI", "onlyDependOn": ["scope utils", "scope UI"] },
    { "source": "scope API", "onlyDependOn": ["scope utils"] },
    { "source": "scope app", "onlyDependOn": ["scope utils", "scope UI", "scope API"] }
  ]
}

Con esto, por ejemplo, utils no puede depender de UI, y UI no puede depender de API. Al romper una regla, el linter lo marcará.

¿Cómo replicar las constraints en ESLint y validar con el linter?

Las mismas restricciones se copian en la configuración de ESLint para que el análisis estático refleje las reglas de nx.json. Al ejecutar el linter, se verifican las capas y no pasa nada que viole las dependencias establecidas. En la validación mencionada, los tres proyectos analizados pasaron correctamente.

Fragmento conceptual de configuración para ESLint:

{
  "rules": {
    "constraints": [
      { "sourceTag": "scope utils", "onlyDependOn": ["scope utils"] },
      { "sourceTag": "scope UI", "onlyDependOn": ["scope utils", "scope UI"] },
      { "sourceTag": "scope API", "onlyDependOn": ["scope utils"] },
      { "sourceTag": "scope app", "onlyDependOn": ["scope utils", "scope UI", "scope API"] }
    ]
  }
}

Claves prácticas: - Etiqueta cada proyecto con un scope claro en su project.json. - Define constraints por capa en nx.json para bloquear ciclos. - Replica las restricciones en ESLint para validación automática. - Ejecuta el linter con frecuencia: detecta violaciones de inmediato.

¿Te gustaría comentar cómo organizas tus tags y constraints en monorepos con Nx o qué casos límite has encontrado?