基于 SSR/SSG 的前端 SEO 优化

前言

前段时间对项目作了 SEO 优化,到如今才来写总结。咱们知道,常规用 Vue/React 开发的是 SPA 应用,可是自然的单页面应用 SEO 就是很差,虽说如今也有各类技术能够改善了,好比使用预渲染,但也都存在各类缺点。可是即便这样,也抵不住 Vue/React 这类框架的潮流,不少产品也能够经过其余亮点而不依赖 SEO 普及开,也有须要登陆才能用的使用 SEO 也没有什么意义。javascript

若是项目中真的对 SEO 和首屏加载速度有刚性需求,又使用 Vue/React 这类技术,且想尽可能减小代码开发附加的难度,有一种比较直接的方式,就是直接使用服务端渲染的框架,Vue 的 Nuxt.js,React 的 Next.js/Gatsby。html

不过,其实学习一门新框架也是一项附加成本啊哈哈,可是 SSR 渲染不过实际开发用不用,起码都要了解一下。我当前以 React 技术栈为主,因此目前只了解的是关于 React 的 SSR 渲染框架,有兴趣的能够看下我这两篇文章:前端

因此本文不讨论单页面应用的 SEO 优化,讲的是基于服务端渲染(SSR)/静态生成(SSG)网站 SEO 的优化。java

本文会回顾传统的 SEO 的优化方式,以及基于 Gatsby SEO 的优化。react

服务端渲染 SSR 与静态网站渲染 SSG

服务端是指客户端向服务器发出请求,而后运行时动态生成 html 内容并返回给客户端。
静态站点的解析是在构建时执行的,当发出请求时,html 将静态存储,直接发送回客户端。git

一般来讲,静态站点在运行时会更快,由于不须要服务端作处理,但缺点是对数据的任何更改都须要在服务端进行彻底重建;而服务端渲染则会动态处理数据,不须要进行彻底重建。github

对于 Vue/React 来讲,对于它们的 SSR/SSG 框架出现的缘由就是主要就是 SEO 和首屏加载速度。web

搜索引擎的工做原理

在搜索引擎网站的后台会有一个很是庞大的数据库,里面存储了海量的关键词,而每一个关键词又对应着不少网址,这些网址是被称之为“搜索引擎蜘蛛”或“网络爬虫”程序从互联网上收集而来的。

这些"蜘蛛"在互联网上爬行,从一个连接到另外一个连接,对内容进行分析,提炼关键词加入数据库中;若是蜘蛛认为是垃圾或重复信息,就舍弃继续爬行。当用户搜索时,就能检索出与关键字相关的网址显示给用户。算法

当用户在搜索引擎搜索时,好比搜索"前端",则跳出来全部含有"前端"二字关键字的网页,而后根据特定算法给每一个含有"前端"二字的网页一个评分排名返回搜索结果。而这些包含"前端"的内容,能够是文章标题、描述、关键字、内容甚至能够是连接。固然,也有多是广告优先置顶,你懂的。数据库

一个关键词对用多个网址,所以就出现了排序的问题,相应的当与关键词最吻合的网址就会排在前面了。在“蜘蛛”抓取网页内容,提炼关键词的这个过程当中,就存在一个问题:“蜘蛛”可否看懂。若是网站内容是 flash 和 js 等,那么它是看不懂的,会犯迷糊,即便关键字再贴切也没用。相应的,若是网站内容能够被搜索引擎能识别,那么搜索引擎就会提升该网站的权重,增长对该网站的友好度。这样一个过程咱们称之为 SEO(Search Engine Optimization),即搜索引擎优化。

SEO 目的

让网站更利于各大搜索引擎抓取和收录,增长对搜索引擎的友好度,使得用户在搜索对应关键词时网站时能排在前面,增长产品的曝光率和流量。

SEO 优化方式

