feat(critical-css): implementar TIPO 4 y TIPO 5 - CSS Below-the-fold y Lazy Loading
## TIPO 4: CSS Below-the-fold (Critical Variables + Responsive) - Inyecta variables CSS críticas inline en wp_head P:-1 - Inyecta media queries críticas inline en wp_head P:2 (corregido de P:1) - Auto-regeneración cuando archivos fuente cambian (filemtime check) - Cache en Assets/CriticalCSS/ para evitar lecturas repetidas - Comando WP-CLI: wp roi-theme generate-critical-css Archivos TIPO 4: - Public/CriticalCSS/Domain/Contracts/ - Interfaces (DIP) - Public/CriticalCSS/Application/UseCases/GetCriticalCSSUseCase.php - Public/CriticalCSS/Infrastructure/Cache/CriticalCSSFileCache.php - Public/CriticalCSS/Infrastructure/Services/CriticalCSSExtractor.php - Public/CriticalCSS/Infrastructure/Services/CriticalCSSInjector.php - bin/generate-critical-css.php ## TIPO 5: CSS No Crítico (Lazy Loading) - Animaciones CSS: carga 2s después de page load via requestIdleCallback - Print CSS: carga solo al imprimir via beforeprint event - Fallback <noscript> para usuarios sin JavaScript - Safari fallback: setTimeout cuando requestIdleCallback no disponible Archivos TIPO 5: - Assets/Js/lazy-css-loader.js - Public/LazyCSSLoader/Infrastructure/Contracts/LazyCSSRegistrarInterface.php - Public/LazyCSSLoader/Infrastructure/Services/LazyCSSRegistrar.php ## Fix: Colisión de prioridades wp_head Antes: TIPO 1 (P:1), TIPO 4 responsive (P:1), TIPO 3 (P:2) - CONFLICTO Después: TIPO 1 (P:1), TIPO 4 responsive (P:2), TIPO 3 (P:3) - OK Nuevo orden de prioridades: P:-1 roi-critical-variables (TIPO 4) P:0 roi-critical-bootstrap (TIPO 2) P:1 roi-critical-css (TIPO 1) P:2 roi-critical-responsive (TIPO 4) P:3 roi-custom-critical-css (TIPO 3) P:5 roi-theme-layout-css (ThemeSettings) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
117
Public/CriticalCSS/Infrastructure/Cache/CriticalCSSFileCache.php
Normal file
117
Public/CriticalCSS/Infrastructure/Cache/CriticalCSSFileCache.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ROITheme\Public\CriticalCSS\Infrastructure\Cache;
|
||||
|
||||
use ROITheme\Public\CriticalCSS\Domain\Contracts\CriticalCSSCacheInterface;
|
||||
|
||||
/**
|
||||
* Cache de CSS critico en filesystem con auto-invalidacion
|
||||
*
|
||||
* Almacena CSS critico generado en archivos .critical.css
|
||||
* dentro de Assets/CriticalCSS/
|
||||
*
|
||||
* @package ROITheme\Public\CriticalCSS\Infrastructure\Cache
|
||||
*/
|
||||
final class CriticalCSSFileCache implements CriticalCSSCacheInterface
|
||||
{
|
||||
private readonly string $cacheDir;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cacheDir = get_template_directory() . '/Assets/CriticalCSS';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(string $key): ?string
|
||||
{
|
||||
$file = $this->getFilePath($key);
|
||||
|
||||
if (!file_exists($file)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
|
||||
return $content !== false ? $content : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function set(string $key, string $css): bool
|
||||
{
|
||||
$this->ensureDirectoryExists();
|
||||
$file = $this->getFilePath($key);
|
||||
|
||||
return file_put_contents($file, $css) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return file_exists($this->getFilePath($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$files = glob($this->cacheDir . '/*.critical.css');
|
||||
|
||||
if ($files === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Compara timestamps para detectar cache desactualizado.
|
||||
* Costo: ~0.1ms (2 llamadas a filemtime)
|
||||
*/
|
||||
public function isStale(string $key, string $sourceFile): bool
|
||||
{
|
||||
$cacheFile = $this->getFilePath($key);
|
||||
|
||||
// Si no existe cache, esta desactualizado
|
||||
if (!file_exists($cacheFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Si no existe fuente, no esta desactualizado (nada que regenerar)
|
||||
if (!file_exists($sourceFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comparar timestamps
|
||||
return filemtime($sourceFile) > filemtime($cacheFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera ruta del archivo cache
|
||||
*/
|
||||
private function getFilePath(string $key): string
|
||||
{
|
||||
return $this->cacheDir . '/' . $key . '.critical.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Asegura que el directorio de cache existe
|
||||
*/
|
||||
private function ensureDirectoryExists(): void
|
||||
{
|
||||
if (!is_dir($this->cacheDir)) {
|
||||
mkdir($this->cacheDir, 0755, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user