> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Assets públicos de paquetes y su actualización

> Analiza el proceso de publicación de Laravel 13 y explica, desde la perspectiva del mantenimiento a largo plazo, la distribución de JavaScript y CSS, el alcance de la selección por etiquetas, las opciones de sobrescritura y la republicación al actualizar con Composer.

Aunque actualices el JavaScript o el CSS de tu paquete, los archivos ya copiados en el directorio `public` de la aplicación no cambian automáticamente. Para evitar que solo el código PHP pase a la nueva versión mientras el navegador sigue usando los assets antiguos, es necesario definir quién es el propietario del destino de publicación y cuál es el procedimiento de actualización.

Esta página parte de los [fundamentos del desarrollo de paquetes](/es/advanced/package-development) y organiza el diseño de la distribución y el mantenimiento a partir del proceso de publicación de Laravel 13. Para verificar la implementación se usa `laravel/framework` `v13.35.0`.

## Publicar no es compilar ni sincronizar

`ServiceProvider::publishes()` registra el origen y el destino de la copia. Quien copia realmente los archivos es `vendor:publish`. No transpila JavaScript, no compila CSS ni añade nada a las entradas de Vite de la aplicación.

Si el paquete distribuye archivos ya compilados, puedes usar, por ejemplo, la siguiente estructura.

```text theme={null}
courier/
├── public/
│   ├── courier.css
│   └── courier.js
└── src/
    └── CourierServiceProvider.php
```

```php theme={null}
<?php

namespace Acme\Courier;

use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../public' => public_path('vendor/courier'),
            ], 'courier-assets');
        }
    }
}
```

En la primera publicación, indica explícitamente el provider y la etiqueta.

```bash theme={null}
php artisan vendor:publish --provider="Acme\Courier\CourierServiceProvider" --tag=courier-assets
```

En este ejemplo se crean `public/vendor/courier/courier.css` y `courier.js`. Si el diseño consiste en distribuirlos como CSS y JavaScript normales, puedes referenciarlos desde Blade de la siguiente manera.

```blade theme={null}
<link rel="stylesheet" href="{{ asset('vendor/courier/courier.css') }}">
<script src="{{ asset('vendor/courier/courier.js') }}" defer></script>
```

Si los distribuyes como ES modules, por ejemplo, adapta la forma de cargarlos al formato de distribución. `asset()` es un helper que genera URLs; no compila, no publica ni genera nombres de archivo basados en el contenido.

<Warning>
  En el origen de la copia coloca únicamente artefactos compilados que se puedan publicar. En este ejemplo, el destino es `public`, accesible desde la web. No incluyas archivos de configuración ni datos internos en el mismo grupo de publicación.
</Warning>

## Las etiquetas no son un espacio de nombres exclusivo del provider

`ServiceProvider` registra las rutas de publicación en un array por clase de provider y en otro por etiqueta. Como el array por etiqueta se comparte entre varios providers, usar una etiqueta genérica como `public` puede incluir también a otros paquetes.

| Indicación | Rutas de publicación seleccionadas |
| - | - |
| `--tag=courier-assets` | Las rutas de todos los providers que registraron esa etiqueta |
| `--provider="Acme\Courier\CourierServiceProvider"` | Todas las rutas registradas por ese provider |
| Provider y etiqueta a la vez | La intersección entre las rutas de ese provider y las de esa etiqueta |
| `--all` | Las rutas de publicación de todos los providers |

Cuando se indican ambos, `pathsForProviderAndGroup()` usa `array_intersect_key()` **con la ruta de origen como clave**. No es un mecanismo para cambiar a otro destino según la etiqueta. Evita diseños que registren el mismo origen varias veces para tener destinos distintos según el uso.

`--tag` se puede indicar varias veces. En ese caso, cada etiqueta se publica por orden. `--all` retorna al principio del proceso de selección, por lo que, aunque añadas `--provider` o `--tag` al mismo tiempo, no se usan para filtrar.

