# 单页面SEO优化方案
本文主要讲服务端渲染原理和SEO优化方案。
# SEO优化
SEO优化就是搜索引擎优化,主要目的就是提高网站的搜索排名,让爬虫更快的找到自己的网站。在很久以前,还使用HTML+CSS+JS和JQuery写页面的时候,网站SEO主要是针对这些原生方式去处理,你比如常见的优化方式有通过meta标签添加title、description、keywords内容,使用语义化标签,优化加载速度等,让爬虫更快去爬取,这些都是以前狭义的SEO优化,后面随着三大框架单页面应用的流行与使用,SEO优化不在单单通过这些就可以实现,还要结合网页内容,让内容更容易搜索到,就像是博客网站如何让你的博客更快被搜到,新闻如何快速被找到等等。SEO也不在指从前端单一层面去优化,而是面向C端,从整个网站整体被搜索优化。
# 浏览器渲染方式
随着前端三大框架的出现,让很多新生代前端忘记了浏览器是如何渲染的,如何工作的,缺乏一些基础的常识,只知道写页面画页面,写好打包扔给后端去部署就完了。作为一个前端,要知道web服务器如何运行,如何部署,网站被访问整个流程是什么才行,下面就来讲解一下浏览器渲染的流程和方式。
# 网站构建流程
我们打开一个网站访问时,不论是请求接口,还是HTML、CSS、JS,或者是其他媒体资源,它们在服务器看来,都只是一个请求,服务器会根据不同的请求返回不同的数据,然后浏览器拿到这些请求数据进行组合好给渲染出来。
这个网站是如何被访问的呢?首先我们要部署一个服务,就像你用Vue启一个服务一样,它可以被本机访问,网站部署也是同样道理,把它部署在远程服务器上就可以让互联网访问,当然这还要涉及一些服务器方面的知识。web服务它需要处理的功能复杂一点,它要处理各种请求,根据不同的请求访问服务器资源返回数据,响应各种资源文件。而像更复杂数据处理,我们可以交给后端服务去跑。
前端服务部署好后,返回给浏览器数据进行渲染,这个时候由于前端发展的历史也渐渐衍生出两种渲染方式,就是客户端渲染和服务端渲染,它俩最大的区别就是如何组装HTML进行返回浏览器渲染。
# 客户端渲染
客户端渲染就是前端Vue和React框架,通过JS动态的组装页面+Ajax填充页面,服务器刚开始响应的HTML只是一个基础的空壳子,前端根据不同的路由加载不同的组件动态更改DOM,并通过接口获取数据进行填充页面内容,所有的页面渲染都是前端进行组装完成的,后端只提供数据接口就可以了。
优缺点:
客户端渲染使用Vue、React框架实现起来会很简单,部署简单,服务器压力小。但因为所有操作都在一个HTML页面进行动态渲染的,爬虫第一时间是爬不到页面内容不利于SEO,并且第一次加载渲染白屏等待时间长,。
# 服务端渲染
在还没有前端分离的时候,浏览器请求页面URL,服务器收到请求后拿到数据,把数据丢到组件模板,像php/jsp/asp,组装成完整HTML返回给浏览器,浏览器拿到是整个HTML页面直接进行渲染,这一整套东西全靠后端进行处理,不仅写起来麻烦还难以维护。
在前后端分离的背景下,为了解决单页面不利用SEO的问题,就提出了服务端渲染概念。前端自己启一个web服务,在前端服务中根据不同的路由请求,把数据和HTML组装好一起返回给浏览器,浏览器直接加载的就是完整的HTML,不需要JS去动态渲染,JS只处理一些交互效果就可以了。
优缺点:
服务端渲染利于SEO,白屏等待时间少,但是实现复杂,需要自己构建一套Node服务,部署的话服务需要Node.js server 运行环境,渲染都在服务端进行处理,服务器压力比较大。
# 实现方案
对于单页面的SEO优化,想要爬虫爬到就必须保证网页他有内容,要保证网页有内容一般有下面几种方法。
# 1、预渲染
预渲染方式就是在打包时,提前在构建过程中生成特定路由页面的静态 HTML 文件,然后在加载时直接进行渲染,而不是再通过JS动态生成。它一般只适用于简单的官网或门户网站,比如你用Vue写了一个官网,想让首页和关于我们等页面的内容让用户搜索到,里面基本上都是纯静态页面,我们就可以使用预渲染方式来优化。
我们可以借助插件prerender-spa-plugin-next (opens new window)来实现预渲染,下面是使用该插件实现预渲染的基本步骤。
安装插件
npm i -D prerender-spa-plugin-next
添加预渲染配置,在项目根目录下的 vue.config.js中,添加以下配置:
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin-next')
module.exports = {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'), // 编译生成的静态文件目录
routes: ['/', '/about', '/contact'] // 需要预渲染的路由列表
})
]
}
# 2、SSR服务端渲染
SSR服务端渲染需要前端自己搭一个Node服务,需要前端自己构建一整套web服务,自己处理请求,把渲染数据拼好放到HTML中进行返回,返回的HTML已经是请求过数据的,是一个完整的HTML,不在通过JS去动态判断。
我们先通过Node创建一个简单的服务器,看一下服务器是如何渲染的:
// app.js
var http = require('http')
var server = http.createServer()
server.on('request', function (req, res) {
if (req.url === '/' || req.url === '/index.html') {
// 渲染数据
var comments = [
{
name: '张三',
message: '你好,我是张三'
},
{
name: '李四',
message: '你好,我是李四'
},
{
name: '王五',
message: '你好,我是王五'
},{
name: '张六',
message: '你好,我是张六'
}
]
var commentList = comments.map(item => {
return `<li>名称:${item.name}---留言:${item.message}</li>`
})
var htmlStr = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>node渲染</title>
</head>
<body>
<ul>
${commentList.join('')}
</ul>
</body>
</html>
`
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(htmlStr)
}
})
server.listen(3000, function () {
console.log('server is running...')
})
这只是简单的使用node模拟启个服务,通常我们构建的Node服务一般是使用 Node的衍生框架如何Express、Koa、Nest等框架去构建,构建完成打包放到服务器上进行运行,然后全网就可以访问到了。 服务器渲染可以真正的解决SEO问题,但是它部署时需要处于 Node.js server 运行环境,前端需要单独启一个服务来运行,我们从0搭建一个服务端渲染框架也会非常麻烦,使用成本比较大,所以我们需要慎重选择,是否有必要上SSR。
上面我们构建服务其实都是使用纯原生进行构建,没有涉及到单页面应用,如果我们使用单页面应用该如何去构建呢,Vue官方给了示例 服务端渲染 (SSR) (opens new window),介绍了如何使用Vue来构建SSR应用,但从文中可以看到Vue官方也不推荐我们自己从0去搭建SSR应用,它推荐我们使用已有的框架来实现,如Nuxt、Quasar等。
# 3、基于Nuxt实现
基于Vue 生态系统构建的全栈框架行业中给了更通用的解决方案使用Nuxt.js (opens new window),React版本的Next.js (opens new window)。Nuxt可以更快的帮助我们使用Vue来构建一个实现SEO优化的应用,它兼容了客户端渲染和服务端渲染。它既可以生成服务端渲染框架,也可以生成预渲染框架,支持支持SPA(单页面)、SSG(预渲染模式)、SSR(服务端渲染)多种模式,我们可以直接根据我们的需求来选择某种模式创建自己的项目。
Nuxt实现服务端渲染最关键的一个API就是asyncData方法,把接口请求放入这个方法中它就会把数据直接渲染好,而不是等网页加载好再异步去请求。
# 项目构建
Nuxt为我们提供了两种模式,一种是SPA单页面纯静态模式,另一种是Universal服务端渲染模式,我们使用Nuxt就是为了服务端渲染,所以就不需要使用SPA这种模式了。在使用Universal服务端渲染模式时,有两种打包方式供我们选择static和server,static就是SSG静态预渲染,server打包方式就是偏向SSR服务端渲染,这两种打包模式都可以进行SEO优化。项目构建参考模板:nuxt-app模板 (opens new window)、nuxt服务端渲染 (opens new window)
打开文件夹执行命令创建项目
npx create-nuxt-app@2.9.2 <项目名>
执行后,根据提示进行选择,在选择渲染模式Rendering mode时我们选择Universal (SSR / SSG),统一使用服务端渲染模式,选择Deployment target部署模式时根据自己的需求选择,如果是简单的SEO需求使用预渲染static,如果全部使用服务端渲染就使用Server。
创建好后执行命令 npm run dev 运行项目。
? Project name: nuxt-app
? Programming language: JavaScript
? Package manager: Npm
? UI framework: Ant Design Vue
? Template engine: HTML
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: ESLint, Prettier
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: None
目前自动执行的脚手架命令是高版本的,创建服务端渲染没有选择服务端框架的选项,Nuxt会使用默认的服务,无法进行更改服务端配置,如果想要使用自己喜欢的服务框架,可以使用低版本的脚手架去创建项目。
npx create-nuxt-app@2.9.2 <项目名>
# 打包部署
1、预渲染部署
target为static预渲染模式打包,执行打包命令:
npm run generate
打包后会生成dist文件夹,如同vue打包一样,只部署前端项目代码,直接把dist部署到服务器上就可以了。 项目地址:nuxt预渲染 (opens new window)
2、服务端渲染部署
target为server服务端渲染模式打包,打包前要在nuxt.config.js中先设置地址和端口号,部署在服务器上以哪个端口进行访问。
server: {
port: 8000, // 访问端口
host: '0.0.0.0' # 以服务器地址开启
}
执行打包命令:
npm run build
服务端渲染模式需要连同后端服务一起部署,然后在服务器上开启服务。执行命令后,将会在根目录下生成一个 .nuxt 的目录。 当我们要在服务器上进行部署的时候,需要将项目下的 .nuxt目录、static目录、nuxt.config.js、package.json 四个资源拷贝到服务器上。然后在服务器上运行下面命令进行启动服务。
# 服务启动
$ npm i
$ npm run start
# 或者
pm2 start npm --name nuxt -- run start
#重启
pm2 restart name
项目地址:nuxt服务端渲染 (opens new window)
# 4、后端实现
前端如果实现起来太麻烦或者已有的网站更改太麻烦,可以通过在服务器配置进行实现,在服务器安装一些插件,通过拦截爬虫请求代理到服务器生成的预渲染地址来达到SEO优化的能力。
1、seo-server (opens new window)插件
通过nignx配置拦截请求头转到这个服务上,用 playwright 浏览器进行渲染,然后返回 html 代码。
2、Prerender.io (opens new window)服务
Prerender.io是预渲染服务,根据用户请求的UA类型,普通用户请求,按照正常流程走,如果是爬虫之类的用户请求,采用由prerender执行页面js后生成的静态页面发送给爬虫,从而达到通用的单页面seo。
# 总结
如果你用单页面应用写一个简单的纯静态官网,只需要部分页面做SEO,推荐使用插件进行预渲染;如果你的网站是面向C端客户,部分页面的接口内容需要做SEO,那么可以使用Nuxt的static模式来部署;如果你的网站是一个动态内容比较多,比如博客、论坛、新闻这一类型的,你可以使用Nuxt的server模式来部署,或者自己搭建一个SSR服务;如果前端自己不想去兼容SEO优化,也可以在服务器配置来实现。
通过上面我们了解了浏览器渲染原理和SEO优化的原理,实现SEO优化方案有哪些,我们总结一些方案的实现思路,这些方案没有说哪一个就绝对好,使用哪种方案根据实际情况而定,以最快方法来解决业务需求才是对的。