From a7dcf4640f4f1bb07cbd29a6126583600abb15a9 Mon Sep 17 00:00:00 2001 From: basantnema31 Date: Wed, 10 Jun 2026 20:31:01 +0530 Subject: [PATCH] perf: implement lazy loading and bundle splitting for faster initial load (resolves #1382) --- next.config.ts | 69 ++++++++++++++++++++++++++-------- src/app/page.tsx | 41 ++++++++++++++++++-- src/components/VideoEditor.tsx | 23 ++++++++++-- 3 files changed, 110 insertions(+), 23 deletions(-) diff --git a/next.config.ts b/next.config.ts index 81ede2f9..3c9e2de3 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,16 +1,53 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - output: "export", - experimental: { - scrollRestoration: true, - }, - // Required for ffmpeg.wasm to load WASM files correctly - // Without this, Next.js might try to process .wasm files and break them - webpack: (config) => { - config.resolve.fallback = { fs: false }; - return config; - }, -}; - -export default nextConfig; \ No newline at end of file +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "export", + experimental: { + scrollRestoration: true, + /** + * Tree-shake lucide-react so only the icons actually used in the + * source are included in the production bundle, instead of the + * full icon library (~2 MB uncompressed). + */ + optimizePackageImports: ["lucide-react"], + }, + // Required for ffmpeg.wasm to load WASM files correctly + // Without this, Next.js might try to process .wasm files and break them + webpack: (config) => { + config.resolve.fallback = { fs: false }; + + /** + * Split large third-party dependencies into separate chunks so the + * browser can cache them independently and users only re-download + * what actually changed between versions. + */ + config.optimization = { + ...config.optimization, + splitChunks: { + chunks: "all", + cacheGroups: { + // Keep ffmpeg.wasm in its own chunk — it is very large and + // changes infrequently, so long-term caching is valuable. + ffmpeg: { + test: /[\\/]node_modules[\\/]@ffmpeg[\\/]/, + name: "ffmpeg", + chunks: "all", + priority: 30, + enforce: true, + }, + // Group all other heavy vendor code together. + vendor: { + test: /[\\/]node_modules[\\/]/, + name: "vendors", + chunks: "all", + priority: 10, + }, + }, + }, + }; + + return config; + }, +}; + +export default nextConfig; \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 381fbd80..9e6f4c4b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,33 @@ -import VideoEditor from "@/components/VideoEditor"; -import Footer from "@/components/Footer"; +"use client"; + +import dynamic from "next/dynamic"; +import { Suspense } from "react"; + +/** + * Lazy-load VideoEditor (the heaviest component ~32 KB). + * `ssr: false` is required because VideoEditor uses browser-only APIs + * (e.g. URL.createObjectURL, navigator, ffmpeg.wasm). + */ +const VideoEditor = dynamic(() => import("@/components/VideoEditor"), { + ssr: false, + loading: () => ( +
+
+
+
+ ), +}); + +/** + * Footer lives below the fold — load it lazily so it never blocks + * the critical rendering path. + */ +const Footer = dynamic(() => import("@/components/Footer"), { + ssr: false, + loading: () => null, +}); export default function Home() { return ( @@ -14,10 +42,15 @@ export default function Home() {
- + + +
-