咱们这里主要讲前端能参与和作的优化方式。好比不少 SEO 优化方式都有介绍:控制首页连接数量,扁平化目录层次,优化网站结构布局,分页导航写法这些等,但实际上,平常前端开发也充当不了网站总体设计的角色,只能是协调,这些大部分都是一开始就定好的东西。

好比新闻媒体类等网站比较重视 SEO 的,一般公司还会设有 SEO 部门或者是 SEO 优化工程师岗位,像上面说的,还有网页关键词、描述的就交给他们参与和提供,有些优化方式咱们难以触及的就不细谈了,有兴趣的能够去了解。

网页 TDK 标签

  • title:当前页面的标题(强调重点便可,每一个页面的 title 尽可能不要相同)
  • description:当前页面的描述(列举几个关键词便可,不要过度堆积)
  • keywords:当前页面的关键词(高度归纳网页内容)

每一个页面的 TDK 都不同,这个须要根据产品业务提炼出核心关键词。

那么页面的 TDK 都不同,咱们就须要对它进行动态设置,react 的话有react-helmet
插件,用于设置头部标签。

import React from 'react'
import { Helmet } from 'react-helmet'

const GoodsDetail = ({ title, description, keywords }) => {
  return (
    <div className='application'>
      <Helmet>
        <title>{title}</title>
        <meta name='description' content={`${description}`} />
        <meta name='keywords' content={`${keywords}`} />
      </Helmet>
      <div>content...</div>
    </div>
  )
}

上面是演示,实际项目作法仍是会把 Helmet 里的内容单独抽离出来作组件。

在 Next.js 里面,是自带 Head 组件的:import Head from 'next/head'

语义化标签

根据内容的结构化,选择合适的 HTML5 标签尽可能让代码语义化,如使用 header,footer,section,aside,article,nav 等等语义化标签可让爬虫更好的解析。

合理使用 h1~h6 标签

一个页面中只能最多出现一次h1标签,h2标签一般做为二级标题或文章的小标题。其他h3-h6标签如要使用应按顺序层层嵌套下去,不能够断层或反序。

好比一般在首页的 logo 上加h1标签,但网站设计只展现 logo 图无文字的状况下,h1 的文字就能够设置font-size为零来隐藏

<h1>
  <img src="logo.png" alt="jacky" />
  <span>jacky的我的博客</span>
</h1>

图片的 alt 属性

通常来讲,除非是图片仅仅是纯展现类没有任何实际信息的话,alt属性能够为空。不然使用img标签都要添加alt属性,使"蜘蛛"能够抓取到图片的信息。
当网络加载不出来或者图片地址失效时,alt属性的内容才会代替图片呈现出来,

<img src="dog.jpg" width="300" height="200" alt="哈士奇" />

a 标签的 title

同理,a 标签的 title 属性其实就是提示文字做用,当鼠标移动到该超连接上时,就会有提示文字的出现。经过添加该属性也有微小的做用利于 SEO。

<a
  href="https://github.com/Jacky-Summer/personal-blog"
  title="了解更多关于Jacky的我的博客"
  >了解更多</a
>

404 页面

404 页面首先是用户体验良好,不会莫名报一些其余提示。其次对蜘蛛也友好,不会由于页面错误而中止抓取,能够返回抓取网站其余页面。

nofollow 忽略跟踪

  • nofollow 有两种用法:
  1. 用于 meta 元标签,告诉爬虫该页面上全部连接都无需追踪。
<meta name="robots" content="nofollow" />
  1. 用于 a 标签,告诉爬虫该页面无需追踪。
<a href="https://www.xxxx?login" rel="nofollow">登陆/注册</a>

