基於 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 簡單的優化強多了。

參考文章


相關文章
相關標籤/搜索