1. 程式人生 > >vue預渲染之prerender-spa-plugin解析(一)

vue預渲染之prerender-spa-plugin解析(一)

前言:這幾天一直看怎麼樣優化頁面載入速度,一個頁面的載入等待時間很長的話,確實很不友好,反正如果是app的話,我會直接解除安裝的,所以各個廠商為了能讓使用者儘快的看到頁面內容做了一系列的操作(預渲染、ssr、同構等等),我們今天來看一下預渲染.

什麼是預渲染?
為什麼需要用預載入呢?
以一個vue的spa(單頁面)應用為例,我們用打包工具打包完畢後,我們的頁面大概是這樣的:

在這裡插入圖片描述
然後我們執行下頁面後:
在這裡插入圖片描述

我們載入頁面的時候,瀏覽器的渲染包含:html的解析、dom樹的構建、cssom構建、javascript解析、佈局、繪製,以上面例子看來,當解析到javascript的時候才回去觸發vue的渲染,然後元素掛載到id為app的div上,這個時候我們才能看到我們頁面的內容,所以即使vue渲染機制很快我們仍然能夠看到一段時間的白屏情況,我們當然希望是載入頁面的時候就可以看到內容了,而無需等待長時間的渲染,為了解決spa應用出現的白屏情況,我們需要在載入js之前做一下頁面的預渲染,這樣使用者就能儘可能快的看到頁面內容.

github上已經有一些預渲染框架了,原理都差不多,我這裡就以prerender-spa-plugin為例了,我們來一步一步解析一下.

先看一下官網的解釋:

This is the stable 3.x version of prerender-spa-plugin based on puppeteer. If you’re looking for the (now-deprecated) 2.x version, based on PhantomJS, take a look at the v2 branch.

The goal of this plugin is to provide a simple prerendering solution that is easily extensible and usable for any site or single-page-app built with webpack.

Plugins for other task runners and build systems are planned.

簡單翻譯一下:“框架是3.0以上是基於puppeteer,2.0是基於PhantomJS為了解決單頁面應用的預渲染問題”

簡單的畫了一下prerender-spa-plugin外掛的工作流程圖:

在這裡插入圖片描述

因為外掛的程式碼也不是很多,我們就不根據官網提示安裝了,我們直接擼它的程式碼,我們拖一部分原始碼到工程中:
在這裡插入圖片描述

小夥伴自己去github上拖程式碼哈,我就不貼了~

然後我們需要安裝幾個依賴庫:
promise-limit(工具庫)
puppeteer(操縱木偶的人)
兩個庫的具體用法我就不介紹了哈,我們直接在專案中執行:

npm install promise-limit --save
npm install puppeteer --save

在安裝puppeteer的時候如果遇到問題了可以用yarn命令:

yarn add puppeteer --save

然後去我們找到我們的webpack.prod.conf.js檔案:

'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const env = require('../config/prod.env')
const PrerenderSPAPlugin = require('../prerender')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
  ....
webpackConfig.plugins.push(new PrerenderSPAPlugin({
  staticDir: path.join(config.build.assetsRoot),
  routes: ['/index.html'],
  renderer: new Renderer({
    headless: false,
    renderAfterDocumentEvent: 'render-event'
  })
}))
module.exports = webpackConfig

我們添加了一個PrerenderSPAPlugin外掛

然後我們在我們的page-a.vue的mounted中告訴預載入框架載入結束:

page-a.vue:

<template>
  <div id="page-a-container">
    我是a頁面<br>
    <button @click="onClick">登入</button>
  </div>
</template>
<script>
  export default {
    name: 'pageA',
    mounted() {
      console.log(this.$store.state.route)
      document.dispatchEvent(new Event('render-event'))
    },
    methods: {
      onClick() {
        this.$store.dispatch('login')
      }
    }
  }
</script>
<style scoped>
  #page-a-container {
    background-color: red;
    color: white;
    font-size: 24px;
    height: 100%;
  }
</style>

document.dispatchEvent(new Event('render-event'))

然後我們執行:

npm run build

在這裡插入圖片描述

我們開啟我們的index.html檔案看一下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>vuexdemo</title>
  <link href="./static/css/app.4024098bac65ecfd7b57ced4b9a7ca18.css" rel="stylesheet">
</head>
<body>
<div id="app">
  <div data-v-5e9a6bbe="" id="page-a-container" class="router-view">
    我是a頁面<br data-v-5e9a6bbe="">
    <button data-v-5e9a6bbe="">登入</button>
  </div>
</div>
<script type="text/javascript" src="./static/js/manifest.3ad1d5771e9b13dbdad2.js"></script>
<script type="text/javascript" src="./static/js/vendor.0455d420b608053dd0d0.js"></script>
<script type="text/javascript" src="./static/js/app.ea2bad6fa5b2bf0b1ce4.js"></script>
</body>
</html>

可以看到,已經是我們渲染完畢後的頁面了~ 到此prerender-spa-plugin的整合算是結束了

這節先到這裡了,下一節我們照著老套路從頭到尾的擼一遍原始碼.
先到這裡啦,歡迎志同道合的小夥伴入群,一起交流一起學習~~ 加油騷年!!
qq群連結:
在這裡插入圖片描述