Writing in the front

At present, front end development is the front end separation, the mainstream of the front end framework are SPA, MPA; This means that page rendering and waiting for white screen time are the problem points we need to solve; This is especially true for large projects.

Webpack can load on demand, reducing the volume of code we need to load on the first screen; With a CDN and some static code (framework, component library, etc…) Caching technology can be a good way to alleviate the problem of long loading rendering time.

Even so, the first screen still has this loading and rendering wait time problem;

What is a skeleton plate

At present, the mainstream and common solution is to use skeleton screen technology, including many native apps, in page rendering, will also use skeleton screen. (In the following figure, the part in the red circle is the skeleton filling of the page before the content appears on the skeleton screen, so as to avoid white space)

How to implement (Principle analysis)

In Vue, we mount the VM using the $mount instance method; Let’s take a quick look at the implementation of the $mount method in Vue code:

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
) :Component {
  el = el && query(el)

  /* istanbul ignore if */
  if (el === document.body || el === document.documentElement) { process.env.NODE_ENV ! = ='production' && warn(
      `Do not mount Vue to <html> or <body> - mount to normal elements instead.`
    )
    return this
  }

  const options = this.$options
  // resolve template/el and convert to render function
  if(! options.render) { ... }return mount.call(this, el, hydrating)
}
Copy the code

As you can see, this code first caches the $mount method on the prototype and then redefines it. Let’s examine this code first. First, it restricts EL. Vue cannot be mounted on root nodes such as body and HTML. Why?

Because the vNode generated by Render is mounted on our defined DOM element via the $mount method; Mount means replace.

By default our template index.html has a div element with the id app. Our final application code will replace this element, which is

; Yes, what we render in Vue is replacing it, not inserting it into the node.

This is why Vue cannot be mounted on root nodes such as body and HTML. You can’t replace element nodes like body and HTML.

If the render method is not defined, the EL or template string is converted to the render method. In Vue 2.0, all Vue components will eventually need the render method. Whether we develop the component in a single.vue file or write an EL or template attribute, this will eventually be converted to render. This procedure is an “online compilation” of Vue and is implemented by calling the compileToFunctions method. Finally, call the $mount method on the original prototype to mount it.

Reference: Vue instance mount implementation

A vivid example

The contents of our template (index.html) look like this:

<body>
  <div id="app">
    <span style="color: red; font-size: 34px;">hello</span>
  </div>
  <! -- built files will be auto injected -->
</body>
Copy the code

The mount point in the template is div#app, and the root node in app. vue is div#app-two. After rendering, div#app on the page becomes div#app-two.

So, here the most important point is: Vue $mount method mount elements, using [replace] template mount point such a method, know this knowledge, we want to achieve skeleton screen, there is a good implementation of the idea.

Implementation method (Concrete implementation)

Scheme 1, in the template to achieve the skeleton screen

In div#app in index. HTML, the skeleton screen will be replaced by the skeleton screen in div#app.

Scheme 2: Use a Base64 image as the skeleton screen

Use pictures as skeleton screens; Simple violence, let UI students spend some time it; The mobile page of Mi Mall adopts this method, which uses a Base64 picture as the skeleton screen.

As in plan 1, write the Base64 image in div#app in our index. HTML module.

Scheme 3. Use. Vue file to complete skeleton screen

We may not want code coding in the default template (index.html); On the basis of scheme 1, we want to extract the code of skeleton screen and use a. Vue file for coding, which is easy to maintain.

Create a skeleton directory under SRC and create two files in it (skeleton.vue, skeleton.entry.js). Vue is the code of our skeleton screen page. Skeleton.entry.js is the entry file to compile skeleton.vue, similar to the main.js file in our vue project.

// skeleton.entry.js
import Vue from 'vue'
import Skeleton from './skeleton.vue'

export default new Vue({
  // Root instance of a simple render application component
  render: h= > h(Skeleton)
})
Copy the code
<! -- skeleton.vue -->
<template>
  <div class="skeleton page">
    <span>Skeleton screen</span>
  </div>
</template>

<style scoped>
</style>
Copy the code

We also need to create a new webpack.skeleton.conf.js file for the skeleton screen build (it doesn’t matter where you put this file, either in the root directory or in the build directory). This is a webpack configuration file with vue-server-renderer to build our skeleton. Vue file contents into a single JSON file (this is the strategy for Vue SSR rendering)

// webpack.skeleton.conf.js
'use strict'
const path = require('path')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')

