Frontend Development 22 min read

How We Cut H5 Page Load Time by 50%: A Deep Dive into Performance Optimization

This article details the systematic performance optimization of Penguin Tutor's H5 core pages, covering metric collection, analysis methods, environment setup, and concrete practices such as network tuning, code splitting, lazy loading, resource hints, and server‑side improvements that reduced total bundle size by 50% and cut onload time from over 6 seconds to around 1.2 seconds.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
How We Cut H5 Page Load Time by 50%: A Deep Dive into Performance Optimization
Penguin Tutor's H5 pages accumulated performance issues after years of iteration, causing slow page load and render speeds. This article summarizes a dedicated optimization project aimed at improving loading and rendering performance.

Project Background

The H5 project is a core component of Penguin Tutor, including course detail, teacher detail, enrollment, and payment pages, deployed to the app and various browsers. Over four years, performance regressions emerged, prompting a focused "H5 Performance Optimization" effort.

Performance optimization results

Performance metrics and data collection

Performance analysis methods and environment preparation

Specific optimization practices

Performance Metrics and Data Collection

The project tracks several key metrics:

First Contentful Paint (FCP) : time from page start to first content display.

Largest Contentful Paint (LCP) : time to render the largest text block or image.

DomContentLoaded Event: DOM parsing completion time.

OnLoad Event: full resource load time.

First Input Delay (FID) : delay from first user interaction to browser response.

Cumulative Layout Shift (CLS) : score of unexpected layout shifts.

Data is reported via IMLOG and monitored with an ELK stack in Grafana.

Performance Analysis and Environment Preparation

Initial observations showed a progress bar continuing for over ten seconds after the page was displayed, indicating a long onload time.

When navigation finishes, the render process loads resources and renders the page. Once the render process signals "finished" (all frames' onload events have fired), the UI thread stops the loading spinner.

Thus, reducing onload time directly shortens the progress bar duration. Chrome DevTools was used for analysis, focusing on Network, Performance, and Lighthouse panels.

1. Network Analysis

Testing under disabled cache and 4G/3G throttling revealed a DOMContentLoaded time of 6.03 s but an onload time of 20.92 s. The longest request during DOMContentLoaded was vendor.js (170 KB, 4.32 s).

Further inspection showed that onload was blocked by many media resources (images, videos, iframes).

2. Performance Analysis

Key Web Vitals (FP/FCP/LCP/CLS) and timings indicated late LCP and multiple layout shifts. Long tasks were observed, notably course.js taking up to 800 ms.

3. Lighthouse Analysis

Lighthouse scores were low, with TTI, SI, TBT, and LCP needing improvement. Diagnostics offered specific optimization suggestions such as image compression and removing unused JS.

Environment Preparation

Performance testing required realistic environment simulation using tools like Whistle, Charles, Fiddler for proxying, and local/nginx or STKE for server simulation. Data reporting tools (IMLOG, TAM, RUM) and bundle analysis tools (webpack‑bundle‑analyzer, rollup‑plugin‑visualizer) were employed.

Specific Optimization Practices

PART1: Loading Time Optimization

1. Critical JS Bundle Optimization

Vendor.js (170 KB gzipped) contained many modules that were only used by a few pages. By adjusting miniChunks rules and extracting truly shared dependencies into a separate common.js , vendor size dropped to 30 KB and common.js to 42 KB, achieving a 60% reduction.

<code>vendor: {
  test({ resource }) {
    return /[\\/]node_modules[\\/](@tencent\/imutils|imlog\/)|qqapi/.test(resource);
  },
  name: 'vendor',
  priority: 50,
  minChunks: 1,
  reuseExistingChunk: true,
},
</code>

2. On‑Demand Loading of Public Components

The Icon component (25 KB) was loaded on every page despite only eight icons being used. Switching to per‑icon imports via

babel-plugin-import

reduced the Icon bundle from 74 KB to 20 KB (≈70% reduction).

3. Code Splitting of Business Components

Non‑critical sections such as "Course Outline", "Course Details", and "Purchase Notice" were split into separate chunks using

React.lazy

or

loadable‑components

, allowing delayed loading and smaller initial JS payload.

4. Tree Shaking

Ensured proper

sideEffects

configuration to avoid dead code in the final bundle.

2. Non‑Critical JS Deferred Loading

Reporting scripts (Sentry, beacon SDK) and captcha components were loaded after the page load using a prefetch check:

<code>const isPrefetchSupported = () => {
  const link = document.createElement('link');
  const { relList } = link;
  if (!relList || !relList.supports) { return false; }
  return relList.supports('prefetch');
};

const prefetch = () => {
  if (isPrefetchSupported()) {
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.as = type;
    link.href = url;
    document.head.appendChild(link);
  } else if (type === 'script') {
    // load script
  }
};
</code>

This prevented non‑essential scripts from blocking the onload event.

3. Media Resource Loading Optimization

3.1 Load Sequencing

Images and videos not visible on initial render were lazy‑loaded using viewport detection (getBoundingClientRect).

3.2 Size Optimization

Large images (e.g., 1715 px width) were served via CDN with dynamic resizing (srcset/sizes) and format selection, achieving up to 13× size reduction on weak networks.

3.3 Other Resources

Iframes were deferred until after onload using setTimeout, and data‑reporting images were delayed or sent via Beacon API to avoid blocking the load event.

PART2: Rendering Optimization

1. TTFB Reduction

Analysis showed that the NGW gateway and STKE service were in different regions, causing ~120 ms network latency. Deploying the gateway and service in the same region reduced average gateway time from 153 ms to 31 ms (≈80% improvement).

2. CSS Rendering Optimization

Only 15% of CSS was used on the first screen. Critical CSS was inlined using

critters

, allowing the page to render before full CSS download.

3. Layout Shift Mitigation

Fixed element dimensions, used base64 for small images, and ensured dynamic content did not alter layout unexpectedly.

Optimization Results

Key improvements:

Bundle size reduced from 460.8 KB to 308 KB (≈50%).

Largest file size reduced from 170 KB to 109 KB (≈56%).

Onload time decreased from 6.18 s to 1.19 s (≈81% reduction).

Lighthouse performance score increased from ~45 to ~80 (≈47% boost).

Progress‑bar load time dropped from 4632 ms to 2581 ms (≈45% improvement).

Conclusion and Future Plans

Further work includes PWA adoption, skeleton screens for non‑direct pages, and CSR‑to‑SSR migration.

CDN migration is planned to reduce download latency.

Continuous performance monitoring will be integrated into the development workflow.

Page‑specific optimizations require proactive developer involvement.

Thank you for reading; feedback and discussion are welcome.

frontendperformanceoptimizationwebh5
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.