Files
recipe-app/.kilo/plans/flutter-lighthouse.md
Nils-Johan Gynther 69bcc3e342
Test Suite / backend-pr-quick (push) Has been skipped
Test Suite / quick-import-pr-quick (push) Has been skipped
Test Suite / backend-full (push) Successful in 14m6s
Test Suite / flutter-quality (push) Failing after 4m44s
feat(web): improve web build configuration and accessibility
- Add source maps and web renderer build arguments with defaults
- Configure Caddy with CSP headers, cache policies, and service worker handling
- Defer loading of import screen for performance optimization
- Add semantic labels to icons for accessibility
- Update web index.html with Swedish language, meta tags, and description
- Add robots.txt and lighthouse configuration
- Add new planning documents and archive entries
2026-05-23 18:04:27 +02:00

14 KiB
Raw Permalink Blame History

🚹 Kritiska Problem (Prioritet 1: Fixa Omedelbart) Dessa problem pĂ„verkar anvĂ€ndarupplevelsen mest och bör Ă„tgĂ€rdas först.

  1. Prestanda: LĂ„ngsam inladdning & Stora Filer 🔮 Problem:

Total storlek: 2,978 KiB (för stor för en webbapp).

/main.dart.js: 1,216 KiB (Flutter’s kompilade JavaScript). canvaskit.wasm: 1,592 KiB (Flutter’s CanvasKit-renderare). MaterialIcons-Regular.otf: 9.8 KiB (ikoner).

Largest Contentful Paint (LCP) misslyckades (tidsgrĂ€ns överskreds). Total Blocking Time (TBT) misslyckades (lĂ„nga JavaScript-uppgifter blockerar huvudtrĂ„den). JavaScript-exekveringstid: 1.8s (för lĂ„ngt). 🟱 Lösningar: A. Optimera Flutter för Web Flutter-webbappar Ă€r tyngre Ă€n traditionella webbappar pĂ„ grund av CanvasKit. HĂ€r Ă€r hur du minskar storleken:

AnvÀnd HTML-renderaren istÀllet för CanvasKit

CanvasKit ger bĂ€ttre grafik men Ă€r mycket tyngre. Ändra i index.html: html Copy

