前言
自从前端三大框架react、vue、Angular面世以来,前端开发逐渐趋向规范化、统一化,大多数时候新建前端项目,首先想到使用的技术一定是三大框架之一,框架给前端开发带来了极大的便利和规范,但是由于这三大框架都是js驱动,在js没有解析加载完成之前页面无法展示,会处于长时间的白屏,带来了一定的用户体验问题,接下来本篇文章会介绍本人最近在白屏优化时遇到的一些问题和思考
SSR
想到白屏问题,首先想到的解决方案一般都是服务端渲染,在服务端将渲染逻辑处理好,然后将处理好的html直接返回给前端展示,这样就可以解决白屏的问题,也可以解决seo的问题,因为不需要动态获取数据了,但是,这和我早期的写后端时的开发模式很像,前端和后端关联在了一起,不利于维护,同时,对于前端工程师来说,要求变高来,需要了解一定的后端知识,虽然有类似Nuxt.js这类的SSR框架帮我们简化了服务端的部分,但是在要做定制或是解决bug时还是无法避免要对服务端部分进行调试、维护,成本颇高,还有需要考虑的服务端渲染会增加服务器压力,要处理并发、运行速度问题等等
预渲染
这个方案是相对简单直接的一个解决办法,尝试成本也比较低,这里介绍如何用prerender-spa-plugin做预渲染,这样就可以在浏览器进行渲染,而不需要将vue或者react代码部署到服务器上,以vue-cli3的官方demo为例做配置,看具体的配置文件:
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
module.exports = {
configurewebpack: config => {
let plugins = []
plugins.push(new PrerenderSPAPlugin({
staticDir: path.resolve(__dirname, 'dist'),
routes: ['/', '/about'],
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
keepClosingSlash: true,
sortAttributes: true
},
renderer: new Renderer({
renderAfterDocumentEvent: 'custom-render-trigger'
})
}))
config.plugins = [
...config.plugins,
...plugins
]
}
}
上面代码是常用prerender-spa-plugin的配置,staticDir预渲染输出的文件地址,routes要做预渲染的路由,minify压缩相关的配置,renderer渲染引擎相关的配置,可以传入自定以的渲染引擎或者直接使用默认的PuppeteerRenderer,renderAfterDocumentEvent是渲染引擎配置中的一个属性,指当某个事件触发时才执行预渲染,这很重要,尤其是对一些特定场景的下的需求,当然简单场景下完全可以不配置renderer渲染引擎选项,直接用默认选项。
接下来执行编译,看看会发生什么?
dist目录下会生成路由对应的文件夹,打开index.html
<div id="app">
<div id="nav">
<a href="/" class="router-link-exact-active router-link-active">Home</a> |
<a href="/about" class="">About</a>
</div>
<div class="home">
<img alt="Vue logo" src="/img/logo.82b9c7a5.png" />
<div class="hello" data-v-7b2de9b7="">
<h1 data-v-7b2de9b7="">Welcome to Your Vue.js App</h1>
<p data-v-7b2de9b7="">For a guide and recipes on how to configure / customize this project,<br data-v-7b2de9b7="" />check out the <a href="https://cli.vuejs.org" data-v-7b2de9b7="" rel="noopener" target="_blank">vue-cli documentation</a>.</p>
<h3 data-v-7b2de9b7="">Installed CLI Plugins</h3>
<ul data-v-7b2de9b7="">
<li data-v-7b2de9b7=""><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" data-v-7b2de9b7="" rel="noopener" target="_blank">babel</a></li>
<li data-v-7b2de9b7=""><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" data-v-7b2de9b7="" rel="noopener" target="_blank">eslint</a></li>
<li data-v-7b2de9b7=""><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-jest" data-v-7b2de9b7="" rel="noopener" target="_blank">unit-jest</a></li>
</ul>
<h3 data-v-7b2de9b7="">Essential Links</h3>
<ul data-v-7b2de9b7="">
<li data-v-7b2de9b7=""><a href="https://vuejs.org" data-v-7b2de9b7="" rel="noopener" target="_blank">Core Docs</a></li>
<li data-v-7b2de9b7=""><a href="https://forum.vuejs.org" data-v-7b2de9b7="" rel="noopener" target="_blank">Forum</a></li>
<li data-v-7b2de9b7=""><a href="https://chat.vuejs.org" data-v-7b2de9b7="" rel="noopener" target="_blank">Community Chat</a></li>
<li data-v-7b2de9b7=""><a href="https://twitter.com/vuejs" data-v-7b2de9b7="" rel="noopener" target="_blank">Twitter</a></li>
<li data-v-7b2de9b7=""><a href="https://news.vuejs.org" data-v-7b2de9b7="" rel="noopener" target="_blank">News</a></li>
</ul>
<h3 data-v-7b2de9b7="">Ecosystem</h3>
<ul data-v-7b2de9b7="">