module.exports = {
  target: 'node'.devtool: '#source-map'.entry: './src/skeleton/skeleton.entry.js'.output: {
    path: path.resolve(__dirname, '.. /dist'),
    publicPath: '/dist/'.filename: '[name].js'.libraryTarget: 'commonjs2'
  },
  module: {
    noParse: /es6-promise\.js$/.// avoid webpack shimming process
    rules: [
      {
        test: /\.vue$/.loader: 'vue-loader'.options: {
          compilerOptions: {
            preserveWhitespace: false}}}, {test: /\.css$/.use: ['vue-style-loader'.'css-loader']]}},performance: {
    hints: false
  },
  externals: nodeExternals({
    // do not externalize CSS files in case we need to import it from a dep
    whitelist: /\.css$/
  }),
  plugins: [
    // This is a plug-in that builds the entire output of the server into a single JSON file.
    // The default file name is' vue-ssR-server-bundle. json '
    new VueSSRServerPlugin({
      filename: 'skeleton.json'}})]Copy the code

3. After writing skeleton.vue, run the webpack.skeleton.conf.js configuration file using webpack-cli.

// package.json
"skeleton": "webpack --progress --config build/webpack.skeleton.conf.js"
Copy the code

Then run:

NPM I [email protected] -d NPM run skeletonCopy the code

A skeleton.json file is generated in the dist folder.

4. Insert the skeleton. Json content into the template file index. HTML. (Create a skeleton.js file in the root directory)

// skeleton.js
const fs = require('fs')
const { resolve } = require('path')
const { createBundleRenderer } = require('vue-server-renderer')

function createRenderer(bundle, options) {
  return createBundleRenderer(bundle, Object.assign(options, {
    // recommended for performance
    // runInNewContext: false}}))const handleError = err= > {
  console.error(`error during render : ${req.url}`)
  console.error(err.stack)
}

const bundle = require('./dist/skeleton.json')
const templatePath = resolve('./index.html')
const template = fs.readFileSync(templatePath, 'utf-8')
const renderer = createRenderer(bundle, {
  template
})

// console.log(renderer)

/** * * The default index.html contains <%= BASE_URL %> interpolation syntax * we will not change the interpolation in the template during the skeleton screen generation step * because the interpolation will be completed at project build time * But if the interpolation syntax is in the template, When we use this template in vue-server-renderder, we will get an error if we do not pass values * so we remove the interpolation in the template and use this method to pass parameters, and then return the two interpolations to the template as they are:  https://cli.vuejs.org/zh/guide/html-and-static-assets.html#%E6%8F%92%E5%80%BC */
const context = {
  title: ' '.// default title
  meta: `
       
       
      `
}

renderer.renderToString(context, (err, html) => {
  if(err) {
    return handleError(err)
  }
  fs.writeFileSync(resolve(__dirname, './index.html'), html, 'utf-8')})Copy the code

Add a slot to div#app in index.html,
This is a must, vue SSR documentation says this. This note is required, please note!


      
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>vue-for-test</title>
  </head>
  <body>
    <div id="app">
      <! --vue-ssr-outlet-->
    </div>
    <! -- built files will be auto injected -->
  </body>
</html>
Copy the code

Reference link: ssr.vuejs.org/zh/guide/#%…

6, execute,

node skeleton.js
Copy the code

Upon successful execution, the contents of div#app in the template index.html will become our skeleton screen code;

7. Look at the effect

There are also examples where you can see the effect online: map-chart; Remember to select Browser -> Network -> Slow 3G mode to preview the skeleton screen.

In plan three, it also involves the content of Vue SSR. For the study of SSR knowledge, you can refer to a tutorial I wrote before: github.com/Neveryu/vue…

Scheme four, automatic generation and automatic insertion of static skeleton screen

Ele. me’s open source plug-in page-skeleton-webpack-plugin, which generates corresponding skeleton screen pages according to different routing pages in the project, and packs skeleton screen pages into corresponding static routing pages through Webpack. However, it should be noted that this plug-in currently only supports the route in history mode, not hash mode, and currently only supports the skeleton screen of the home page, there is no component-level local skeleton screen implementation, the author said that there will be a plan to implement (ISSUe9) in the future.

In addition, there is a plug-in vue-skeleton-webpack-plugin, which changes the way of inserting skeleton screen from manual to automatic. The principle is to use the vUE pre-rendering function during construction to insert the rendering result HTML fragment of skeleton screen component into the mount point of HTML page template. Inline styles into the head tag. This plugin can set different skeleton screens for different routes on a single page, or for multiple pages. At the same time, for debugging convenience, skeleton screens will be written to the router, which is quite nice.


Write in the last

My home page: neveryu. Making. IO/index. HTML

QQ group: 685486827

Copy the code