现代js框架做SEO,你选择SSR还是preRender?

1,805 阅读6分钟

闲来无事水文章系列

注:此文章只是想简单阐述一下SSR和preRender各自做SEO的处理思路。选择一个东西还是要根据当前业务、时间成本、技术的熟悉程度来进行选择

前言

前些日子,在处理低代码的同时接手了一个要做SEO的官网。官网的技术栈是我用vue搭起来的,众所周知对于现代的js框架来说,要做SEO首先要处理的就是要让蜘蛛可以爬到你页面上的所有内容。

怎么处理呢?

比较传统的两个方案

  • 做SSR
  • 做预渲染

因为我也是第一次接触这种东西,又赶上我亲爱的老大跑路了,所以我开始自己瞎鼓捣。总的来说就是爬了一堆坑,所以上面这两种主流方案我也都试了一个遍。

首先来说一下比较火的SSR,SSR其实是比较简单的,因为无论是React还是Vue都有一个对应next或者nuxt做对应(当然还有一个开源的egg做的也蛮强的)。

简单说一下它的基本原理:拿一个spa的React举例,就是要想办法将app这个根组件在服务器端就转成html串传给浏览器(比如可以借助react-dom/server下面的renderToString方法)。当然服务端绑定不了事件,还有同时维护一个客户端的代码。再处理客户端服务端store数据不一致问题(脱水注水)。

虽然细看好像东西很多,但是说来说去主要就是想把html在服务器生成好了再返回去,且SSR的轮子也很成熟。有轮子嘛,用就完事了。但是好像预渲染就没有那么出名了。所为这篇文章我们来玩一玩预渲染。

预渲染原理

1. 使用预渲染服务器(爬虫的应用)

首先项目没做处理时

不做任何处理的时候项目基本流程是这样的(如下图)。客户端访问index.html,服务器返回。

1621850107478.png

没有做处理的时候肯定获取的html是这样的

1621850316698.png

这时候,浏览器肯定先得解析js。才能把对应的dom挂到id为root的div上,浏览器完成渲染,页面显示

但是蜘蛛不会看js执行完后的结果,它看到的东西就是上图中啥信息都没有的骨架。

给他加一个预渲染服务器

此时的架构变成了这个样子(ps:实际上判断是否是蜘蛛直接用react所在的服务器就可以了,这里只是看的清晰一点)

1621851047068.png

如果普通用户访问,那没有必要处理。如果是蜘蛛访问,那就要走一下预渲染服务器了

这个预渲染中主要干了点什么东西呢?

主要它模拟了一下这样的操作

1621851412651.png

就类似于这种操作:当我们F12时,元素面板里面的东西已经是chunkjs执行完毕之后的了。所以是不是可以把这里的html copy一份返给蜘蛛呢?

看到这里,不知道小伙伴是不是有点对这个预渲染服务器的工作有些好奇,不晓得它是怎么做到的。

但是遗憾的是,小白当初对它也基本没有花费精力。所以我也没有具体去看看它实现思路,不过小白在这里提供一下我自己的一个思路

按上面的模拟操作,看起来我们可以采用爬虫的思路。这里我简单的用Puppeteer ,按上面的架构简单实现一下

步骤一:首先可以用cra新启一个react项目

1621910267171.png

此时页面当然是客户端渲染的,源码上看不到任何主要内容(如Learn React)

1621910294455.png

步骤二:搭建我们的预渲染服务器(当然是用前端最熟悉的node了)

可以看到这里新开了一个pup_server

1621910498165.png

因为只是简单模仿,那么我们就可以这么干。开一个浏览器,再开一个页面打开上面那个react项目(假设端口在3000)。然后爬取它的代码copy一份

核心代码如下


const puppeteer = require('puppeteer')
const fs = require('fs')

const start = async () => {
    const browser = await puppeteer.launch({
        headless: false,
    })
    const page = await browser.newPage();
    await page.goto('http://localhost:3000/', { timeout: 20000 });
    const html = await page.content()
    fs.writeFileSync('index.html', html)
}

start()

打开一下copy来的html,可以看到这份已经有了内容。

1621910818997.png

预览这份文件好像有点问题,但是它只是给蜘蛛的,view效果我们又不cure

1621910775539.png

有兴趣的小伙伴可以也看一下这个Prerender

2. 再来说一下使用prerender-spa-plugin

说实话,上面的架构有一点复杂。这里webpack提供了一个插件prerender-spa-plugin。其实原理还是那个原理。

首先使用这个东西处理一般的SPA项目,它要求你的路由模式得是history。因为它要按照路由进行打包。什么意思呢?

来看一下打出的目录结构你就明白了

1621911192862.png

简单介绍一下,我的这个项目有四个路由,分别是about index intro study

原本的正常打出来的包是不会有这四个文件夹的,这里多出来的这四个文件夹是什么东西呢?有了上面的基础我们很快就能想到了。这就是在本来SPA包构建完成之后他又搞了个模拟浏览器,打开对应路由的页面拿到其中的源码copy出来,又依次在放到以各个路由命名的文件夹下

1621911652143.png

可以看到这些文件夹下,都是copy过来的html。这个东西就是要给蜘蛛的。从用户的角度其实是没有变化的,还是从根的index.html开始。和以往的流程是一样的。只是为了seo专门处理了一些需要给蜘蛛的东西

SSR和preRender到底是有什么不同呢?

从思想上看:

先说现代框架要做SEO的主要矛盾是什么呢?

答:就因为现在框架的主要内容区域的dom(<div id='root'></div>)。它就是需要浏览器执行js去创建去挂载,可是蜘蛛就是拿不到这些内容。

针对这个问题

SSR想的是:好你拿不到是吧,那我就在服务器端把html都整好了发给你。

preRender想的是:客户端有两种角色,1是普通用户2是蜘蛛。只是你蜘蛛拿不到是吧,那我就想方法给你蜘蛛想要的,用户那块逻辑我不动。

要用哪个呢,处理看当前业务,也要看他们分别有什么不足是吧?

比如:SPA项目的通病就是首屏慢,这个时候你用SSR不仅处理了SEO还处理了首屏问题

但是,你boss突然给你了一个你对他业务完全不熟悉的项目让你做SEO,给你一两天时间。你总不能直接就把它拿过来开始往next或者nuxt上迁移吧(我惊了)

好了今天先去吃饭了,这篇先简单说下思想。后面有机会再好好整理一篇出来...