<Tip>
  Para no sobrescribir también la configuración y las vistas del usuario, usa en el procedimiento de actualización una etiqueta de assets propia del paquete. Si indicas solo el provider y añades `--force`, la configuración y las vistas del mismo provider también pueden verse afectadas.
</Tip>

## Elegir la opción de republicación adecuada

La publicación de archivos y de directorios de `VendorPublishCommand` decide si copia en función de la existencia del archivo de destino y de las opciones. La siguiente tabla muestra el comportamiento para archivos de assets normales que existen en el origen.

| Opción | Archivo que no existe en el destino | Archivo que existe en el destino |
| - | - | - |
| Ninguna | Se añade | Se conserva |
| `--force` | Se añade | Se sobrescribe |
| `--existing` | No se añade | Se sobrescribe |
| `--existing --force` | No se añade | Se sobrescribe |

`--existing` no es una opción para proteger las modificaciones. Sobrescribe los archivos existentes, pero no publica los archivos añadidos en la nueva versión. En una actualización en la que el JavaScript necesite un archivo nuevo, `--existing` por sí solo puede dejar los artefactos incompletos.

Si el contrato establece que el paquete gestiona el destino de publicación y que el usuario no lo edita directamente, ejecuta lo siguiente después de actualizar.

```bash theme={null}
php artisan vendor:publish --provider="Acme\Courier\CourierServiceProvider" --tag=courier-assets --force
```

<Warning>
  `--force` no fusiona diferencias y sobrescribe también las modificaciones del usuario. Separa el CSS que el usuario personaliza de los artefactos gestionados por el paquete, por ejemplo cargándolo como un archivo independiente. Define una política de actualización distinta de la de la personalización de la configuración y las vistas.
</Warning>

### Los archivos eliminados permanecen en el destino

`moveManagedFiles()`, en la publicación de directorios, recorre los archivos del origen y los escribe. No existe ningún proceso que busque y elimine archivos que solo existan en el destino. `--force` tampoco realiza una sincronización completa del directorio.

Por ejemplo, aunque elimines `legacy.js` en la nueva versión, si la versión anterior ya estaba publicada, `public/vendor/courier/legacy.js` permanece. Al renombrar un archivo también se conserva el archivo con el nombre antiguo, así que registra en las notas de la versión los archivos eliminados o renombrados y los cambios en las referencias.

Si ofreces un procedimiento para eliminar los archivos antiguos, indica concretamente los archivos que pertenecen al paquete. No propongas un procedimiento que elimine por completo un directorio en el que el usuario pueda haber colocado archivos propios.

## Participar en laravel-assets implica un contrato de sobrescritura

La plantilla oficial de aplicación de Laravel 13 incluye el siguiente script en `post-update-cmd` de `composer.json`.

```json theme={null}
{
    "scripts": {
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ]
    }
}
```

Se trata de un script de la aplicación. No es la detección automática de paquetes la que actualiza los archivos publicados. En aplicaciones existentes, el script puede haberse modificado o eliminado, así que comprueba la configuración del lado del usuario.

Para participar en esta vía de actualización, cambia el segundo argumento del `publishes()` anterior a un array y registra los mismos assets en dos etiquetas.

```php theme={null}
$this->publishes([
    __DIR__.'/../public' => public_path('vendor/courier'),
], ['courier-assets', 'laravel-assets']);
```

`laravel-assets` no es una etiqueta con un proceso de copia especial. Como el script de la plantilla publica esa etiqueta con `--force`, los archivos que participan se sobrescriben al actualizar con Composer. No registres la configuración ni las vistas que el usuario edita.

<Info>
  La actualización automática presupone que la aplicación tenga el script, que se ejecute ese evento y que el provider registre las rutas de publicación. Para que la actualización sea posible también en despliegues que no cumplen estas condiciones, documenta el comando de republicación con la etiqueta propia del paquete.
