DEV Community

Cover image for Killblanks use pre-render and skeleton screen to solve page blanks
Phillips
Phillips

Posted on

Killblanks use pre-render and skeleton screen to solve page blanks

Preface

White screens have always been a major problem that has plagued the front-end when the CSR project was born. How to increase the waiting time of users, reduce the bounce rate, and improve the page performance under the condition of low cost is the front-end has been solving problems. This kind of solution directly generates a skeleton screen from the page node, and pre-renders the user to display the outline of the content while waiting for the content to load, providing a better user experience and making the content feel faster.

How does the white screen come about

This is a screenshot of the Chrome performance of a normal CSR project. As you can see from the snapshot, the time for the white screen is about 330ms.

The execution logic of the page during this time:

  • Request HTML -> Wait for HTML document -> Parse HTML -> Request JS and CSS resources -> Execute vendors and index.js logic

After 330ms, the page appears in a general frame, the execution logic of the page:

  • vue render each component -> mounted page mount -> call the business API request data -> render the returned data -> complete page

It is precisely because the CSR project spends a lot of time in the processes of waiting for file loading, CSSOM construction, JS parsing, etc., that the user will be in a state of gray and white screens that are not interactive for a long time, that is, blanks.

For details, please see the article of Hanyang Pre-rendering during construction: Practice of first frame optimization of web pages

What will the white screen affect

By analyzing more than 150 websites and page abandonment data of 150 million page visits, Gomez discovered the lack of visitor loyalty. The page response time increased from 2 seconds to 10 seconds, and the page bounce rate increased by 38%.

To put it simply, each additional 1s of page waiting time is a decrease in the bounce rate and transaction rate for the app. For the boss, it is "losing money", and for you, it is impossible to increase the salary.

Currently commonly used white screen solutions

Scheme Pre-rendering SSR NSR
Advantages Does not rely on data SEO friendly, easy to build, FMP is faster than pre-rendering SEO friendly, high first screen performance, FMP is the fastest
Disadvantages SEO is not friendly, FMP is slow High cost, high front-end load pressure High cost, high client pressure

Both SSR and NSR are very good solutions to the white screen, but the shortcomings are also obvious. The cost is too high. SSR relies heavily on the stability of the service. For small and medium-sized companies, there are few resources to provide a stable server for the front end. In the environment, once the node fails, the loss is great, and the CSR solution is very costly for the client and there are many uncertainties.

Pre-rendering is not a silver bullet

Based on this, pre-rendering may be the simplest and most practical solution, but pre-rendering is not a silver bullet, let’s take a look at the first version of our team’s implementation of pre-rendering

When you happily hand over the hard-made pre-rendering to the visual inspection, you may get just a word ugly :(

That's right, ugly or unfriendly, feeling that the internet speed is very slow, these are the reactions of colleagues who have seen the first version. Why is this happening?

It can be found by comparing the two screenshots

  • 1. The picture is not loaded, causing a large area of ​​color blocks on the page
  • 2. The back-end request is not returned, which also caused the vacancy of the page and even the deformation of the frame

We found that the problem is mainly in the placeholder element. If the element can be placed in advance, the pre-rendering can render a very beautiful page, so is there any placeholder element that is convenient fast good-looking?

When I searched for a solution, I found that someone had proposed a placeholder solution.

A scheme for automatically generating skeleton screens

Skeleton screen

Yes, it is @Jocs, who shared A scheme for automatically generating skeleton screens, and the subsequent open source page-skeleton-webpack-plugin, providing a lower cost solution The plan of the skeleton screen provides a new idea for the realization of the skeleton screen. For the specific plan, please see his article

It is a pity that the page-skeleton-webpack-plugin has not been updated and maintained for three years. Although it is a very feasible solution, there is still a lot of room for improvement, so I decided to use the page-skeleton-webpack-plugin On the basis of, provide a more convenient solution, this is the origin of Killblanks

Killblanks

This project officially started in 2020. After half a year of debugging and development, it finally successfully passed the abtest test and went live. And in February 2021 open source, thanks to everyone who paid for it.

Principle

Use Purpeteer to simulate the browser request page function, and load the Google plug-in @killblanks/skeleton-ext Generate the page of the skeleton screen component, straight out the html file

Frame

Currently Killblanks is built on lerna and consists of three core functions

Use

Killblanks is very convenient to use, if you understand the principle, you can get started in three minutes

1. Installation

  yarn add @killblanks/prerender -D
Enter fullscreen mode Exit fullscreen mode

2. Configuration

// webpack.config.js
const prerender = require('@killblanks/prerender')

export default {
  ...
  plugins: [new prerender()]
  ...
}
Enter fullscreen mode Exit fullscreen mode

3. Use @killblanks/skeleton-ext

4. Use the generated skeleton screen components in the project

  • For example, like what is done in DEMO
    // index.vue
    <template>
      <div class="container">
        <skeleton :show="!!filterProductList.length">
          <div class="productionList">
            <div v-for="(item, key) in filterProductList" :key="item.goods_id + key" class="production">
              xxx
            </div>
          </div>
        </skeleton>
      </div>
    </template>

    <script>
    import skeleton from './skeleton'
    export default {
      components: {
        skeleton
      },
      data: () => {
        return {
          filterProductList: []
        }
      },
      mounted() {
        setTimeout(() => {
          const res = JSON.parse(
            `{"goods_id":"5e7d6d331d41c801b95f594f","name":"skeleton-test","photo":"https://o-static.ihago.net/ikxd/e62403ac0d365c57b4dbc1a0ab7e9cf4/128.png","svga_photo":"","tag":"new","type":1,"type":1805,"real_price":199,"price":299,"discount":8000,"update_time":1594695268}`
          )
          this.filterProductList = Array(10).fill(res)
        }, 3000)
      }
    }
    </script>
Enter fullscreen mode Exit fullscreen mode
    // skeleton.vue
      <script>
    import Vue from 'vue'
    const skeletonLoader = {
      name: 'skeletocnLoader',
      functional: true,
      props: {
        show: {
          type: Boolean,
          default: false
        }
      },
      render(h, context) {
        const { show } = context.props
        if (!show || window.__PRERENDER_INJECTED__) {
          const html = `<div>xxx</div>`
          const component = Vue.compile(html)
          return h(component)
        } else {
          return context.children[0]
        }
      }
    }
    export default skeletonLoader
    </script>
Enter fullscreen mode Exit fullscreen mode

5. Enter PRERENDER_SKELETON in the browser's console

    Enter `PRERENDER_SKELETON` in the Chrome console to start the skeleton screen preview
Enter fullscreen mode Exit fullscreen mode

Final effect

Performance

Finally, look at the abtest test, Killblanks brought about the changes in page performance data

Data Sources

Use the company's online activities in Indonesia to conduct abtest to obtain relevant data

Data

type total fcp lcp
@killblanks 1532 536ms 661ms
Normal 1730 990ms 993ms

First-contentful-paint(fcp)

  • FCP average comparison: 536: 990 @killblanks can increase 454ms, an average increase of 45%

Largest-contentful-paint(lcp)

  • LCP average comparison: 661: 993 @killblanks can increase 332ms, an average increase of 33.4%

Future

killblanks There are still many functions to be improved in the future, which is currently being done

  • unit test
  • Optimize documentation
  • Support react && angular
  • Complete demo

Welcome to the front-end friends to leave your own opinions in issue, If you have time, please killblanks Click ⭐.

Top comments (0)