Skip to content

Performance Optimisation & Core Web Vitals #841

Description

@DokaIzk

Title: perf: optimise Next.js bundle and achieve green Core Web Vitals scores

Labels: frontend performance quality
Complexity: medium
Branch: perf/core-web-vitals
Depends on: FE-6, FE-7, FE-8


Problem Context

A slow frontend undermines the credibility of SoroScan as a production-grade tool. Google measures Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and Interaction to Next Paint (INP) as ranking signals and user-experience indicators. Achieving green Core Web Vitals is both a UX requirement and an SEO necessity.


Scope

Included:

  • @next/bundle-analyzer audit and large dependency elimination
  • Dynamic imports (next/dynamic) for heavy components (charts, editors, Monaco)
  • Image optimisation with next/image across all pages
  • Font optimisation with next/font to eliminate layout shift from font loading
  • Route-based code splitting verification
  • web-vitals library integration for reporting LCP, CLS, INP to console (dev) and analytics (prod)
  • Lighthouse CI in GitHub Actions reporting scores on every PR

Not included:

  • CDN / edge caching setup (infrastructure-level)
  • Service worker / PWA (separate issue)

Implementation Guidelines

Files to create/update:

  • next.config.ts — enable bundleAnalyzer, set images.domains, configure swcMinify
  • src/app/layout.tsx — switch to next/font for all typefaces
  • src/lib/web-vitals.tsreportWebVitals callback
  • src/app/page.tsx — use next/image for all hero/logo images
  • .github/workflows/lighthouse.yml — Lighthouse CI action

Bundle analysis workflow:

ANALYZE=true npm run build
# Opens bundle-analyzer in browser — identify chunks > 100 KB

Dynamic import pattern for heavy charts:

const EventTimelineChart = dynamic(
  () => import('@/components/charts/EventTimelineChart'),
  { loading: () => <Skeleton className="h-64 w-full" />, ssr: false }
);

Lighthouse CI config:

# lighthouserc.js
module.exports = {
  ci: {
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.9 }],
        'categories:accessibility': ['error', { minScore: 0.9 }],
        'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
      },
    },
  },
};

Constraints:

  • First-load JS bundle for the landing page must not exceed 200 KB (compressed)
  • No layout shift from late-loading fonts or images (use width/height on all <Image> components)
  • All dynamic() fallbacks must use shadcn <Skeleton> components to avoid CLS

Acceptance Criteria

  • Lighthouse Performance score ≥ 90 on the landing page
  • LCP ≤ 2.5 s, CLS ≤ 0.1, INP ≤ 200 ms on desktop
  • First-load JS ≤ 200 KB (gzip) on the landing page
  • All images use next/image with explicit dimensions
  • All fonts loaded via next/font with display: swap
  • Lighthouse CI action blocks PRs that regress Performance below 90



Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions