Monorepositorio con TypeScript: organización de código en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Monorepositorio con TypeScript: organización de código en la práctica

\n\n

En el desarrollo web moderno, especialmente al trabajar con TypeScript, los desarrolladores a menudo se enfrentan a un dilema: almacenar todo el código en un solo repositorio (monorepositorio) o dividirlo en muchos repositorios pequeños (polirepositorio). Para proyectos medianos y grandes, donde la reutilización del código y una configuración unificada son importantes, el monorepositorio se convierte en el estándar de facto. En este artículo, analizaremos cómo organizar correctamente un monorepositorio en TypeScript, desde la estructura básica hasta técnicas avanzadas.

\n\n

¿Qué es un monorepositorio y para qué sirve?

\n\n

Un monorepositorio es un enfoque en el que el código de varios proyectos (paquetes, bibliotecas, aplicaciones) se almacena en un solo repositorio. En el contexto de TypeScript, esto es especialmente conveniente, ya que permite:

\n\n
    \n
  • Reutilizar tipos e interfaces entre diferentes partes del sistema sin publicar en npm.
  • \n
  • Simplificar la refactorización: un cambio en un paquete se valida automáticamente en todos los dependientes.
  • \n
  • Tener una configuración unificada para linter, formateador y compilador.
  • \n
  • Simplificar CI/CD: un repositorio, un pipeline.
  • \n
\n\n

Entre las herramientas populares para trabajar con monorepositorios en TypeScript se destacan Nx, Turborepo y npm/yarn/pnpm workspaces. Consideraremos un enfoque que utiliza pnpm workspaces y TypeScript Project References, ya que es un conjunto mínimo y flexible.

\n\n

Estructura del monorepositorio: configuración básica

\n\n

Vamos a crear una estructura típica de monorepositorio para un proyecto TypeScript. Supongamos que tenemos tres paquetes: core (tipos y utilidades comunes), server (backend) y web (frontend).

\n\n

1. Configuración raíz

\n\n

Empecemos por la raíz del proyecto. Creemos un archivo package.json con workspace:

\n\n
{\n  "name": "my-monorepo",\n  "private": true,\n  "workspaces": [\n    "packages/*"\n  ],\n  "scripts": {\n    "build": "tsc -b",\n    "clean": "tsc -b --clean",\n    "lint": "eslint packages/*/src"\n  }\n}\n
\n\n

Luego, configuremos el tsconfig.json raíz. Usaremos Project References, que es una característica clave de TypeScript para monorepositorios:

\n\n
{\n  "compilerOptions": {\n    "target": "ES2020",\n    "module": "commonjs",\n    "strict": true,\n    "composite": true,\n    "declaration": true,\n    "declarationMap": true,\n    "sourceMap": true,\n    "outDir": "./dist",\n    "rootDir": ".",\n    "skipLibCheck": true\n  },\n  "references": [\n    { "path": "./packages/core" },\n    { "path": "./packages/server" },\n    { "path": "./packages/web" }\n  ]\n}\n
\n\n

Importante: la opción composite: true es obligatoria para los paquetes a los que otros paquetes hacen referencia. Habilita la compilación incremental y la generación de archivos .d.ts.

\n\n

2. Configuración del paquete core

\n\n

Vayamos a packages/core. Creemos package.json:

\n\n
{\n  "name": "@my/core",\n  "version": "1.0.0",\n  "main": "dist/index.js",\n  "types": "dist/index.d.ts",\n  "scripts": {\n    "build": "tsc -b"\n  }\n}\n
\n\n

Y el tsconfig.json para este paquete:

\n\n
{\n  "extends": "../../tsconfig.json",\n  "compilerOptions": {\n    "outDir": "./dist",\n    "rootDir": "./src"\n  },\n  "include": ["src"]\n}\n
\n\n

Creemos un módulo simple src/index.ts:

\n\n
export interface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\nexport function greet(user: User): string {\n  return `Hello, ${user.name}!`;\n}\n
\n\n

Ahora el paquete

Blogs

Book Recommendations