一般用在 a 标签比较多,它主要有三个做用:

  1. "蜘蛛"分配到每一个页面的权重是必定的,为了集中网页权重并将权重分给其余必要的连接,就设置rel='nofollow'告诉"蜘蛛"不要爬,来避免爬虫抓取一些无心义的页面,影响爬虫抓取的效率;并且一旦"蜘蛛"爬了外部连接,就不会再回来了。
  2. 付费连接:为了防止付费连接影响 Google 的搜索结果排名,Google 建议使用 nofollow 属性。
  3. 防止不可信的内容,最多见的是博客上的垃圾留言与评论中为了获取外链的垃圾连接,为了防止页面指向一些拉圾页面和站点。

创建 robots.txt 文件

robots.txt 文件由一条或多条规则组成。每条规则可禁止(或容许)特定抓取工具抓取相应网站中的指定文件路径。
User-agent: *
Disallow:/admin/
SiteMap: http://www.xxxx.com/sitemap.xml

关键词:

  1. User-agent 表示网页抓取工具的名称
  2. Disallow 表示不该抓取的目录或网页
  3. Allow 应抓取的目录或网页
  4. Sitemap 网站的站点地图的位置
  • User-agent: *表示对全部的搜索引擎有效
  • User-agent: Baiduspider 表示百度搜索引擎,还有谷歌 Googlebot 等等搜索引擎名称,经过这些能够设置不一样搜索引擎访问的内容

参考例子的话好比百度的 robots.txt,京东的 robots.txt

robots 文件是搜索引擎访问网站时第一个访问的,而后根据文件里面设置的规则,进行网站内容的爬取。经过设置AllowDisallow访问目录和文件,引导爬虫抓取网站的信息。

它主要用于使你的网站避免收到过多请求,告诉搜索引擎应该与不该抓取哪些页面。若是你不但愿网站的某些页面被抓取,这些页面可能对用户无用,就经过Disallow设置。实现定向 SEO 优化,曝光有用的连接给爬虫,将敏感无用的文件保护起来。

即便网站上面全部内容都但愿被搜索引擎抓取到,也要设置一个空的 robot 文件。由于当蜘蛛抓取网站内容时,第一个抓取的文件 robot 文件,若是该文件不存在,那么蜘蛛访问时,服务器上就会有一条 404 的错误日志,多个搜索引擎抓取页面信息时,就会产生多个的 404 错误,故通常都要建立一个 robots.txt 文件到网站根目录下。

空 robots.txt 文件

User-agent: *
Disallow:

若是想要更详细的了解 robots.txt 文件,能够看下:

通常涉及目录比较多的话都会找网站工具动态生成 robots.txt,好比 生成 robots.txt

创建网站地图 sitemap

当网站刚刚上线的时候,连往该网站的外部连接并很少,爬虫可能找不到这些网页;或者该网站的网页之间没有较好的衔接关系,爬虫容易漏掉部分网页。这个时候,sitemap 就派上用场了。

sitemap 是一个将网站栏目和链接归类的一个文件,让搜索引擎全面收录站点网页地址,了解站点网页地址的权重分布以及站点内容更新状况,提升爬虫的爬取效率。Sitemap 文件包含的网址不能够超过 5 万个,且文件大小不得超过 10MB。

sitemap 地图文件包含 html(针对用户)和 xml(针对搜索引擎)两种,最多见的就是 xml 文件,XML 格式的 Sitemap 一共用到 6 个标签,其中关键标签包括连接地址(loc)、更新时间(lastmod)、更新频率(changefreq)和索引优先权(priority)。

爬虫怎么知道网站有没有提供 sitemap 文件呢,也就是上面说的路径放在了 robots.txt 里面。

先找网站的根目录里找 robots.txt,好比腾讯网下的 robots.txt 以下:

User-agent: *
Disallow:
Sitemap: http://www.qq.com/sitemap_index.xml

就找到了 sitemap 路径(只列出一部分)

<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>http://news.qq.com/news_sitemap.xml.gz</loc>
    <lastmod>2011-11-15</lastmod>
  </sitemap>
  <sitemap>
    <loc>http://finance.qq.com/news_sitemap.xml.gz</loc>
    <lastmod>2011-11-15</lastmod>
  </sitemap>
  <sitemap>
    <loc>http://sports.qq.com/news_sitemap.xml.gz</loc>
    <lastmod>2011-11-15</lastmod>
  </sitemap>
  <sitemap>
