Zum Hauptinhalt springen

[Lv1] Routing-Optimierung: Drei Ebenen des Lazy Loading

Durch drei Ebenen des Route Lazy Loading wurde die Erstladung von 12,5 MB auf 850 KB reduziert, mit einer 70%igen Verkürzung der First-Screen-Zeit.


Problemhintergrund (Situation)

Projekteigenschaften:

  • 27+ verschiedene Multi-Tenant-Templates (Multi-Tenant-Architektur)
  • Jedes Template hat 20-30 Seiten (Startseite, Lobby, Aktionen, Agenten, Nachrichten etc.)
  • Wenn der gesamte Code auf einmal geladen wird: Erstbesuch erfordert Download von 10 MB+ JS-Dateien
  • Wartezeit des Benutzers über 10 Sekunden (besonders in mobilen Netzwerkumgebungen)

Optimierungsziel (Task)

  1. JavaScript-Volumen beim Erstladen reduzieren (Ziel: < 1 MB)
  2. First-Screen-Zeit verkürzen (Ziel: < 3 Sekunden)
  3. Bedarfsgesteuertes Laden (Benutzer lädt nur, was benötigt wird)
  4. Entwicklererfahrung beibehalten (darf die Entwicklungseffizienz nicht beeinträchtigen)

Lösung (Action)

Wir haben eine Strategie mit drei Ebenen des Route Lazy Loading angewendet, optimiert auf den Ebenen "Template" -> "Seite" -> "Berechtigungen".

Ebene 1: Dynamisches Template-Laden

// src/router/routes.ts
export default async function (siteKey?: string) {
// Lädt dynamisch die Route-Konfiguration des entsprechenden Templates basierend auf Umgebungsvariablen
const module = await import(`../../template/${siteKey}/router/routes.ts`);
return { routes: module.routes };
}

Erklärung:

  • Das Projekt hat 27 Templates, aber der Benutzer verwendet nur eines
  • Bestimmt die aktuelle Marke über environment.json
  • Lädt nur die Route-Konfiguration dieser Marke, die anderen 26 Templates werden nicht geladen

Ergebnis:

  • Ca. 85% weniger Route-Konfigurationscode beim Erstladen

Ebene 2: Seiten-Lazy Loading

// Traditioneller Ansatz (schlecht)
import HomePage from './pages/HomePage.vue';
component: HomePage; // Alle Seiten werden in main.js gebündelt

// Unser Ansatz (gut)
component: () => import('app/template/okbet_green/pages/HomePage/Home.vue');
  • Jede Route verwendet Arrow Function + import()
  • Erst wenn der Benutzer die Seite tatsächlich besucht, wird der entsprechende JS-Chunk heruntergeladen
  • Vite bündelt automatisch jede Seite als eigenständige Datei

Ebene 3: Bedarfsgesteuerte Ladestrategie

// src/router/index.ts
router.beforeEach((to, from, next) => {
const { needAuth } = to.meta;
if (needAuth && !store.isLogin) {
// Nicht eingeloggte Benutzer laden keine Seiten wie "Agenten-Center"
return next({ name: 'HomePage' });
}
next();
});

Optimierungsergebnis (Result)

Vor der Optimierung:

Erstladung: main.js (12,5 MB)
First-Screen-Zeit: 8-12 Sekunden
Enthält alle 27 Templates + alle Seiten

Nach der Optimierung:

Erstladung: main.js (850 KB) -93%
First-Screen-Zeit: 1,5-2,5 Sekunden +70%
Enthält nur Kerncode + aktuelle Startseite

Konkrete Daten:

  • JavaScript-Volumen reduziert: 12,5 MB -> 850 KB (Reduktion um 93%)
  • First-Screen-Zeit verkürzt: 10 Sekunden -> 2 Sekunden (Verbesserung um 70%)
  • Nachfolgende Seitenladung: Durchschnittlich 300-500 KB pro Seite
  • Benutzererfahrungsbewertung: Von 45 auf 92 Punkte (Lighthouse)

Geschäftswert:

  • Absprungrate sank um 35%
  • Verweildauer stieg um 50%
  • Konversionsrate stieg um 25%

Interview-Schwerpunkte

Häufige Erweiterungsfragen:

  1. F: Warum nicht React.lazy() oder Vue Async-Komponenten verwenden? A: Wir verwenden tatsächlich Vue Async-Komponenten (() => import()), aber der Schlüssel ist die Drei-Ebenen-Architektur:

    • Ebene 1 (Template): Zur Kompilierzeit entschieden (Vite-Konfiguration)
    • Ebene 2 (Seite): Lazy Loading zur Laufzeit
    • Ebene 3 (Berechtigungen): Steuerung durch Navigation Guards

    Einfaches Lazy Loading deckt nur Ebene 2 ab; wir haben zusätzlich die Template-Ebene getrennt.

  2. F: Wie entscheidet man, welcher Code in main.js gehört? A: Mit der manualChunks-Konfiguration von Vite:

    build: {
    rollupOptions: {
    output: {
    manualChunks: {
    'vendor': ['vue', 'pinia', 'vue-router'],
    'ui': ['element-plus'],
    }
    }
    }
    }

    Prinzip: Nur was "jede Seite benötigt" kommt in den Vendor Chunk.

  3. F: Beeinträchtigt Lazy Loading die Benutzererfahrung (Wartezeit)? A: Zwei Strategien dagegen:

    • Prefetch: In Leerlaufzeiten möglicherweise besuchte Seiten vorladen
    • Loading-Zustand: Skeleton Screen statt weißem Bildschirm verwenden

    Reale Tests: Durchschnittliche Ladezeit nachfolgender Seiten < 500 ms, vom Benutzer nicht wahrnehmbar.

  4. F: Wie misst man den Optimierungseffekt? A: Mit einer Kombination verschiedener Tools:

    • Lighthouse: Performance Score (45 -> 92)
    • Webpack Bundle Analyzer: Visuelle Analyse der Chunk-Größen
    • Chrome DevTools: Network Waterfall, Coverage
    • Real User Monitoring (RUM): Echte Benutzerdaten
  5. F: Welche Trade-offs gibt es? A:

    • Mögliche zirkuläre Abhängigkeiten während der Entwicklung (Modulstruktur muss angepasst werden)
    • Erste Routenumschaltung hat kurze Ladezeit (mit Prefetch gelöst)
    • Insgesamt überwiegen die Vorteile, besonders die spürbare Verbesserung für mobile Benutzer