El build que no usaba CPU
El síntoma
Un pnpm build que no avanza.
No da error. No escupe una traza. No se cae. Simplemente se queda quieto, y lo desconcertante es que el ventilador tampoco suena. El Monitor de Actividad confirma lo que ya sospechas: el proceso no está usando procesador.
Un build lento consume CPU. Uno parado sin consumirla no está trabajando: está esperando algo.
La pista que lo convierte en un rompecabezas de verdad llega al intentar empezar de cero:
rm -rf .next
Tampoco termina.
Borrar una carpeta es de las operaciones más simples que hace un sistema de archivos. Si eso se cuelga, el problema no está en tu código, ni en tu gestor de paquetes, ni en el compilador.
Qué estaba pasando
El repositorio vivía en ~/Documents/. En macOS, esa carpeta y el Escritorio
los sincroniza iCloud Drive cuando está activada la opción «Carpetas
Escritorio y Documentos».
Y .next son miles de archivos de compilación que se reescriben enteros en
cada build.
Mientras iCloud mantiene un archivo abierto para subirlo, el sistema no permite sobrescribirlo ni borrarlo. La operación no falla: espera. Por eso no hay mensaje de error y por eso no hay consumo de procesador. Hay dos programas trabajando sobre los mismos miles de archivos: uno intenta reescribirlos y el otro intenta subirlos a la nube.
Cuando medimos qué se estaba sincronizando, el reparto era este:
| Carpeta | Tamaño | ¿Se regenera sola? |
|---|---|---|
.next | 503 MB | Sí |
node_modules | 465 MB | Sí |
.git | 11 MB | No |
| El trabajo real (código, contenido, documentación) | ~9 MB | No |
| Total | 987 MB |
.next se regenera en cada build y node_modules con un install. .git
no: es el historial del proyecto.
De casi un gigabyte sincronizándose, el trabajo real eran nueve megabytes. El 99 % restante eran archivos que la máquina reconstruye sola en un par de minutos.
Nada de esto afecta al sitio publicado. Es un problema de la máquina en la que se desarrolla, no de lo que recibe el visitante.
El riesgo que todavía no habíamos tenido
Hasta aquí, todo lo que has leído nos pasó. Lo de esta sección, no. No es una experiencia nuestra: es un comportamiento documentado de macOS, y lo contamos porque, si te ocurre, es peor que lo anterior y más difícil de diagnosticar.
iCloud tiene una opción llamada «Optimizar el almacenamiento del Mac». Cuando el disco se queda corto, el sistema retira la copia local de los archivos que considera poco usados y deja solo la de la nube. El archivo sigue apareciendo en el Finder; simplemente ya no está en el disco.
Si eso le ocurriera a un archivo de node_modules, el build fallaría diciendo
que un módulo no existe. Existe, y además lo verías en pantalla, pero no
estaría en la máquina. Es un error difícil de rastrear precisamente porque
todo lo que miras parece correcto.
Para que quede claro: a nosotros el proyecto se nos bloqueó, pero nunca nos faltó un archivo. Ese es el riesgo que evitamos al mover el proyecto, no uno que hayamos sufrido.
Cómo reconocerlo
Tres señales que juntas no dejan lugar a dudas:
du -sh .next # cientos de MB
pwd | grep -q Documents && echo "⚠️ dentro de iCloud"
brctl log --last 2m -q # actividad reciente de iCloud
brctl es la herramienta de línea de comandos de iCloud, y casi nadie la
conoce. macOS oculta parte de los nombres de archivo en ese registro, pero si
el build está parado y ahí ves actividad continua de iCloud, ya tienes el
diagnóstico.
La solución
Borrar .next y volver a compilar no sirve: se regenera y vuelve a
bloquearse. Hay que sacar el proyecto de las carpetas que sincroniza
iCloud.
mkdir -p ~/Developer
mv ~/Documents/mi-proyecto ~/Developer/
cd ~/Developer/mi-proyecto
rm -rf .next # ahora sí termina
pnpm build
Elegimos ~/Developer porque macOS la reconoce como carpeta de desarrollo y
le pone su propio icono, pero sirve cualquier ruta fuera de Documents y
Desktop.
Mover la carpeta no rompe nada: Git guarda sus rutas de forma interna y el
historial viaja dentro de .git, así que el repositorio sigue funcionando
exactamente igual en su nueva ubicación.
El primer build después de mover compiló en 2,5 segundos.
Si después de mover
node_modulesda errores raros, puede que iCloud hubiera retirado ya la copia local de algún archivo, el riesgo de la sección anterior. Uninstalllo reconstruye.
La regla que queda
La pregunta no es «¿dónde guardo mis proyectos?». Es otra, y vale para cualquier servicio de sincronización:
Lo que se regenera solo no se respalda.
node_modules, .next, .turbo, dist, build y __pycache__ no son tus
datos. Son el resultado de aplicar un comando a tus datos. Si desaparecieran
ahora mismo, un install y un build los traerían de vuelta.
Tus datos son el código, el contenido y el historial de Git, y ese historial ya está respaldado en el servidor remoto, que es mejor copia de seguridad que cualquier carpeta sincronizada.
Dicho de otro modo: es el mismo criterio que ya aplicas en el
.gitignore. Lo que no merece entrar en el repositorio tampoco merece entrar
en la nube. La lista es casi la misma, y por la misma razón.
El principio más general
Más allá de iCloud, este caso enseña a leer una categoría entera de problemas.
Un proceso parado que no consume procesador no está trabajando: está esperando. Y lo que espera casi nunca es la CPU: es un archivo, un puerto, un bloqueo o la red.
Cuando algo se cuelga, la primera pregunta no es «¿qué estoy haciendo mal?». Es «¿quién más está tocando esto?». La respuesta suele estar fuera del programa que estás mirando.