A auditoria do PR #34 mediu LCP acima da meta de 2,5 s da SPEC §6.6 em todas as páginas no mobile, mas ficou registrada apenas como tabela num comentário do Linear — `storage/app/lighthouse` é gitignored, então não havia artefato para comparar depois. Esta entrega mede de novo, encontra a causa dominante e corta o que dava para cortar. ## Fontes servidas em dobro (88 KiB) Bunny entrega cada peso de EB Garamond em woff2 e woff, e o plugin de fontes emitia uma regra `@font-face` para cada, woff2 primeiro e woff depois. Duas regras com a mesma família, peso, estilo e unicode-range fazem a última vencer: o navegador renderizava a partir dos woff e descartava os woff2 pré-carregados. O log de rede da home prova: 3 woff em prioridade VeryHigh (88 KiB), a mais alta da página e à frente do elemento de LCP, mais 3 woff2 em High (74 KiB) baixados só por causa do `<link rel="preload">`. 162 KiB de tráfego para 74 KiB de fonte útil. woff2 é suportado por todo navegador que este site atende desde 2016, então as regras woff eram peso morto, não fallback. O plugin `amare:fonts-woff2-only` remove as regras do CSS e do manifest e tira os arquivos do bundle. É o que derruba o FCP de 1,51 s para 0,91 s em todas as páginas. ## Ativos de marca reencodados (102 KiB) — absorve MAN-122 O logotipo era servido a 512 px de largura para renderizar em 48 px (lockup, cabeçalho e rodapé de toda página) e 32 px (mark, home), com `loading="eager"`. Reencodados a 3× do maior render: lockup 149×144 (84 → 14 KiB) e mark 191×96 (42 → 10 KiB), mesmos nomes de arquivo para não invalidar cache. As variantes `on-dark` foram reencodadas junto por consistência; nenhuma view as usa hoje. Os 16 baselines visuais foram regenerados no runner Linux e o diff é imperceptível a 2× de zoom — mesma forma, mesma cor, menos bytes. ## Efeito medido Mobile, mediana de 3 execuções por página: home 4,58 → 3,39 s; portfolio 3,98 → 1,58 s; portfolio-detalhe 3,98 → 3,01 s; servicos 3,68 → 2,63 s; sobre 3,01 → 1,58 s; contato 2,55 → 1,51 s. Desktop passa com folga em todas (máximo 0,79 s). Acessibilidade, boas práticas e SEO seguem 100, CLS 0,000 e TBT 0 ms. `contato`, `portfolio` e `sobre` entraram na meta. `servicos`, `portfolio-detalhe` e `home` continuam fora, e o que falta está identificado: o elemento de LCP da home é a imagem do hero em JPEG q82 (143 KiB), e `Improve image delivery` estima 0,90 s de ganho restante. O lever é variante WebP em ResponsiveImage com `<picture>` — fora deste escopo porque mexe no pipeline de mídia que o CMS usa para upload. ## Ferramental - `scripts/perf/lighthouse.sh` ganha `/portfolio/{slug}`, passada desktop, mediana de 3 execuções e uma guarda de HTTP 200 antes de auditar. Uma rota em 404 produz relatório com score alto: a rota mais pesada do site apareceria como ótima e ninguém notaria. - `scripts/perf/summarize-lighthouse.mjs` extrai do JSON o elemento de LCP, a decomposição em fases e as requests até o LCP. - `docker/ci-runner.Dockerfile` e `scripts/test/visual-update-ci.sh` versionam a receita de regeneração de baselines, que existia só como checklist. - `CLAUDE.md` corrigido: Pest Browser serve a aplicação de um servidor Amp in-process, não do FrankenPHP. A paridade que importa nos baselines é Linux vs macOS, não o runtime HTTP. - Sem gate de performance no CI (§14.1 e §22). No lugar, orçamento de bytes para os ativos de marca e asserção de que o build só emite woff2. Staging não foi medido: a origem responde 303 para blocked.teams.cloudflare.com a partir da rede corporativa, inclusive em `/up`. Duas hipóteses seguem não validadas por dependerem de `FILESYSTEM_DISK=r2` — os ~4 round trips a R2 por imagem que `x-media.image` faz sem cache, e a falta de `preconnect` para a origem cross-origin de mídia. Ambas documentadas em docs/evidence/lighthouse/README.md. Co-Authored-By: Claude noreply@anthropic.com AI-Assisted: yes AI-Tool: claude-code
53 lines
1.9 KiB
PHP
53 lines
1.9 KiB
PHP
@props([
|
|
'variant' => 'on-light',
|
|
'mark' => false,
|
|
'alt' => null,
|
|
'class' => '',
|
|
])
|
|
|
|
@php
|
|
$settings = $siteSettings ?? null;
|
|
$uploadedPath = is_object($settings) ? ($settings->logo_path ?? null) : null;
|
|
$uploadedAlt = is_object($settings) ? ($settings->logo_alt ?? null) : null;
|
|
|
|
$resolvedAlt = $alt
|
|
?? (filled($uploadedAlt) ? $uploadedAlt : null)
|
|
?? ((is_object($settings) && filled($settings->brand_name ?? null))
|
|
? $settings->brand_name
|
|
: 'Amare Assessoria');
|
|
|
|
$variant = $variant === 'on-dark' ? 'on-dark' : 'on-light';
|
|
$kind = $mark ? 'mark' : 'lockup';
|
|
$staticSrc = asset("brand/{$kind}-{$variant}.webp");
|
|
|
|
$usesUploadedLogo = filled($uploadedPath);
|
|
|
|
$src = $usesUploadedLogo
|
|
? \Illuminate\Support\Facades\Storage::disk('public')->url($uploadedPath)
|
|
: $staticSrc;
|
|
|
|
// Reserve the box before the image arrives (SPEC §6.4). The intrinsic size
|
|
// of the shipped assets is known and fixed; an uploaded logo has arbitrary
|
|
// dimensions, so it gets no attributes rather than wrong ones. The CSS
|
|
// classes still govern the rendered size in both cases — width/height only
|
|
// give the browser the aspect ratio to reserve.
|
|
//
|
|
// The webp assets are encoded at 3x the largest rendered size (lockup at
|
|
// h-12 = 48 px, mark at h-8 = 32 px), which is why these are 149x144 and
|
|
// 191x96 rather than the 512-wide originals kept as png fallbacks. See
|
|
// tests/Feature/PublicSite/BrandAssetBudgetTest.php.
|
|
$intrinsic = $usesUploadedLogo
|
|
? []
|
|
: ($mark ? ['width' => 191, 'height' => 96] : ['width' => 149, 'height' => 144]);
|
|
@endphp
|
|
|
|
<img
|
|
{{ $attributes->merge([
|
|
'src' => $src,
|
|
'alt' => $resolvedAlt,
|
|
'class' => trim('brand-logo '.$class),
|
|
'decoding' => 'async',
|
|
'loading' => 'eager',
|
|
] + $intrinsic) }}
|
|
/>
|