</Info>

## Alinear las versiones de PHP y de los assets en el despliegue

```mermaid theme={null}
flowchart TD
    A["Actualizar el paquete"] --> B["Registrar las rutas de publicación"]
    B --> C["vendor:publish --force con la etiqueta propia<br>o el script de actualización de laravel-assets"]
    C --> D["Añadir los archivos nuevos<br>Sobrescribir los archivos existentes"]
    D --> E["Limpiar los archivos antiguos indicados<br>Aplicar la política de caché del navegador y la CDN"]
    E --> F["Comprobar que PHP y los assets funcionan con la misma versión"]
```

`config:cache` y `view:cache` no reescriben el JavaScript ni el CSS publicados. Si el diseño sirve los archivos con la misma URL después de publicarlos, la caché del navegador o de la CDN puede hacer que se use el contenido antiguo. Incluye también en el procedimiento de actualización la política de entrega de la aplicación, como URLs que reflejen la versión de los artefactos o la invalidación de la caché.

En cada versión, comprueba las siguientes combinaciones.

* En una aplicación sin publicar, se publican todos los archivos compilados necesarios.
* Con la versión anterior ya publicada, `--force` actualiza los archivos existentes y añade los nuevos.
* La actualización de los assets no sobrescribe la configuración, las vistas ni el CSS propio del usuario.
* Se indica cómo tratar los archivos eliminados o renombrados y no quedan referencias a la versión anterior.
* El contenido de la nueva versión llega a través de la URL de entrega real, y el procesamiento de PHP y del navegador funciona de forma coordinada.

## Páginas relacionadas

<Columns cols={2}>
  <Card title="Detección automática de paquetes" icon="magnifying-glass" href="/es/advanced/package-discovery">
    Revisa las diferencias entre la actualización de Composer, la detección de providers y la publicación de archivos.
  </Card>

  <Card title="Sobrescritura y actualización de vistas de paquetes" icon="eye" href="/es/advanced/package-views">
    Revisa la política de mantenimiento de las plantillas que personaliza el usuario.
  </Card>

  <Card title="Caché de paquetes e integración con optimize" icon="gears" href="/es/advanced/package-optimization">
    Explica la caché del paquete, que se gestiona por separado de la publicación de archivos.
  </Card>

  <Card title="Gestión de la compatibilidad de versiones" icon="code-branch" href="/es/advanced/package-versioning">
    Trata los cambios en el destino de publicación y el formato de distribución como un contrato de compatibilidad.
  </Card>
</Columns>

## Fuentes primarias consultadas

* [Documentación oficial de Laravel: Public assets](https://github.com/laravel/docs/blob/13.x/packages.md#public-assets)
* [Documentación oficial de Laravel: Publishing file groups](https://github.com/laravel/docs/blob/13.x/packages.md#publishing-file-groups)
* [Laravel Framework v13.35.0: ServiceProvider](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Support/ServiceProvider.php) — `publishes()`, `addPublishGroup()`, `pathsToPublish()`, `pathsForProviderAndGroup()`.
* [Laravel Framework v13.35.0: VendorPublishCommand](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Foundation/Console/VendorPublishCommand.php) — alcance de la selección, condiciones de sobrescritura y proceso de copia dentro de directorios.
* [Plantilla oficial de aplicación de Laravel 13: composer.json](https://github.com/laravel/laravel/blob/13.x/composer.json) — republicación de `laravel-assets` mediante `post-update-cmd`.


## Related topics

- [Desarrollo de paquetes para Laravel](/es/advanced/package-development.md)
- [Temas avanzados](/es/advanced/index.md)
- [Publicación y actualización de migraciones de paquetes](/es/advanced/package-migrations.md)
- [Actualización de Laravel 10 a 11](/es/blog/upgrade-10-to-11.md)
- [Actualización de Laravel 8 a 9](/es/blog/upgrade-8-to-9.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.