</sitemapindex>
  • loc:页面永久连接地址,能够是静态页面,也但是动态页面
  • lastmod:页面的最后修改时间,非必填项。搜索引擎根据此项与 changefreq 相结合,判断是否要从新抓取 loc 指向的内容

通常网站开发完后,这个 sitemap 通常都是靠自动生成,好比 sitemap 生成工具

结构化数据

结构化数据(Structured data)是一种标准化格式,使用它向 Google 提供有关该网页含义的明确线索,从而帮助理解该网页。通常都 JSON-LD 格式,这格式长什么样呢,看谷歌官方的示例代码:

<html>
  <head>
    <title>Party Coffee Cake</title>
    <script type="application/ld+json">
      {
        "@context": "https://schema.org/",
        "@type": "Recipe",
        "name": "Party Coffee Cake",
        "author": {
          "@type": "Person",
          "name": "Mary Stone"
        },
        "nutrition": {
          "@type": "NutritionInformation",
          "calories": "512 calories"
        },
        "datePublished": "2018-03-10",
        "description": "This coffee cake is awesome and perfect for parties.",
        "prepTime": "PT20M"
      }
    </script>
  </head>
  <body>
    <h2>Party coffee cake recipe</h2>
    <p>
      This coffee cake is awesome and perfect for parties.
    </p>
  </body>
</html>

列明了网页页面种类属于"食谱",做者和发布时间,描述和烹饪时间等等。这样谷歌搜索出来就有机会含有这些提示或者你带着关键信息去搜索更有利于找到结果。

官方提供了各类字段用来描述"食谱",你只要去查阅相关字段,就能够直接按格式来使用了。

由于该 SEO 优化针对谷歌搜索引擎特有的,因此有设置该方式的网站一般是用户是不限于国内的,不只是结构化数据特有,还有一种 SEO 优化方式是 AMP 网页,感兴趣的能够了解看看 —— AMP

谷歌还提供了测试工具 Structured Data Testing Tool,能够输入测试网站网址来查看该网站有没有结构化数据设置。

性能优化

好比减小 http 请求,控制页面大小,懒加载,利用缓存等等,这方式就不少了,都是为了提升网站的加载速度和良好用户体验,这个也不是专指 SEO 的问题,是开发中都要作的事情。

由于当网站速度很慢时,一旦超时,"蜘蛛"也会离开。

Gatsby 下的 SEO 优化

自己 Gatsby 就采起静态生成的方式,SEO 已经是能够,但依然仍是要作 SEO 优化。

知道了上述的 SEO 优化方式后,Gatsby 该如何实战优化呢?这个,因为 Gatsby 社区比较强大,插件不少,因此上面几个依靠插件就能够快速配置生成。

gatsby-plugin-robots-txt

在 gatsby-config.js 里面配置

module.exports = {
  siteMetadata: {
    siteUrl: 'https://www.xxxxx.com'
  },
  plugins: ['gatsby-plugin-robots-txt']
};

gatsby-plugin-sitemap

在 gatsby-config.js 里面配置

{
  resolve: `gatsby-plugin-sitemap`,
  options: {
    sitemapSize: 5000,
  },
},

网页 TDK

Gatsby 标准脚手架和有官方文档都有一个 SEO.js 文件,里面就是给咱们设置 TDK 提供了方法

import React from 'react'
import PropTypes from 'prop-types'
import { Helmet } from 'react-helmet'
import { useStaticQuery, graphql } from 'gatsby'

function SEO({ description, lang, meta, title }) {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )

  const metaDescription = description || site.siteMetadata.description

  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata.author,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ].concat(meta)}
    />
  )
}

SEO.defaultProps = {
  lang: `en`,
  meta: [],
  description: ``,
}

