feat(web): improve web build configuration and accessibility
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

- 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
This commit is contained in:
Nils-Johan Gynther
2026-05-23 18:04:27 +02:00
parent 30d27d6b8a
commit 69bcc3e342
16 changed files with 1847 additions and 301 deletions
+706
View File
@@ -0,0 +1,706 @@
🚨 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 (Flutters kompilade JavaScript).
canvaskit.wasm: 1,592 KiB (Flutters 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<void> 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 <picture> med srcset för responsiva bilder.
Exempel:
html
Copy
<picture>
<source srcset="image-480w.jpg" media="(max-width: 600px)">
<source srcset="image-800w.jpg" media="(max-width: 1200px)">
<img src="image-1200w.jpg" alt="Receptbild">
</picture>
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
<link rel="preload" href="/main.dart.js" as="script">
<link rel="preload" href="/flutter_bootstrap.js" as="script">
2. 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
<meta name="viewport" content="width=device-width, initial-scale=1.0">
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">
3. 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
<meta name="description" content="Upptäck och lagra dina recept. Importera kvitton och håll koll på ditt kylskåp med vår smarta app.">
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: Flutters 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 Flutters --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.
2. 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
),
3. 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,
),
2. 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).
3. 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 Chromes "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 Flutters 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.