随着react、vue、angular等前端框架的流行愈来愈多的web应用变成了单页应用,它们的特色是异步拉取数据在浏览器中渲染出HTML。使用这些框架极大的提高web用户体验和开发效率的同时缺带来一个新问题,那就是这样的网页没法被搜索引擎收录。虽然这些web框架支持服务端渲染,但这可能又会增长开发成本。html
有没有一个可用于任何单页应用的SEO解决方案,让咱们不用对代码作改变保持原有的开发效率?chrome-render能够帮咱们作到这点,它经过控制HeadlessChrome渲染出最终的HTML返回给爬虫来实现。前端
前不久chrome团队宣布chrome支持headless模式,HeadlessChrome支持chrome所具备的全部功能只不过由于不显示界面而更快资源占用更小。相比于以前的phantomjs(做者由于HeadlessChrome的推出而宣布中止维护)chrome的优点在于它又一个很强的爹(google)会一直维护它优化它,而且chrome在用户量、体验、速度、稳定性都是第一的,因此我认为HeadlessChrome会渐渐替代以前全部的HeadlessBrowser方案。vue
既然HeadlessChrome是以无界面模式运行的,那要怎么控制它和它交互?
chrome提供了远程控制接口,目前能够经过chrome-remote-interface来用js代码向chrome发送命令进行交互。在启动chrome的时候要开启远程控制接口,而后经过 chrome-remote-interface 链接到chrome后再经过协议控制chrome。具体操做见文档:react
chrome-render先会经过chrome-runner以headless模式启动和守护你操做上的chrome,再经过chrome-remote-interface操控chrome去访问须要被SEO的网页让chrome运行这个网页,等到包含数据的HTML被渲染出来时读取当前网页DOM转换成字符串后返回。chrome
怎么知道你的网页何时已经渲染出包含数据的HTML了能够返回了呢?为了提高chrome-render效率,默认会在domContentEventFired
时返回。对于复杂的场景还能够经过开启chrome-render的useReady
选项,等到网页里调用了window.chromeRenderReady()
时返回。api
只渲染出了HTML还不够咱们还须要检测出来着搜索引擎爬虫的访问,若是请求来着爬虫就返回chrome-render渲染后的HTML不然返回正常的单页应用所需HTML。浏览器
综上,总体架构以下:
只需如下几行简单代码就可以让chrome渲染出HTML:
const ChromeRender = require('chrome-render'); ChromeRender.new().then(async(chromeRender)=>{ const htmlString = await chromeRender.render({ url: 'http://qq.com', }); });
chrome-render只是作了渲染出HTML的工做,要实现SEO还须要和web服务器集成。为了方便你们使用我作了一个koa中间件koa-seo,要集成到你现有的项目很简单,以下:
const seoMiddleware = require('koa-seo'); const app = new Koa(); app.use(seoMiddleware());
只需像这样接入一个中间件你的单页应用就被SEO了。
chrome-render除了用于通用SEO解决方案其实能够用于通用服务端渲染,由于目的都是渲染出最终的HTML再返回。针对通用服务端渲染我也作了一个koa中间件koa-chrome-render。使用chrome-render作服务端渲染的
优点在于:
通用,适用于全部单页应用
对原有代码几乎无改动,最多再合适的地方加个window.chromeRenderReady()
,保持原有开发效率
缺点在于:
和react、vue等只带的服务端渲染相比性能低(经我测试大约 200ms vs 60ms)
chrome-render渲染时占用资源高,一次渲染大约占用25Mb内存,当请求量大时服务器可能扛不住。可是能够经过缓存渲染结果优化。
你们可能会说这个很像prerender.io,没错思路是同样的,chrome-render的优点在于:
chrome-render开源可本身部署,prerender要收费是商业产品
prerender基于已经中止维护的phantomjs
本文中所提到的相关项目都是开源的而且有详细的使用文档,它们的文档连接以下:
喜欢的给个star,但愿你们和我一块儿来改进它们让它们更强大。