Skeleton screen injection practice 1: vue-skeleton-webpack-plugin

The skeleton screen shows the general structure of the page to the user before the page data is loaded, and then renders the page after the request data is returned to supplement the data content that needs to be displayed.

Skeleton screens are a way to enhance the user experience in pre-rendering.

There are a lot of technical solutions to generate skeleton screen, probably:

  • 1. Write skeleton screen code manually

  • 2. Generate a skeleton screen by pre-rendering hand-written code, e.g. Vue-skeleton-webpack-plugin

  • 3, Ele. me internal skeleton page generation tool: page-skeleton-webpack-plugin

  • 4. The DOM manipulation method of JavaScript is combined with Puppeteer to automatically generate the web skeleton screen

  • The other… .

This article mainly introduces one of them: vue-skeleton-webpack-plugin

(a) specific operation of single page skeleton screen

1. Install vue-skeleton-webpack-plugin in the project

npm i vue-skeleton-webpack-plugin -D
Copy the code

Create an entry file that uses only skeleton screen components:

/src/components/Skeleton/entry-skeleton.js

import Vue from 'vue';
import Skeleton from './Skeleton';

export default new Vue({
    components: {
        Skeleton
    },
    template: '<Skeleton />'
});
Copy the code

/src/components/Skeleton/Skeleton.vue

<template>
    <div class="skeleton-wrapper">
        <header class="skeleton-header"></header>
        <section class="skeleton-block">
            <img src="data:image/svg+xml; base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2a WV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiI GhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291c mNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgM CAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsb D0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIge Gxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIM jMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2R jZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNO TE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==">
            <img src="data:image/svg+xml; base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2a WV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiI GhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291c mNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgM CAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsb D0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIge Gxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIM jMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2R jZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNO TE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg==">
        </section>
    </div>
</template>

<script>
export default {
    name: 'skeleton'
};
</script>

<style scoped>
.skeleton-header {
    height: 152px;
    background: grey;
    margin-top: 60px;
    width: 152px;
    margin: 60px auto;
}
.skeleton-block {
    display: flex;
    flex-direction: column;
    padding-top: 8px;
}
</style>
Copy the code

3, create a webpack configuration for the server rendering object, will be the entrance to the newly created file specified as entry depends on entry: build/webpack skeleton. Conf. Js

const path = require('path')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const nodeExternals = require('webpack-node-externals')

function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = merge(baseWebpackConfig, {
  target: 'node'.// Distinguish between default 'web'
  devtool: false.entry: {
    app: resolve('.. /src/components/Skeleton/entry-skeleton.js')  // multiple pages of incoming objects
  },
  output: Object.assign({}, baseWebpackConfig.output, {
    libraryTarget: 'commonjs2'
  }),
  externals: nodeExternals({
    whitelist: /\.css$/
  }),
  plugins: []})Copy the code

4, create a webpack configuration for the server rendering object, will be the entrance to the newly created file specified as entry depends on entry: build/webpack. Dev. Conf., js and build/webpack. Prod. Conf., js

. .const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')

module.exports = merge(baseWebpackConfig, { ... .plugins: [...// inject skeleton content(DOM & CSS) into HTML
        new SkeletonWebpackPlugin({
            webpackConfig: require('./webpack.skeleton.conf'),
            quiet: true})]})Copy the code

NPM run dev: NPM run dev:

 throw new Error(^Error:

Vue packages version mismatch:

- vue@2.516.
- vue-server-renderer@2.612.

This may cause things to work incorrectly. Make sure to use the same version for both.
Copy the code

Cause: The vUE version is inconsistent with the vue-server-renderer version. Therefore, the vUE and vue-server-Renderer must be installed in the same version.

Note:

The vUE version of the original project was [email protected], but for unification, [email protected] and [email protected][email protected] were tried, which were invalid. Upgraded to [email protected] + [email protected]

npm i vue@2.516. vue-server-renderer@2.516. -D
Copy the code

NPM run dev again is ok

(2) Detailed operation of multi-page skeleton screen

1. Create a new oneSkeleton2.vueFile:

/src/components/Skeleton2.vue

Comments:

If multiple pages are different, it is necessary to write different skeleton screen corresponding to the page (CSS style prepared pages), so as to match one by one, so it is necessary to write the corresponding page skeleton screen style or UI design (pages using pictures or base64);

In a word: although this interaction is good, but the workload is relatively large, if the later stage of the page changes greatly, the whole skeleton screen needs to be changed.

<template>
    <div class="skeleton-wrapper">Skeleton For Home</div>
</template>

<script>

export default {
    name: 'skeleton2'
};
</script>

<style scoped>

.skeleton-header {
    height: 152px;
    background: grey;
    margin-top: 60px;
    width: 152px;
    margin: 60px auto;
}

.skeleton-block {
    display: flex;
    flex-direction: column;
    padding-top: 8px;
}
</style>
Copy the code

2. Modify the import fileentry-skeleton.js

import Vue from 'vue';
import Skeleton from './Skeleton';
import Skeleton2 from './Skeleton2'; / / new

export default new Vue({
    components: {
        Skeleton,
        Skeleton2 / / new
    },
    // Note: id="skeleton" or id="skeleton2" is the key that controls whether the skeleton is displayed
    template: ` 
      
`
}); Copy the code

3, modify,build/webpack.dev.conf.jsandbuild/webpack.prod.conf.js

Comments: the build/webpack. Prod. Conf. Js must configure, because when packed online need to inject.

. .const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')... .plugins: [
        // inject skeleton content(DOM & CSS) into HTML
        new SkeletonWebpackPlugin({
            webpackConfig: require('./webpack.skeleton.conf'),
            quiet: true.minimize: true.// Select whether to compress and inject HTML JS code under SPA
            router: {
                mode: 'hash'.routes: [{// Insert skeleton screen route 1
                        path: /\/comboHelper/.// Regex is used for routing. If a page needs to be added to the skeleton screen, write the corresponding page route
                        skeletonId: 'skeleton' // This is the HTML that corresponds to whether to display the id of template in the entry file entry-skeleton.js
                    },
                    { // Insert skeleton screen route 1
                        path: /\/commercialActivity\? /,
                        skeletonId: 'skeleton'
                    },
                    {
                        path: '/'.skeletonId: 'skeleton2',},]}}),]Copy the code

Matters needing attention:

Failed to match current routing path when using multiple skeletons?

The path option to match each Skeleton can be a string or a re. If you want to match /page1? For key=value, you can write the regular path: /^/page1/.

In practice, if this project is a route with dynamic parameters, the route is written as:

path: '/play/:type/:id'.// If a route is a dynamic parameter, the configuration must be the same as that of the router
Copy the code

Invalid, change to regular is OK

path: /\/commercialActivity\? /.Copy the code

conclusion

  • Hand-written HTML, CSS for the target page to customize the skeleton screen

  • The skeleton screen can be thought of as a blank version of the page before the data is loaded in, a simple key render path

  • The main idea is to use vue-server-renderer, a plugin originally used for server-side rendering, to process the.vue file we wrote into HTML and insert it into the mount point of the page template to complete the skeleton screen injection. Cons: This is not very civilized, and if the page style changes, you have to change the skeleton screen again, which increases maintenance costs.

  • Use pictures as skeleton screen: simple violence, let UI students spend more effort; The mobile page of Mi Mall adopts this method, which uses a Base64 picture as the skeleton screen.

  • Interaction problem: When the DOM node data is loaded back, there will be a blank screen transition between the skeleton screen and the real page. When the network speed is slow, this blank screen phenomenon will be obvious! (First screen skeleton -> then mount vue white screen straight -> page)