Optimizing Web Performance with Lazy Loading, Code Splitting, and Critical Rendering Path
Lazy loading defers off-screen assets, code splitting loads JavaScript on-demand via dynamic imports, and critical rendering path optimization eliminates render-blocking resources through strategic preloading and critical CSS inlining.
Modern frontend applications must deliver sub-second initial paint times to meet Core Web Vitals standards. The datawhalechina/easy-vibe repository provides concrete implementations for optimizing web performance with lazy loading, code splitting, and critical rendering path strategies using Vue 3 and Vite, documented extensively in the web performance guide at docs/zh-cn/appendix/3-browser-and-frontend/web-performance.md.
Lazy Loading: Deferring Non-Critical Resources
Lazy loading postpones the download of non-essential resources until they enter the viewport or become required by user interaction. This technique directly reduces the initial page weight and improves Largest Contentful Paint (LCP) metrics.
Native Image Lazy Loading
The easiest implementation uses the native HTML loading attribute, which instructs the browser to delay fetching until the image approaches the viewport.
<img src="placeholder.jpg"
data-src="real-image.jpg"
loading="lazy"
alt="Optimized picture" />
According to the easy-vibe source code, this pattern is documented in lines 66–68 of the performance guide, where placeholder-swap strategies load the real asset only when necessary.
Component-Level Lazy Loading
Beyond images, Vue single-file components can be lazy-loaded using dynamic imports wrapped in arrow functions. This ensures that heavy UI elements do not block the initial bundle execution.
// Lazy load a heavy component only when the user clicks "Show More"
document.getElementById('show-more').addEventListener('click', async () => {
const { default: MoreContent } = await import('./components/MoreContent.vue');
// Mount MoreContent logic here
});
Code Splitting: Reducing JavaScript Payload
Code splitting breaks the monolithic JavaScript bundle into smaller chunks that are fetched on demand. This prevents the main thread from being blocked during initial load, improving Time to Interactive (TTI).
Route-Based Dynamic Imports
In Vue Router configurations, define routes using dynamic import() statements to automatically create separate chunks for each page. As implemented in lines 90–95 of the easy-vibe documentation:
// src/router/index.js
const routes = [
{
path: '/about',
// Component is loaded only when the user navigates to /about
component: () => import('../views/About.vue')
},
// additional routes...
];
export default createRouter({ history, routes });
This pattern ensures that users download only the code required for their current view, keeping the initial payload minimal.
Critical Rendering Path: Speeding Up First Paint
The critical rendering path represents the sequence of steps the browser takes to convert HTML, CSS, and JavaScript into pixels on screen. Optimizing this path ensures that above-the-fold content renders as quickly as possible.
Preloading Key Assets
Use <link rel="preload"> to tell the browser which resources are essential for the first paint, allowing it to fetch them with higher priority. The easy-vibe repository demonstrates this in lines 100–104:
<!-- Preload critical CSS and hero image -->
<link rel="preload" href="/assets/css/critical.css" as="style">
<link rel="preload" href="/assets/img/hero-image.jpg" as="image">
Preloading prevents resource discovery delays that normally occur when the browser parses CSS or JavaScript to find additional dependencies.
Inlining Critical CSS
For styles required immediately upon page load, embed them directly within a <style> tag in the document <head>. This eliminates the network request for the critical CSS file. As shown in lines 108–113 of the performance documentation:
<style>
/* Only the CSS required for the above-the-fold view */
.hero { background:#000; color:#fff; }
</style>
Inlining ensures the browser can construct the render tree immediately without waiting for external stylesheets to download.
Complete Implementation Workflow
Combining these three techniques in a VitePress or Vue 3 project produces a streamlined loading sequence:
- Preload critical fonts and the above-the-fold hero image.
- Inline the tiny subset of CSS needed for the initial viewport.
- Lazy load all images below the fold using
loading="lazy". - Split route components so that heavy JavaScript loads only after user navigation.
This workflow aligns with the implementation strategy found in docs/en/stage-3/core-skills/basics/index.md, which lists "component lazy loading to reduce first-screen load time" as a core requirement.
Key Source Files in the Repository
docs/zh-cn/appendix/3-browser-and-frontend/web-performance.md– Comprehensive guide covering lazy loading (lines 66–68), code splitting patterns (lines 90–95), preloading strategies (lines 100–104), and critical CSS inlining (lines 108–113).docs/.vitepress/theme/components/appendix/web-performance/ImageOptimizationDemo.vue– Interactive demonstration of lazy-loaded image techniques used throughout the documentation.vite.config.ts– Vite configuration file where build-time chunking and asset optimization strategies are defined.docs/en/stage-3/core-skills/basics/index.md– Curriculum specification detailing performance requirements including lazy loading mandates.
Summary
- Lazy loading uses native
loading="lazy"attributes or dynamic component imports to defer off-screen assets, reducing initial page weight. - Code splitting leverages dynamic
import()in Vue Router to create route-specific chunks, ensuring users download only the JavaScript required for their current view. - Critical rendering path optimization combines
<link rel="preload">for key assets and inline CSS for above-the-fold content to achieve the fastest possible First Contentful Paint (FCP). - Together, these techniques improve Core Web Vitals including LCP, CLS, and TTI without sacrificing functionality.
Frequently Asked Questions
What is the difference between lazy loading and code splitting?
Lazy loading typically refers to deferring the download of assets—such as images or components—until they are needed, often using browser-native APIs or intersection observers. Code splitting is a build-time technique that divides JavaScript bundles into separate files so that only the code required for the initial route is executed. While lazy loading delays resource fetching, code splitting reduces the amount of JavaScript parsed and executed on startup.
How does preloading improve the critical rendering path?
Preloading tells the browser to initiate high-priority requests for resources—such as fonts, hero images, or critical CSS—early in the document parsing phase, before the renderer discovers them in CSS or JavaScript. This eliminates network latency from the render-blocking path, allowing the browser to construct the render tree and paint pixels faster.
When should I inline CSS versus loading it externally?
Inline critical CSS directly into the HTML <head> when the styles are required for the above-the-fold content and are small enough that the inline block does not bloat the initial HTML payload. Load non-critical CSS externally using <link rel="stylesheet"> or asynchronous loading techniques for styles that apply to below-the-fold content or subsequent interactions.
Can I implement these optimizations without a framework like Vue?
Yes. Native browser APIs support all three techniques: use loading="lazy" for images, dynamic import() for JavaScript modules (supported in modern browsers), and standard <link> tags for preloading. However, build tools like Vite (as configured in vite.config.ts within the easy-vibe repository) automate code splitting and asset optimization, making implementation significantly more maintainable.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →