En producción · 2026
Un sistema de interfaz compartido entre todas mis aplicaciones
Paquete privado con los primitivos y los tokens que consumen el portfolio, Rebote y los CRM que vengan, para que no diverjan.
- Rol
- Diseño y desarrollo
- Primitivos
- 29
- Tokens de diseño
- 108
- Aplicaciones que lo consumen
- 2
Problema
Los componentes de interfaz vivían dentro del portfolio. Con una segunda aplicación en camino, la única forma de reutilizarlos era copiarlos — y dos copias del mismo botón dejan de ser el mismo botón en cuanto alguien arregla algo en una sola.
No es un problema estético. Es que cada arreglo hay que hacerlo N veces y acordarse de las N.
Decisión
Un paquete privado, publicado y versionado, en lugar de meter todas las aplicaciones en un mismo repositorio. La alternativa del monorepo evita publicar y permite cambios atómicos, pero obliga a que cada proyecto viva en el mismo repositorio, y no todos pueden.
La regla que decide qué entra: si un componente necesita una prop específica de una aplicación para funcionar, todavía no está listo para compartirse. Se queda donde está hasta que un segundo proyecto lo pida igual. Sin esa regla, la librería acaba llena de componentes con quince propiedades para cubrir tres casos.
Implementación
Veintinueve primitivos y ciento ocho tokens de diseño. Los tokens son la parte que más iguala dos productos: los componentes se pueden cambiar, pero si el color, el radio y la tipografía coinciden, dos aplicaciones distintas siguen pareciendo de la misma casa.
Se publica como código fuente TypeScript, sin compilar, y el consumidor lo transpila. Así no hay dos pasos de compilación que mantener sincronizados ni un artefacto que pueda quedarse viejo respecto al código.
La directiva de componente cliente se pone solo donde hace falta: diez de los veintinueve siguen siendo de servidor. Marcarlos todos como cliente habría sido más rápido y habría metido JavaScript en cada página que los usa.
El token de lectura del registro entra en los contenedores como secreto de construcción, no como argumento: un argumento queda grabado en las capas de la imagen y lo lee cualquiera que la descargue.
Resultado
La segunda aplicación es Rebote, que ya estaba en producción con sus estilos escritos a mano. Migrarla fue reescribir un solo fichero: una capa de adaptación de la que ya importaban 26 de sus 28 pantallas. Ninguna de esas pantallas se tocó.
Ese fichero se mantiene en vez de sustituir cada llamada por el componente de la librería, por dos motivos concretos. Uno, la clase de campo se aplica sobre 128 controles, y buena parte son select y textarea, que no pueden ser un campo de texto. Y dos, el avatar de jugador, la tarjeta de estadística y la cabecera de página hablan de jugadores y de partidos: un componente que necesita saber qué es un jugador no pertenece a una librería compartida. Lo genérico sube, lo que conoce el dominio se queda.
La migración también dejó un fallo de diseño a la vista. El barril exportaba los veintinueve primitivos, incluidos los que dependen de animaciones, formularios o notificaciones; importar un botón obligaba a instalar seis paquetes que no se usan. Ahora el barril solo lleva lo que no arrastra dependencias opcionales y el resto se importa por su ruta. Un barril que obliga a instalar dependencias de lo que no usas traslada un problema de la librería a todos sus consumidores.