📝 BLOG

JavaScript Optimization: Performance, Bundle Size and Loading

JavaScript optimization directly affects page loading speed and interaction performance (INP). This guide covers bundle reduction, code splitting, lazy loading, and performance techniques.

Last updated:

Prepared by: Gsetsoft

JavaScript Optimization: Performance, Bundle Size and Loading

Why JavaScript Performance Matters

JavaScript is the most CPU-consuming resource in the browser. Large JS files increase parse and compile time and negatively affect INP (Interaction to Next Paint) metric.

Typically JavaScript makes up 40-60% of page weight. Unused JavaScript causes unnecessary CPU and memory consumption.

JavaScript optimization improves Core Web Vitals metrics (especially INP and LCP). Optimized JS provides a faster and more responsive user experience.

Bundle Size Optimization

Tree shaking: Remove unused exports. Use ES modules (import/export). CommonJS (require) doesn't support tree shaking.

Bundle analysis: Visualize bundle contents with webpack-bundle-analyzer or rollup-plugin-visualizer. Identify which libraries take up the most space.

Alternative libraries: day.js instead of moment.js (2KB vs 300KB), lodash-es or native methods instead of lodash. Replace large libraries with lighter alternatives.

Dependency audit: Detect unused dependencies with npm ls or depcheck. Remove unnecessary dependencies from package.json.

Code Splitting

Route-based splitting: Create separate bundle for each page. Lazy load page components with React.lazy() and Suspense.

Component-based splitting: Split heavy components (modal, chart, editor) into separate chunks. Load on demand with dynamic import().

Vendor splitting: Split node_modules dependencies into separate vendor chunk. Vendor chunk doesn't change and stays in browser cache.

Webpack: Automatic code splitting with optimization.splitChunks. Vite: Rollup's automatic code splitting. Next.js: Automatic route-based splitting.

Lazy Loading

Dynamic import(): Module is loaded on demand with const module = await import('./heavy-module.js');.

Intersection Observer: Load component when visible. Lazy load below-the-fold components with React.lazy + Intersection Observer.

Prefetch and preload: Prefetch non-critical modules in the background. Browser loads when idle with <link rel="prefetch" href="chunk.js">.

React Suspense: Show loading state for lazy loaded components with <Suspense fallback={<Loading />}><LazyComponent /></Suspense>.

Performance Techniques

Debounce and throttle: Use debounce/throttle on scroll, resize, and input events. Implement with Lodash debounce or native setTimeout.

Web Workers: Separate heavy computations from main thread. Run CPU-intensive work in background with new Worker('worker.js').

requestAnimationFrame: Synchronize animations and DOM updates with requestAnimationFrame. Target 60fps.

Virtual scrolling: Render only visible items in large lists (1000+ items). Use react-window or vue-virtual-scroller.

Memoization: Prevent unnecessary computations and re-renders with useMemo, useCallback, and React.memo.

Measurement and Monitoring

Lighthouse Performance audit: Check JavaScript execution time, unused JavaScript, and bundle size metrics.

Chrome DevTools Performance tab: Analyze JavaScript execution, scripting, and rendering times. Detect long tasks and main thread blocking.

Web Vitals: Monitor INP, LCP, and CLS metrics. Collect real user data with web-vitals library.

Real User Monitoring (RUM): Monitor real user performance data with Sentry, Datadog, or New Relic.

Your privacy choice

Essential cookies support security and sessions. Basic visits are also counted; with your permission we enable additional usage analytics. Cookie Policy