As is well known, instant page load is important. It doesn’t matter where or when, people hate waiting for pages to load. Therefore, page load consistency is critical for web performance like Core Web Vitals shows.

This article tells you about our origin trial experience for prerendering which is an idea for improving page load consistency.

What Is Prerendering

Prerendering renders likely next pages in advance. The page will be displayed instantly when the link is clicked. This is a huge improvement for user experience.

There are various ways to prerender. This article introduces the new solution, prerendering through Speculation Rules.

The prerendered news page is displayed instantly.

Things You Should Consider Before Prerendering

You should consider some things before enabling prerendering. First, you should stop some function executions during prerendering. For example, the page view logs or performance logs should not be collected twice in a page. Those functions should be delayed until after the page is actually displayed, it is called activation, like the following code example.

Note: Browsers do not start requests to Cross-Origin iframe src in the current implementation. This means prerendering does not affect the standard advertisements. In addition, the processes for viewability are also not executed.


function waitForPageActivation() {
  return new Promise((resolve) => {
    // document.prerendering tells whether the page is prerendering or not
    if (document.prerendering) {
      // The prerenderingchange event occurs when the page has been actually displayed
      document.addEventListener('prerenderingchange', () => resolve());
    } else {
      resolve();
    }
  });
}

waitForPageActivation().then(sendPageView);
waitForPageActivation().then(addPerformanceListener);

Second, if you were measuring RUM, you should change the start time for Largest Contentful Paint (LCP) to the activation time. Otherwise LCP will artificially look as if it got worse. LCP value can be calculated using the following code.


import { getLCP } from 'web-vitals';

getLCP(({ delta }) => {
  const timing = performance.getEntriesByType('navigation')[0];
  // The activationStart value is not set until prerenderingchange event occurs
  const activationStart = timing.activationStart ? timing.activationStart : 0;
  const value = delta - activationStart;
});

Note: The example above uses the stable version of web-vitals.js. There is now an experimental implementation of measuring Prerendered pages in the @next version.

Finally, you should pick up the appropriate page for prerendering. Ideally, the page users frequently access next is a good candidate. The bandwidth or the battery may be consumed too much if they leave the site before accessing the page.

In the trial, the news detail page is prerendered when the news headline page is displayed. We implemented it with the prerender method in the quicklink library.


<script type=”module”>
  import { prerender } from ‘https://.../quicklink.mjs’;

  window.addEventListener('load', () => {
    const match = location.pathname.match(/\\/(.+)\\/hl\\/([0-9a-z-_]+)/);
    if (!match) return;

    const [_, dirname, entryId] = match;
    prerender(`/${dirname}/${entryId}/`);
  });
</script>

As the prerender method is called, the following speculation rules are inserted into the HTML. You can write it directly, but quicklink has improved code readability and helped us to start the trial within a short time.


<script type="speculationrules">
  {"prerender":[{"source": "list","urls": ["/entry/12345/"]}]}
</script>

Calculate Prerendering Hit Ratio

We collected the prerendering hit ratio during this trial. To calculate it, we sent two logs on prerendering and activation using the code below.


if (document.prerendering) {
  // Timing to send prerendering

  document.addEventListener('prerenderingchange', () => {
    // Timing to send activation
  });
}

Result

As a result of the trial in a week, the medium LCP improved a half, from 0.68 seconds to 0.31 seconds. Additionally, the 95th percentile LCP improved the time by 1 second, from 2.2 seconds to 1.2 seconds. This means almost all users can read the news content within 1 second. This makes both users and us happy.

The prerendering hit ratio is around 30 percent. It is not too low, but we should improve the value. To avoid unnecessary resource consumption, browsers should predict more efficiently.

Prerendering quicklink, -1.0s P95 LCP, Prerendering P5 138s P50 310ms P95 1206ms, Non-prerendering P5 216ms P50 680ms P95 2200ms, Ameba