Ir al contenido principal
Laravel, shipping fast.
Capitulo 18 · Publicar plantillas en sitios activos

Hornear en la instalacion gana a copiar ficheros a mano

Julian Beaujardin

Dividir en niveles sólo se paga si meter una versión nueva del paquete dentro de una instancia existente es realmente barato. El enfoque ingenuo trata el nivel del paquete como una carpeta de ficheros que comparas y reaplicas a mano.

// Bad: reconciling a new template version by hand, one instance at a time
foreach (Site::pluck('repo_path') as $repoPath) {
    exec("cd {$repoPath} && git apply /patches/theme-v1.1.85.diff");
    exec("cd {$repoPath} && git add -A && git commit -m 'apply theme patch' && git push");
}

Esto funciona con tres clientes. Deja de funcionar con treinta: cada instancia se desvía un poco de las demás, alguien editó un Blade directamente en una máquina durante un incidente, otra instancia va dos versiones atrasada porque su parche entró en conflicto y nadie lo terminó. Seis meses después, «actualizar el tema» significa abrir una docena de repositorios y leer diffs antes de fiarte de ninguno. No estás publicando una versión: estás haciendo arqueología.

El arreglo es hacer que el paquete se instale a sí mismo. Se publica como una librería de Composer cuyo service provider registra comandos de Artisan reales, y el instalador —no una persona con un fichero de parche— decide qué se copia y adónde.

// src/Commands/InstallWebploTheme.php (Webplo\Templates\Commands)
public function handle(): int
{
    $theme = $this->argument('theme') ?? env('SITE_THEME', 'template-1');
    $themePath = __DIR__.'/../../resources/stubs/themes/'.$theme;

    if (! is_dir($themePath)) {
        $this->error("Theme '{$theme}' not found.");

        return self::FAILURE;
    }

    $viewsBase = is_dir($themePath.'/views') ? $themePath.'/views' : $themePath;
    $home = $viewsBase.'/pages/home.blade.php';

    if (! file_exists($home)) {
        $this->error("Theme '{$theme}' is missing pages/home.blade.php — aborting to avoid a broken install.");

        return self::FAILURE;
    }

    // ... copyFile()/copyDir() the theme's views into resource_path(), each
    // one skipping existing files unless --force was passed

    $this->call('webplo:install-editable', ['--force' => $this->option('force')]);

    $this->callSilent('cache:clear');
    $this->callSilent('config:clear');

    return self::SUCCESS;
}

Qué te compra esto:

  • Una guarda de fichero obligatorio antes de copiar nada. El comando comprueba que existe la vista de inicio y se niega a seguir sin ella. Un tema malformado falla en voz alta y pronto, en lugar de dejar un sitio a medio instalar.
  • Una bandera --force que por defecto es segura. Las copias se saltan lo que ya existe salvo que se pase --force, así que reejecutar el instalador en una instancia con ediciones locales sin confirmar no las pisa por accidente.
  • Un segundo comando llamado desde dentro del primero. El instalador del tema no necesita saber cómo están dispuestos los ficheros del sistema editable.
  • La limpieza de cachés horneada, no dejada a que la recuerde quien lo ejecute.

La regla: el paquete debería poseer el acto de instalarse a sí mismo. En cuanto «actualizar un tema» significa «subir una restricción de versión y ejecutar un comando», actualizar treinta instancias son treinta operaciones idénticas, aburridas y programables en lugar de treinta juicios sobre qué parche aplica limpiamente a qué árbol ligeramente distinto.