<script> window.flutterConfiguration = { renderMode: "html", // IstÀllet för "canvas" (CanvasKit) }; </script>

Fördel: Minskar storleken med ~1.5MB (WASM-filen laddas inte). Nackdel: Vissa avancerade animationer/efekter fungerar inte lika bra.

Aktivera komprimering (GZIP/Brotli)

Din server skickar okomprimerade filer. Lösning:

Nginx: LĂ€gg till i konfigurationen: nginx Copy

gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; brotli on; brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

Apache: AnvÀnd mod_deflate eller mod_brotli. Cloudflare: Aktivera "Brotli Compression" i instÀllningarna.

Cachea statiska resurser

Problem: /main.dart.js och flutter_bootstrap.js har ingen cache-TTL. Lösning: LÀgg till Cache-Control-headers: nginx Copy

location ~* .(js|css|png|jpg|jpeg|gif|ico|wasm|otf)$ { expires 1y; add_header Cache-Control "public, immutable"; }

Besparing: ~1.2MB vid upprepade besök.

Dela upp JavaScript-koden (Code Splitting)

Flutter laddar allt i en stor fil (main.dart.js). Lösning: AnvÀnd deferred imports för att ladda funktioner pÄ begÀran: dart Copy

// I din Dart-kod: import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:my_app/receipt_import.dart' deferred as receipt_import;

// Ladda endast nÀr behövs: Future loadReceiptImport() async { await receipt_import.loadLibrary(); }

Effekt: Minskar initial laddningstid.

Optimera bilder

Problem: Bilder laddas inte optimalt. Lösning:

AnvÀnd flutter_image_compress för att komprimera bilder innan uppladdning. För webb: AnvÀnd med srcset för responsiva bilder. Exempel: html Copy

Receptbild

B. FörbÀttra Laddningsordningen

Fördröj laddning av icke-kritiska resurser

Ladda canvaskit.wasm efter att sidan har renderats: html Copy

<script> window.addEventListener('load', () => { const script = document.createElement('script'); script.src = 'https://www.gstatic.com/canvaskit/v1/chromium/canvaskit.wasm'; document.body.appendChild(script); }); </script>

AnvÀnd preload för kritiska resurser

LĂ€gg till i <head>: html Copy

  1. TillgĂ€nglighet: GrundlĂ€ggande Problem 🔮 Problem:

[user-scalable="no"] i viewport-meta-taggen

Varför det Àr dÄligt: AnvÀndare med nedsatt syn kan inte zooma in. Lösning: Ta bort user-scalable="no": html Copy

Saknas alt-texter pÄ bilder

Problem: SkÀrmlÀsare kan inte beskriva bilder. Lösning: LÀgg till alt-texter i Flutter: dart Copy

Image.network( 'https://example.com/recept.jpg', semanticLabel: 'Bild pÄ lasagne med ost och tomatsÄs', // Alt-text ),

Saknas lang-attribut

Problem: SkÀrmlÀsare vet inte vilket sprÄk sidan anvÀnder. Lösning: LÀgg till i <html>: html Copy

<html lang="sv">
  1. SEO: GrundlĂ€ggande Problem 🔮 Problem:

Saknas meta description

Varför det Àr dÄligt: Sökmotorer visar ingen beskrivning i resultaten. Lösning: LÀgg till i <head>: html Copy

Ogiltig robots.txt

Problem: Din robots.txt innehÄller HTML-kod istÀllet för korrekt syntax. Lösning: Skapa en korrekt robots.txt: text Copy

User-agent: * Allow: / Sitemap: https://recept.gynther.se/sitemap.xml

⚠ Viktiga FörbĂ€ttringar (Prioritet 2: Fixa Inom 1-2 Veckor) Dessa problem pĂ„verkar anvĂ€ndarupplevelsen och SEO, men Ă€r inte lika kritiska.

  1. Prestanda: JavaScript & Rendering 🟡 Problem:

LÄng JavaScript-exekveringstid (1.8s)

Orsak: Flutter’s main.dart.js tar 1.7s att parsas och exekveras.

Minify CSS/JS misslyckades

Flutter genererar redan minifierad kod, men du kan optimera vidare.

🟱 Lösningar:

Aktivera Flutter’s --release flagga

Bygg appen med: bash Copy

flutter build web --release

Detta genererar optimerad och minifierad kod.

AnvÀnd flutter build web --no-source-maps

Source maps ökar filstorleken. Ta bort dem i produktion: bash Copy

flutter build web --no-source-maps

Fördröj laddning av icke-kritisk JavaScript

AnvÀnd defer eller async för skript som inte behövs omedelbart: html Copy

<script src="/flutter_bootstrap.js" defer></script>

Reducera DOM-storlek

Problem: Din sida har 21 element med en max-djup pÄ 7 (acceptabelt, men kan optimeras). Lösning: Undvik onödiga Container-widgets i Flutter. AnvÀnd const widgets dÀr möjligt.

  1. TillgĂ€nglighet: Interaktiva Element 🟡 Problem:

Saknas focus-indikatorer

AnvÀndare som navigerar med tangentbord ser inte vilka element som Àr fokuserade.

Saknas aria-label pÄ anpassade knappar

SkÀrmlÀsare vet inte vad knapparna gör.

🟱 Lösningar:

LĂ€gg till focus-stilar i CSS

Exempel: css Copy

button:focus, [tabindex="0"]:focus { outline: 2px solid #4285F4; outline-offset: 2px; }

AnvÀnd semantics i Flutter för tillgÀnglighet

Exempel för en knapp: dart Copy

Semantics( label: 'Importera kvitto', button: true, child: ElevatedButton( onPressed: () => _importReceipt(), child: Text('Importera'), ), ),

LÀgg till aria-label pÄ ikonknappar

Exempel: dart Copy

IconButton( icon: Icon(Icons.upload), onPressed: () => _uploadFile(), tooltip: 'Ladda upp kvitto', // Visas pÄ hover semanticsLabel: 'Ladda upp kvitto', // För skÀrmlÀsare ),

  1. SĂ€kerhet: Content Security Policy (CSP) 🟡 Problem:

Saknas CSP-header

Din sida Àr sÄrbar för XSS-attacker (Cross-Site Scripting).

🟱 Lösning: LĂ€gg till en stark CSP i din serverkonfiguration: nginx Copy

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://*.gstatic.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://recept.gynther.se; frame-src 'none'; object-src 'none';";

Förklaring:

script-src: TillÄter skript frÄn self och gstatic.com (för Flutter). unsafe-inline: NödvÀndigt för Flutter (men försök minska anvÀndningen). img-src: TillÄter bilder frÄn self och gstatic.com.

📌 Mindre Problem (Prioritet 3: Fixa NĂ€r Tid Finns) Dessa Ă€r förbĂ€ttringar som inte Ă€r kritiska men kan förbĂ€ttra UX och SEO.

  1. Prestanda: Bildoptimering

Problem: Bilder laddas utan width och height (orsakar layout shifts). Lösning: AnvÀnd Image.network med explicit storlek: dart Copy

Image.network( 'https://example.com/recept.jpg', width: 300, height: 200, fit: BoxFit.cover, ),

  1. SEO: Structured Data

Problem: Saknas schema.org-markup för recept (gör att Google kan visa "rich results"). Lösning: LÀgg till JSON-LD i <head>: html Copy

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Recipe", "name": "Lasagne", "author": { "@type": "Person", "name": "Nils-Johan Gynther" }, "datePublished": "2026-05-21", "description": "En klassisk lasagne med köttfÀrs och bechamelsÄs.", "prepTime": "PT30M", "cookTime": "PT45M", "totalTime": "PT1H15M", "recipeYield": "4 portioner", "recipeCategory": "Middag", "recipeCuisine": "Italiensk", "keywords": "lasagne, pasta, köttfÀrs", "recipeIngredient": ["500g köttfÀrs", "250g ost", "1 paket lasagneplattor"], "recipeInstructions": [ { "@type": "HowToStep", "name": "Börja med att frÀsa köttfÀrsen.", "text": "FrÀs köttfÀrsen i en stekpanna tills den Àr genomstekt." }, { "@type": "HowToStep", "name": "Lagra lasagnen i ugnen.", "text": "Skikta lasagneplattor, köttfÀrs och sÄs i en ugnsform. GrÀdda i 45 minuter pÄ 200°C." } ] } </script>

Effekt: Google kan visa receptkort i sökresultaten (ökad klickfrekvens).

  1. TillgÀnglighet: Logisk Tab-Order

Problem: AnvÀndare kan tabba till element som Àr dolda eller off-screen. Lösning: AnvÀnd FocusableAction i Flutter för att kontrollera tab-order: dart Copy

FocusableActionDetector( autofocus: true, onFocusChange: (hasFocus) { if (hasFocus) { // Hantera focus } }, child: MyWidget(), ),

📊 Sammanfattning av Prioriteringar

  Prioritet
  Problem
  Lösning
  Tidsuppskattning
  Impact




  1 (Kritisk)
  Stora filer (2.9MB)
  Byt till HTML-renderare, aktivera GZIP, cachea resurser
  1-2 timmar
  ⭐⭐⭐⭐⭐ (Hög)


  1 (Kritisk)
  LÄng JavaScript-exekvering (1.8s)
  Code splitting, defer non-critical JS
  2-4 timmar
  ⭐⭐⭐⭐⭐ (Hög)


  1 (Kritisk)
  user-scalable="no"
  Ta bort frÄn viewport-meta-taggen
  5 minuter
  ⭐⭐⭐⭐ (Hög)


  1 (Kritisk)
  Saknas meta description
  LĂ€gg till i 
  5 minuter
  ⭐⭐⭐ (Medel)


  1 (Kritisk)
  Ogiltig robots.txt
  Skapa korrekt robots.txt
  10 minuter
  ⭐⭐⭐ (Medel)


  2 (Viktig)
  Saknas CSP-header
  LĂ€gg till i serverkonfigurationen
  1 timme
  ⭐⭐⭐⭐ (Hög)


  2 (Viktig)
  Saknas alt-texter
  LĂ€gg till semanticLabel i Flutter
  1-2 timmar
  ⭐⭐⭐ (Medel)


  2 (Viktig)
  LÄng DOM-parsning
  Minska onödiga widgets
  1-2 timmar
  ⭐⭐ (LÄg)


  3 (Mindre)
  Saknas structured data
  LÀgg till JSON-LD för recept
  1 timme
  ⭐⭐ (LÄg)

đŸ› ïž Konkreta ÅtgĂ€rder (Steg-för-Steg) Steg 1: Fixa Prestanda (1-2 dagar)

Byt till HTML-renderare (sparar ~1.5MB):

Ändra index.html som visat ovan.

Aktivera GZIP/Brotli pÄ servern. Cachea statiska filer (1 Är för JS/CSS). Bygg appen med --release: bash Copy

flutter build web --release --no-source-maps

Ladd upp den optimerade versionen till din server.

Steg 2: Fixa TillgÀnglighet (1 dag)

Ta bort user-scalable="no" frÄn viewport. LÀgg till lang="sv" i <html>. LÀgg till alt-texter pÄ alla bilder. LÀgg till semanticsLabel pÄ knappar och ikoner.

Steg 3: Fixa SEO (1 dag)

LÀgg till meta description. Fixa robots.txt. LÀgg till structured data för recept.

Steg 4: SĂ€kerhet (1 timme)

LĂ€gg till CSP-header i serverkonfigurationen.

📈 FörvĂ€ntade Resultat

  MĂ€tning
  Nuvarande
  Efter Fixar
  FörbÀttring




  Total storlek
  2,978 KiB
  ~500-800 KiB
  -70%


  Laddningstid (LCP)
  Timeout
  < 2.5s
  ✅ Fixad


  JavaScript-exekvering
  1.8s
  < 1s
  -45%


  TillgÀnglighet
  82/100
  95+/100
  +15 poÀng


  SEO
  6/10
  9/10
  +50%


  SĂ€kerhet
  Risk för XSS
  Skyddad
  ✅ Fixad

🔍 Hur du Testar FörbĂ€ttringarna

Kör Lighthouse igen i Chrome DevTools (F12 → "Lighthouse"). Testa pĂ„ mobil (anvĂ€nd Chrome’s "Device Toolbar"). AnvĂ€nd WebPageTest (webpagetest.org) för att mĂ€ta prestanda globalt. Testa tillgĂ€nglighet med:

WAVE Evaluation Tool SkÀrmlÀsare (t.ex. NVDA eller VoiceOver).

💡 Extra Tips för Flutter-Webbappar

AnvÀnd flutter build web --target=lib/main_deferred.dart

FörbÀttrar code splitting.

Ladda Flutter asynkront

LĂ€gg till async i <script>-taggen: html Copy

<script src="/flutter_bootstrap.js" async></script>

AnvÀnd flutter_tex för text-rendering

Minskar beroendet av CanvasKit.

Override Flutter’s default fonts

AnvÀnd systemtypsnitt för snabbare laddning: css Copy

@font-face { font-family: 'Roboto'; src: local('Roboto'), local('Roboto-Regular'); }

🎯 Sammanfattning: Vad du ska göra nu

Fixa de kritiska prestandaproblemen (HTML-renderare, GZIP, caching). Fixa tillgÀnglighetsproblemen (user-scalable, alt-texter, lang). Fixa SEO (meta description, robots.txt). LÀgg till sÀkerhetsheaders (CSP). Testa och iterera med Lighthouse.