SEO.propTypes = {
  description: PropTypes.string,
  lang: PropTypes.string,
  meta: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
}

export default SEO

而后在页面模板文件中引入 SEO.js,并传入页面的变量参数,便可设置 TDK 等等头部信息。

structured data

好比说项目是新闻文章展现的,能够设置三种结构化数据(数据类型和字段不是凭空捏造的,这个须要去 Google 查符合对应匹配的)——文章详情页,文章列表页,再加个公司的介绍。

在项目根目录下新建

  • ./src/components/Jsonld.js
    封装外部包住的 script 标签做为组件
import React from 'react'
import { Helmet } from 'react-helmet'

function JsonLd({ children }) {
  return (
    <Helmet>
      <script type="application/ld+json">{JSON.stringify(children)}</script>
    </Helmet>
  )
}

export default JsonLd
  • ./src/utils/json-ld/article.js - 文章详情结构化数据描述
const articleSchema = ({
  url,
  headline,
  image,
  datePublished,
  dateModified,
  author,
  publisher,
}) => ({
  '@context': 'http://schema.org',
  '@type': 'Article',
  mainEntityOfPage: {
    '@type': 'WebPage',
    '@id': url,
  },
  headline,
  image,
  datePublished,
  dateModified,
  author: {
    '@type': 'Person',
    name: author,
  },
  publisher: {
    '@type': 'Organization',
    name: publisher.name,
    logo: {
      '@type': 'ImageObject',
      url: publisher.logo,
    },
  },
})

export default articleSchema
  • ./src/utils/json-ld/item-list.js - 文章列表结构化数据描述
const itemListSchema = ({ itemListElement }) => ({
  '@context': 'http://schema.org',
  '@type': 'ItemList',
  itemListElement: itemListElement.map((item, index) => ({
    '@type': 'ListItem',
    position: index + 1,
    ...item,
  })),
})

export default itemListSchema
  • ./src/utils/json-ld/organization.js - 公司组织结构化数据描述
const organizationSchema = ({ name, url }) => ({
  '@context': 'http://schema.org',
  '@type': 'Organization',
  name,
  url,
})

export default organizationSchema

而后再分别引入页面,好比咱们在文章详情页面,引入对应类型文件,大概就是这么个用法:

// ...
import JsonLd from '@components/JsonLd'
import SEO from '@components/SEO'
import articleSchema from '@utils/json-ld/article'

const DetailPage = ({ data }) => {
  // 处理 data,拆开相关字段
  return (
    <Layout>
      <SEO
        title={meta_title || title}
        description={meta_description}
        keywords={meta_keywords}
      />
      <JsonLd>
        {articleSchema({
          url,
          headline: title,
          datePublished: first_publication_date,
          dateModified: last_publication_date,
          author: siteMetadata.title,
          publisher: {
            name: siteMetadata.title,
            logo: 'xxx',
          },
        })}
      </JsonLd>
      <Container>
        <div>content...</div>
      </Container>
    </Layout>
  )
}

上面的代码要是迷迷糊糊却是正常,由于没有了解过结构化数据的内容,但看文档就大概能够了解清楚了。

Lighthouse 性能优化工具

能够去谷歌商店安装LightHouse,打开 F12,进入你的网站,点击Generate report,就会生成网站对应的报告

  • 生成的 report:

在它下面有一些提示,针对性能和 SEO 等,你能够根据提示去改善你的代码。

文章的介绍到这里就结束了,但愿对你们了解 SEO 有一点帮助。SEO 的摸索并非以上举例完就差很少没了,其实有各类各样的方式能够优化。上面列举的是比较常见的,事实上,我以为 SEO 优化无非是想吸引更多的用户点击和使用网站,但若是网站的内容优质用户体验良好,加性能好,那么有用户使用后就自带推广性,那么无疑比 SEO 简单的优化强多了。

参考文章


相关文章
相关标签/搜索