You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
new Vue({
el: '#app',
router,
render: h => h(App),
mounted () {
// You'll need this for renderAfterDocumentEvent.
document.dispatchEvent(new Event('render-event'))
}
});
既然有了每个路由对应的 HTML,那么对应 SEO 优化应该不成问题了。我们可以更改 title 、meta 。而且页面的内容都已经在 HTML 中直接呈现,就不会有因为 js 等资源加载慢导致白屏的问题。 prerender-spa-plugin 的确在一定程度上解决了我们对于 SEO 的诉求和页面加载慢的问题。但是它的缺点还是很明显的。
不同的用户看到不同的页面,动态数据页面
经常发生变化的页面,数据实时性展示(比如体育比赛等)
路由过多,构建时间过长
正确使用的姿势
聊了这么多,大家都是为了给用户更好的体验。基本上我们做的页面都是强依赖动态数据展示,如果渲染的静态页面和最后呈现的页面之前切换并不自然,那么体验是很差的。我们不能为了解决 SEO 或者加载慢的问题,引入新的问题。那到底该怎么做呢?其实很简单:Loading 或者 骨架屏。这两个都是将过渡的 HTML 片段插入到 <div id="app"></div> 中。一旦js加载完,vue开始渲染正式页面时候,就将把过渡的 HTML 片段干掉了。看一下下面的代码
目前
Vue
、React
在前端界混的风生水起,它们的开发思想使得我们能真正做到前后端分离、解耦。单页面的使用给用户带来了更好体验。不过对于Vue
和 React 这种框架来说,HTML in JS
的思路在首屏加载慢、白屏以及SEO
等问题就日益突出了。不仅需要拼框架的功能、生态,当然还不能忘记“用户至上的原理“,拼体验。孜孜不倦的前端朋友们给出了几个解决方案:1.Server-side rendering(SSR),2.Prerendering。下面我将一一介绍一下。
什么是SSR?
SSR 直译就是服务端渲染,通过设置
SSR
,你就可以在后台的Node.js
环境中完成渲染逻辑,然后将HTML
视图直接返回给客户端。这样你不仅可以使用Vue
和React
技术,而且可以直出页面内容。而非只有一个空壳子在后端那里。这样也方便了搜索引擎的蜘蛛获取页面,解决SEO
问题。SSR有什么问题?
你可以回想一下我们在很早之前的前端开发模式,其实就是后端直出页面。前端重构页面,交由后端套页面渲染首页的数据。当然一些异步的数据,则通过
ajax
获取数据渲染。这似乎又回到了之前的开发模式。前端和后端还是紧密联系在一起了。给维护和迭代带来的不便。那它没有好处吗?有的!目前,社会上还是有成熟的框架和线上的产品,比如
Nuxt.js
[1], ,说明它还是具有价值的。它很明显可以解决首屏白屏或者SEO等问题。但是它也引入很多问题,其一,对工程师要求较高,需要同时掌握的前后端知识。其二,要考虑在服务端
Node.js
环境中的内存泄露、运行速度、并发压力等问题。node 层的服务可以用“脆弱”两个字来形容。其三,开发成本增加,研发周期变长等。一般来说,是需要一个强大且稳定的基础架构来支撑服务端的压力。如果你可以应付这些,无疑
SSR
对于增强应用体验是非常棒的~,但对于像我这样有点焦虑的人来说,是否有其他解决办法呢?有的,Prerendering
!Prerendering
有时候,我们开发的单页面应用也就几个页面,非常小型,仅仅是为了
SEO
、首页白屏问题,大家都觉得有点校枉过正了。可以利用第三方插件prerender-spa-plugin
[2],在客户端实现渲染,这样无需将Vue
或者React
代码部署在服务端。prerender-spa-plugin
是Webpack
的插件,它可以编译应用中的所有静态页面,轻而易举的建立对应的索引路径。下面结合Vue.js
和prerender-spa-plugin
来解决前面所提出的的问题。安装
使用
staticDir
指的是预渲染输出的页面地址,routes
指的是需要预渲染的路由地址,renderer
则是所采用的渲染引擎是什么,目前用的是V3.4.0
版本支持PuppeteerRenderer
。inject
则是预渲染过程中都能拿到的值,该值提供给你了机会,让你觉得是否渲染这部分代码。例如下面的代码,是不会被预渲染进HTML
中的。renderAfterDocumentEvent
这个则很关键,这个是监听document.dispatchEvent
事件,决定什么时候开始预渲染。实例
具体可以看一下官方的
Vue.js 2.0 + vue-router Prerender SPA Example
[3] 实例。原理及缺点
prerender-spa-plugin
利用了Puppeteer
[4] 的爬取页面的功能。Puppeteer
是一个Chrome
官方出品的headless Chrome node
库。它提供了一系列的 API, 可以在无 UI 的情况下调用Chrome
的功能, 适用于爬虫、自动化处理等各种场景。它很强大,所以很简单就能将运行时的HTML
打包到文件中。原理是在Webpack
构建阶段的最后,在本地启动一个Puppeteer
的服务,访问配置了预渲染的路由,然后将 puppeteer 中渲染的页面输出到HTML
文件中,并建立路由对应的目录。利用官方的实例进行编译结果如下:
每个对应的路都有一个对应的静态
HTML
。每一个HTML
内除了这个
Vue
的挂载元素外,还有静态的标签内容。既然有了每个路由对应的
HTML
,那么对应SEO
优化应该不成问题了。我们可以更改title
、meta
。而且页面的内容都已经在HTML
中直接呈现,就不会有因为js
等资源加载慢导致白屏的问题。prerender-spa-plugin
的确在一定程度上解决了我们对于SEO
的诉求和页面加载慢的问题。但是它的缺点还是很明显的。正确使用的姿势
聊了这么多,大家都是为了给用户更好的体验。基本上我们做的页面都是强依赖动态数据展示,如果渲染的静态页面和最后呈现的页面之前切换并不自然,那么体验是很差的。我们不能为了解决
SEO
或者加载慢的问题,引入新的问题。那到底该怎么做呢?其实很简单:Loading
或者 骨架屏。这两个都是将过渡的HTML
片段插入到<div id="app"></div>
中。一旦js加载完,vue开始渲染正式页面时候,就将把过渡的HTML
片段干掉了。看一下下面的代码Loading
或者骨架屏只是为了增强用户体验,那么跟本文的主体有什么关系呢?有关系,一般在做过渡效果的时候,很多都是手写代码,这样既不利于维护,也不利于统一标准。我们可以使用prerender-spa-plugin
进行操作,它能把整个页面都生成静态文件输出到HTML
,那么对于我们的Loading
组件或者页面首屏的DOM
和样式自动化的输出到HTML
中,不是轻而易举的事情吗?并且对于骨架屏来说,它只需要展示首屏的内容,所以我们可以利用插件的全局变量,进行判断,是否需要后续的抓取页面动作。这样也解决了骨架屏的体积大小问题。再则,
SEO
的问题对于目前开发的应用,很少有要求,基本都是入口页。但是用prerender-spa-plugin
也可以完美的解决,生成Loading
的多个路由页面或者骨架屏的多个路由页面,都可以由后端部署到vm
模板中,编写对应的title
和meta
,利用SEO
的优化。以上是自动化抓取页面生成骨架屏,但目前还是处于研究阶段,目前我们在生产项目中用的仍然是手写的骨架屏组件,可以参考这个
vue-skeleton-loading
[5] 组件。利用预渲染的插件将骨架屏Loading
组件或者标准的Loading
组件以DOM
形式输出到部署生产的HTML
页面中。总结
本文罗列了单页面体验的痛点:首屏加载慢、白屏的问题以
SEO
。也给出了渐进的解决方案利用预渲染prerender-spa-plugin
的输出Vue
或者React
公用组件(骨架屏组件和Loading
组件)到各个路由页面HTML
中。后续将依赖预渲染插件进行自动化骨架屏的输出方案,欢迎讨论和交流,敬请关注~扩展阅读
[1] Nuxt.js:https://nuxtjs.org/guide
[2] prerender-spa-plugin:https://github.com/chrisvfritz/prerender-spa-plugin
[3] vue2-webpack-router:https://github.com/chrisvfritz/prerender-spa-plugin/tree/dba55854a95a7a4e9b4aaf4203fb0563739bc58a/examples/vue2-webpack-router
[4] puppeteer: https://github.com/GoogleChrome/puppeteer
[5] vue-skeleton-loading:https://github.com/jiingwang/vue-skeleton-loading
The text was updated successfully, but these errors were encountered: