在目前的前端领域,单页web
应用(SPA)已经有了比较高的占有率,比较主流的web
框架React
、Angular
、Vue
几乎已经统治了前端市场。html
单页应用确实带来了更好的先后端分离,以及用户体验好、快,内容的改变不须要从新加载整个页面等等的优势,喜忧参半,SPA
应用首屏加载慢、白屏以及 SEO
等问题也就慢慢显露出来。前端
问题的来源是SPA
应用采用的是客户端渲染,DOM
节点要等待JS
文件加载完毕后才会生成,因此就浮现了以上几个问题。vue
为了解决以上问题,目前有两个比较主流的解决方案:webpack
SSR
)Prerender
)当服务器接收到请求后,它把须要的组件渲染成 HTML 字符串,而后把它返回给客户端(这里统指浏览器)。以后,客户端会接手渲染控制权。git
优点:github
SEO
,因为搜索引擎爬虫抓取工具能够直接查看彻底渲染的页面。time-to-content
),特别是对于缓慢的网络状况或运行缓慢的设备。问题:web
目前已经有了比较成熟的服务端渲染应用框架,React有Next.js,Vue有Nuxt.js(文档十分详细,社区也挺丰富👍),它们都是由zeit.co 背后的团队发布的,固然你也能够本身构建一套服务端渲染。chrome
无需使用web
服务器实时动态编译 HTML
,而是使用预渲染方式,在构建时 (build time
) 简单地生成针对特定路由的静态HTML
文件。npm
若是项目中使用 webpack
,你可使用 prerender-spa-plugin 轻松地添加预渲染,后面将会具体实现。后端
在对你的应用程序使用服务器端渲染 (SSR
) 以前,你应该问的第一个问题是,是否真的须要它。这主要取决于内容到达时间 (time-to-content
) 对应用程序的重要程度。若是并不过重要,这种状况下去使用服务器端渲染 (SSR
) 将是一个小题大做之举。
若是假设你须要更好SEO
和内容到达时间 (time-to-content
) ,若是你使用服务器端渲染 (SSR
) 只是用来改善少数页面,那么这个时候你可能更须要预渲染,优势是设置预渲染更简单,你能够得到SSR
的几乎全部优势,无需更改代码或添加服务器端就能轻松实现的解决方案。
用prerender-spa-plugin能够给现有项目加入预渲染,咱们就以Vue
为实例进行预渲染优化。
先用Vue
官方提供的脚手架3.0搭建一个简单的Vue
项目,步骤就不写了,具体实现能够参照官方文档。
prerender-spa-plugin
依赖yarn add prerender-spa-plugin --dev
复制代码
由于这个组件须要依赖Puppeteer,它是是 Google Chrome 团队官方的无界面(Headless)Chrome 工具,它是一个 Node
库,提供了一个高级的 API 来控制 DevTools协议上的无头版 Chrome 。也能够配置为使用完整(非无头)的 Chrome。
鉴于 Puppeteer
须要 Chromium
,可是即使你的上网姿式足够科学,也一样会遇到安装失败的问题,尝试了不少解决方案,提供一个成功率较高的解决方案。
在你的项目根目录建立一个.npmrc
的文件,固然你也能够直接修改你本机的.npmrc
配置。
// .npmrc
puppeteer_download_host = https://npm.taobao.org/mirrors
复制代码
而后再尝试安装。
vue.config.js
// vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
publicPath: './',
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: resolve('dist'),
routes: ['/', '/about'], // 你须要预渲染的路由
renderer: new Renderer({
inject: {
_m: 'prerender'
},
// 渲染时显示浏览器窗口,调试时有用
headless: true,
// 等待触发目标时间后,开始预渲染
renderAfterDocumentEvent: 'render-event'
})
})
]
}
}
}
}
复制代码
更多详细的配置能够查看prerender-spa-plugin
官方文档,根据需求添加。
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
mounted () {
// 触发renderAfterDocumentEvent
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')
复制代码
yarn run build
复制代码
没有使用预渲染打包获得的dist
文件夹目录:
使用预渲染后打包获得的dist
文件夹目录:
能够看到多了一个about
目录,里面有一个html
文件。咱们查看一下根目录的html
文件,也就是首页的html
文件。
没有使用预渲染获得根目录html文件
:
使用预渲染获得根目录html文件
:
我把它们都部署到gh-pages
上,咱们来看一下差异。
没有使用预渲染请求到的Document
:
使用预渲染请求到的Document
:
能够看到使用预渲染时初始化的HTML
文件已经有了DOM
结构,这样爬虫就能够来抓取到DOM
结构,SEO
优化更好。
录了两个GIF
点击刷新体验下差异,提早在调试工具钩上Disable cache
,每次刷新都不会使用缓存,从新向服务器发起请求。没有使用预渲染:
使用预渲染:
能够看到使用预渲染以后首屏几乎没有白屏。
能够点击下面连接亲自体验一下,Demo地址:
这是我使用时感受比较遗憾的地方,并不必定全面。
我的理解,插件的实现原理是在打包完成以后, 利用了 Puppeteer
的爬取页面的功能,模拟浏览器访问路由,而后把JS
生成的DOM
结构以HTML
静态文件的形式再保存下来。
确实是渐进式的解决了SPA
应用潜在的一些问题,而且比较容易的就能集成到现有的项目,但也有遗憾的地方。
本文只是作了一个简单的Demo
,更多的使用技巧还须要你亲手去探索。
文中若是有问题和遗漏,欢迎在评论区指出,若是本文能给帮助到你,请给个点赞
👍和关注
。
也能够点击我另外的文章:
本文到此结束,886🚀🚀