Skip to main content

Sobre esta página

En Fundamentos del desarrollo de paquetes presentamos que basta con escribir la sección extra.laravel en composer.json para que los service providers y las fachadas se registren automáticamente. En esta página se explica qué ocurre por debajo: cómo funciona la clase Illuminate\Foundation\PackageManifest a nivel de código fuente.
Esta página es la hermana de Fundamentos del desarrollo de paquetes. Se recomienda leer primero el uso básico de la detección automática.

Visión general del mecanismo de detección automática

La clase PackageManifest

El núcleo de la detección automática es Illuminate\Foundation\PackageManifest. A continuación se muestra un resumen de la implementación en la versión 13.x del framework.
Los puntos clave son tres:
  • El manifiesto se guarda en memoria una vez cargado (propiedad $this->manifest). Aunque llames varias veces a providers() en una misma petición, la E/S de archivo se produce una sola vez.
  • build() solo se ejecuta si el archivo de manifiesto no existe. En operación normal no se reconstruye en cada arranque.
  • El archivo real es un archivo PHP que hace return de un array plano (bootstrap/cache/packages.php), el formato más rápido de cargar simplemente con require.

Proceso de construcción del manifiesto

El método build() es la parte que realmente agrega la información de los composer.json.
Un aspecto importante es que en lugar de parsear directamente los composer.json, se lee vendor/composer/installed.json. Es un archivo de metadatos de todos los paquetes instalados que Composer genera al ejecutar composer install / composer update. Como la sección extra del composer.json de cada paquete queda concentrada aquí, Laravel confía y lee únicamente la información gestionada por Composer.
installed.json suele estar en .gitignore, por lo que en la configuración inicial (cuando no existe vendor/) la detección automática no funciona. La caché se construye por primera vez tras finalizar composer install.

Dos formas de escribir dont-discover

dont-discover puede declararse tanto en el composer.json del paquete como en el de la aplicación, pero su significado es distinto.
composer.json del paquete
composer.json de la aplicación
Al observar la implementación de build(), el array $ignore se acumula mediante array_merge con el configuration['dont-discover'] de cada paquete. Es decir, técnicamente un paquete puede «desactivar la detección automática de sus propios paquetes dependientes» (por ejemplo, cuando no quieres registrar por duplicado los providers de un subpaquete que utilizas internamente). No obstante, en la práctica lo habitual es desactivarlo desde la aplicación.

Especificar * en dont-discover

Si el array que devuelve packagesToIgnore() contiene *, entonces $ignoreAll = true y se desactiva por completo la detección automática de todos los paquetes. Se utiliza cuando quieres evitar la sobrecarga de la detección automática en CI o entornos de test, o cuando quieres gestionar todo manualmente en bootstrap/providers.php.

El archivo de caché en sí

getCachedPackagesPath() devuelve la variable de entorno APP_PACKAGES_CACHE si está definida y, en caso contrario, bootstrap/cache/packages.php.
Si abres este archivo directamente, verás que simplemente hace return de un array asociativo sencillo.
Como la clave es el nombre del paquete, puedes comprobar en la salida de php artisan package:discover qué paquetes se han detectado.

Cuándo se reconstruye la caché

Illuminate\Foundation\ComposerScripts engancha tres eventos de Composer y todos llaman al mismo clearCompiled().
Es decir, tanto si ejecutas composer install, composer update o composer dump-autoload, la caché de configuración, la de servicios y la de paquetes se eliminan de golpe. La próxima vez que arranque Laravel se ejecutará PackageManifest::build() y se reconstruirá a partir del estado más reciente de installed.json. Este es el comportamiento estándar de un proyecto Laravel, registrado en la sección scripts de composer.json.
composer.json de una app Laravel (extracto)

Reconstrucción manual con php artisan package:discover

Si la caché sigue desactualizada o si modificas vendor/ directamente sin pasar por Composer, puedes reconstruirla manualmente con el comando package:discover.
El comando es en realidad un envoltorio muy ligero.
Solo llama a $manifest->build() e imprime el resultado; apenas tiene lógica específica de comando. En situaciones donde no se disparan los eventos de Composer, como cuando usas composer install --no-scripts en un pipeline de CI, necesitas invocar este comando explícitamente.
Si utilizas Orchestra Testbench para las pruebas del paquete, Testbench ofrece su propio comando vendor/bin/testbench package:discover. Consulta Pruebas de paquetes con Testbench para más detalles. Es distinto del package:discover de Artisan y construye el manifiesto para la aplicación esqueleto exclusiva de Testbench.

Precauciones al desplegar

En producción es habitual ejecutar composer install --no-dev --optimize-autoloader, pero si añades --no-scripts la caché de paquetes no se actualiza. Es más seguro incluir un paso explícito de reconstrucción en el script de despliegue.
El orden también importa. Ejecuta package:discover antes que config:cache. Si la caché de configuración se genera primero, es posible que la configuración de paquetes añadida posteriormente (por ejemplo, la registrada con mergeConfigFrom) no se refleje.

Resumen

  • La detección automática no funciona sobre el contenido estático de composer.json, sino leyendo el vendor/composer/installed.json que genera Composer.
  • El resultado se guarda en bootstrap/cache/packages.php como un array PHP plano y se carga de forma muy rápida simplemente con require.
  • La caché se elimina automáticamente en los eventos de composer install/update/dump-autoload y se reconstruye en el siguiente arranque.
  • En entornos donde ejecutas Composer con --no-scripts, es necesario invocar explícitamente php artisan package:discover.
  • Si añades * a dont-discover, puedes desactivar por completo la detección automática.

Páginas relacionadas

Última modificación el 2 de agosto de 2026