SEO简介

什么是SEO?

搜索引擎优化 (SEO) 是通过有机搜索引擎结果增加网站流量的数量和质量的做法。这是通过提高您的网站在搜索引擎上的排名来实现的。您的网站排名越高,它就越有可能出现在搜索结果的第一页,并且会有更多的人访问它。

为什么SEO很重要?

68% 的在线体验始于搜索引擎,75% 的人从不滚动浏览搜索引擎结果的第一页。这意味着如果没有 SEO,您的 Web 应用程序可能会错过潜在的增长和成功,并且会被隐藏起来。

SEO是如何工作的?

SEO过程可以分为3个步骤:

  1. **爬虫:**爬虫可以被认为是搜索引擎的“居民”,他们出去访问网页。然后,他们将有关这些网页的信息反馈给搜索引擎,这些网页被索引到称为索引的数据库中,以供以后检索。

  2. 索引: 当人们进行 Google 搜索时,结果不仅基于您的内容中最常见的词,还基于与用户最相关的内容。这意味着像谷歌这样的搜索引擎在对您的网页在某个关键字的结果中进行排名时会关心诸如标题和元描述之类的元数据。

  3. **排名:**一旦搜索引擎创建了您网站的索引,它就会尝试对与用户搜索查询相关的所有索引页面进行排名。搜索引擎的目标是为用户提供与其查询匹配的最佳结果。

SEO 最佳实践

现在我们知道了 SEO 的工作原理,让我们看看它的最佳实践是什么。

  1. 做一个好公民,做一个有用的网站

在我们继续之前,这可能是最重要的建议:写有用的内容!如果没有人看到它,你在优化你的 React 应用程序上付出了多少努力都没有关系。如果您发布人们关心的内容,那么其他互联网用户可能会链接到您的网站并与他们的朋友分享,这会增加在搜索引擎结果中可见的可能性。

  1. 用你的标题和元描述来描述

这意味着你应该写一些更具描述性的东西,而不是写像“家”这样的标题。这是因为搜索引擎机器人不够智能,无法根据彼此接近的不同单词来判断你的页面是关于什么的。

  1. 为您网站的每个页面创建独特的内容

在您的网站上有重复的内容对 SEO 不利。例如,如果您有多个具有相同内容的页面 - 搜索引擎将无法正确地对每个页面进行排名。

  1. 优化您的页面速度

像谷歌这样的搜索引擎关心页面速度。

这里要记住的重要一点是,爬网寻找内容的 GoogleBot 的带宽非常低。这意味着如果加载时间不长,它应该不会有任何问题来抓取您网站的任何页面。

页面加载所需的时间可能会对访问者的停留数量产生重大影响。用时不到 2 秒的页面的平均跳出率为 9%,而在 5 秒内加载的页面显示为 38%。

  1. 优化图片

我们都知道图像是在我们的页面上增加更多多样性和创造力的好方法,但是在使用它们时应该做一些事情。优化图像不仅会提高 Google Bot 抓取您的内容的速度;它还将提高用户的加载速度!

  1. 包括各种内部链接

内部链接是让人类和搜索引擎更容易访问您的网站的好方法。它们向 Google 提供了这些页面上的内容相关的额外信号,这将有助于在结果中排名更高;同时还通过他们所有的额外信息使其比以往任何时候都更容易!

创建博客应用

在本节中,我们创建一个名为sanity-blog的新 react.js 应用程序,该应用程序连接到 Sanity。

完成的项目可以在这个Github repo上找到!您也可以查看这个应用程序的现场版

设置一个新的 React 应用程序

⚠️ 在开始之前,请确保在您的环境中安装了 Node.js。要了解更多信息,请访问节点网站。

打开您的 Shell 并运行以下命令。

npx create-react-app sanity-blog

进入全屏模式 退出全屏模式

接下来,运行此命令将目录更改为您创建的项目

cd sanity-blog

进入全屏模式 退出全屏模式

为确保一切正常,请在终端中执行以下命令。你的 React 应用程序应该在浏览器上打开http://localhost:3000。

npm start

进入全屏模式 退出全屏模式

现在让我们安装一些我们需要的依赖项。在项目的根目录中运行以下命令:

npm install @portabletext/reactimport @portabletext/react @sanity/image-url react-router-dom
npm install -D tailwindcss postcss autoprefixer @tailwindcss/typography
npx tailwindcss init

进入全屏模式 退出全屏模式

接下来,让我们设置 TailwindCSS 来设置前端的样式。转到src/index.css并将文件内容替换为

@tailwind base;
@tailwind components;
@tailwind utilities;

进入全屏模式 退出全屏模式

现在转到./tailwind.config.js文件并将其替换为以下内容

module.exports = {
  content: ["./src/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [require("@tailwindcss/typography")],
}

进入全屏模式 退出全屏模式

设置健全性

我们的目标是:

  • 为我们的博客创建一个新的 Sanity 项目

  • 自定义默认博客架构以添加 SEO 字段

  • 添加一些内容

让我们开始在我们的本地环境中安装 Sanity CLI。

⚠️ 在运行这些命令之前,请确保您位于sanity-blog目录中。

npm i -g @sanity/cli

进入全屏模式 退出全屏模式

当 Sanity CLI 安装成功后,我们可以在我们的 React 项目中激活初始化 Sanity。

sanity init

进入全屏模式 退出全屏模式

现在您在命令行中看到了几个问题。回答他们如下:

? Select project to use **Create new project**
? Your project name: **Sanity Blog**
? Use the default dataset configuration? **Yes**
? Project output path: **[Choose default path]**
? Select project template **Blog (schema)**

进入全屏模式 退出全屏模式

完成后,您应该会在sanity-blog头下看到一个名为sanityblog的新文件夹,然后运行以下命令启动 Sanity Studio。

cd sanityblog
sanity start

进入全屏模式 退出全屏模式

运行这些命令后,您应该会看到

sanity start
✔ Checking configuration files...
⠧ Compiling...webpack built 2f98f0cdc718c8744e79 in 11987ms
✔ Compiling...
Content Studio successfully compiled! Go to http://localhost:3333

进入全屏模式 退出全屏模式

前往http://localhost:3333打开 Sanity Studio。

现在,让我们为我们的帖子模型添加一些新字段,以便可以针对搜索引擎进行优化。

在您的代码编辑器中转到sanityblogschemas并打开post.js文件。

[post.js 在项目中的位置](https://res.cloudinary.com/practicaldev/image/fetch/s--_rl0K0DB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https:// /s3-us-west-2.amazonaws.com/secure.notion-static.com/b9dddd29-63f7-4e37-867a-fafa55b24761/Screen_Shot_2022-02-07_at_22.31.37.png)

post.js 在项目中的位置

将此文件的内容替换为以下内容:

export default {
  name: 'post',
  title: 'Post',
  type: 'document',
  groups: [
    {
      name: 'seo',
      title: 'SEO',
    },
  ],
  fields: [
    {
      name: 'title',
      title: 'Title',
      type: 'string',
    },
    {
      name: 'seoTitle',
      title: 'SEO Title',
      group: 'seo',
      validation: Rule => [
        Rule.required().min(40).max(50).error('SEO titles between 40 and 50 characters with commonly searched words have the best click-through-rates'),
      ],
      type: 'string',
    },
    {
      name: 'seoDescription',
      title: 'SEO Description',
      group: 'seo',
      validation: Rule => [
        Rule.required().min(50).max(156).error('Good SEO descriptions utilize keywords, summarize the story and are between 140-156 characters long.'),
      ],
      type: 'text',
    },
    {
      name: "ogTitle",
      title: "Open Graph Title",
      group: 'seo',
      validation: Rule => [
        Rule.required().min(40).max(50).error('SEO titles between 40 and 50 characters with commonly searched words have the best click-through-rates'),
      ],
      type: "string",
    },
    {
      name: "ogDescription",
      title: "Open Graph Description",
      group: 'seo',
      validation: Rule => [
        Rule.required().min(50).max(156).error('Good SEO descriptions utilize keywords, summarize the story and are between 140-156 characters long.'),
      ],
      type: "text",
    },
    {
      name: "ogImage",
      title: "Open Graph Image",
      group: 'seo',
      type: "image",
    },
    {
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'title',
        maxLength: 96,
      },
    },
    {
      name: 'author',
      title: 'Author',
      type: 'reference',
      to: {type: 'author'},
    },
    {
      name: 'mainImage',
      title: 'Main image',
      type: 'image',
      options: {
        hotspot: true,
      },
    },
    {
      name: 'categories',
      title: 'Categories',
      type: 'array',
      of: [{type: 'reference', to: {type: 'category'}}],
    },
    {
      name: 'publishedAt',
      title: 'Published at',
      type: 'datetime',
    },
    {
      name: 'body',
      title: 'Body',
      type: 'blockContent',
    },
  ],

  preview: {
    select: {
      title: 'title',
      author: 'author.name',
      media: 'mainImage',
    },
    prepare(selection) {
      const {author} = selection
      return Object.assign({}, selection, {
        subtitle: author && `by ${author}`,
      })
    },
  },
}

进入全屏模式 退出全屏模式

我们对默认架构添加了 2 个重要更改:

  1. 我们添加了一个名为 SEO 的新组,该组将在帖子页面上显示为一个标签。该组包含 SEO 的所有必要字段。

[屏幕截图 2022-02-07 在 23.02.43.png](https://res.cloudinary.com/practicaldev/image/fetch/s--NCF6k_6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d0cb79c3-51d2-4b95-a621-4dc813f63019/Screen_Shot_2022-02-07_at_23.02.43.png)

  1. 我们有一套全新的元标题、描述、开放图标题、描述和图像字段。这些都经过验证,因此它们包含适当的长度以在 SEO 中产生最佳结果。

[屏幕截图 2022-02-07 at 23.11.11.png](https://res.cloudinary.com/practicaldev/image/fetch/s--4zspmOvC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/83dc1a07-51a5-4d3e-b899-93beaea3d911/Screen_Shot_2022-02-07_at_23.11.11.png)

最后,让我们在 Sanity Studio 中创建一个示例博客文章

[屏幕截图 2022-02-07 at 23.24.09.png](https://res.cloudinary.com/practicaldev/image/fetch/s--YitzvwPa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7f327558-7060-49ae-b249-55fcdd849b46/Screen_Shot_2022-02-07_at_23.24.09.png)

将 Sanity 连接到我们的 React 应用程序

要将 Sanity 连接到 React 应用程序,我们首先安装 Sanity 客户端。转到项目的根目录并运行以下命令

npm install @sanity/client

进入全屏模式 退出全屏模式

接下来,我们需要创建一个 Sanity Client 实例并在我们的项目中进行设置。为此,请在src文件夹下创建一个名为client.js的新文件,然后在该文件中添加以下代码:

import sanityClient from "@sanity/client";

export default sanityClient({
    apiVersion: "2022-04-06",
  projectId: "Your Project ID Here",
  dataset: "production",
  useCdn: true,
});

进入全屏模式 退出全屏模式

💡要找到projectId你可以去sanityblog/sanity.json搜索projectId

最后,让我们将 React 应用 URL 添加到 Sanity Project CORS 源。在命令行中,转到sanityblog文件夹并运行以下命令并对问题回答“是”。

sanity cors add http://localhost:3000

进入全屏模式 退出全屏模式

创建 React 组件

src文件夹下创建一个名为components的新文件夹,让我们在其中添加AllPosts.jsOnePost.js

AllPosts.js文件应包含

import React, { useState, useEffect } from 'react';
import sanityClient from "../client"
import imageUrlBuilder from "@sanity/image-url";

const builder = imageUrlBuilder(sanityClient);
function urlFor(source) {
  return builder.image(source);
}

export default function AllPosts() {
    const [posts, setPosts] = useState([]);
    const [loading, setLoading] = useState(true);
    useEffect(() => {
            // This is GROQ syntax for our query, to learn more about it, check out the docs at https://www.sanity.io/docs/groq
      sanityClient.fetch(
        `*[_type == "post"] | order(publishedAt desc) {
          title,
          publishedAt,
          slug,
          body,
          "authorName": author->name,
          "authorImage": author->image,
          mainImage{
            asset->{
              _id,
              url
             }
           },
          categories {
            title,
            slug,
          },
        }`
        )
        .then(posts => {
          setPosts(posts);
          setLoading(false);
        })
    }, []);

    return loading ? (
        <div>Loading...</div>
      ) : ( 
        <div className="relative bg-gray-50 pt-16 pb-20 px-4 sm:px-6 lg:pt-24 lg:pb-28 lg:px-8">
        <div className="absolute inset-0">
          <div className="bg-white h-1/3 sm:h-2/3" />
        </div>
        <div className="relative max-w-7xl mx-auto">
          <div className="text-center">
            <h2 className="text-3xl tracking-tight font-extrabold text-gray-900 sm:text-4xl">From the blog</h2>
            <p className="mt-3 max-w-2xl mx-auto text-xl text-gray-500 sm:mt-4">
              Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ipsa libero labore natus atque, ducimus sed.
            </p>
          </div>
          <div className="mt-12 max-w-lg mx-auto grid gap-5 lg:grid-cols-3 lg:max-w-none">
            {posts.map((post) => (
              <div key={post.slug.current} className="flex flex-col rounded-lg shadow-lg overflow-hidden">
                <a href={`/${post.slug.current}` } className="block mt-2">
                    <div className="flex-shrink-0">
                    <img className="w-full object-cover" src={urlFor(post.mainImage).width(100).url()} alt={post.title} />
                    </div>
                    <div className="flex-1 bg-white p-6 flex flex-col justify-between">
                    <div className="flex-1">
                        <p className="text-xl font-semibold text-gray-900">{post.title}</p>
                    </div>
                    <div className="mt-6 flex items-center">
                        <div className="flex-shrink-0">
                            <span className="sr-only">{post.authorName}</span>
                            <img className="h-10 w-10 rounded-full" src={urlFor(post.authorImage).width(100).url()} alt={post.authorName} />
                        </div>
                        <div className="ml-3">
                        <p className="text-sm font-medium text-gray-900">
                            {post.authorName}
                        </p>
                        <div className="flex space-x-1 text-sm text-gray-500">
                            <time dateTime={post.publishedAt}>{post.publishedAt}</time>
                            <span aria-hidden="true">&middot;</span>
                        </div>
                        </div>
                    </div>
                    </div>
                </a>
              </div>
            ))}
          </div>
        </div>
      </div>
      );
}

进入全屏模式 退出全屏模式

OnePost.js文件应包含

import React, {useState, useEffect} from 'react';
import sanityClient from '../client';
import imageUrlBuilder from '@sanity/image-url';
import { PortableText } from '@portabletext/react'

const builder = imageUrlBuilder(sanityClient);
function urlFor(source) {
  return builder.image(source);
}

export default function OnePost(){
    const [post, setPost] = useState([]);
    const [loading, setLoading] = useState(true);
    useEffect(() => {
      sanityClient.fetch(
        `*[_type == "post" && slug.current == $slug][0]{
          title,
          publishedAt,
          slug,
          body,
          "authorName": author->name,
          "authorImage": author->image,
          mainImage{
            asset->{
              _id,
              url
            }
          },
          categories {
            title,
            slug,
          },
        }`,
        {slug: window.location.pathname.split('/')[1]}
      )
      .then(post => {
        setPost(post);
        setLoading(false);
      })
    }, []);

    return loading ? (
        <div>Loading...</div>
    ) : (
      <div className="relative py-16 bg-white overflow-hidden">
          <div className="hidden lg:block lg:absolute lg:inset-y-0 lg:h-full lg:w-full">
            <div className="relative h-full text-lg max-w-prose mx-auto" aria-hidden="true">
              <svg
                className="absolute top-12 left-full transform translate-x-32"
                width={404}
                height={384}
                fill="none"
                viewBox="0 0 404 384"
              >
                <defs>
                  <pattern
                    id="74b3fd99-0a6f-4271-bef2-e80eeafdf357"
                    x={0}
                    y={0}
                    width={20}
                    height={20}
                    patternUnits="userSpaceOnUse"
                  >
                    <rect x={0} y={0} width={4} height={4} className="text-gray-200" fill="currentColor" />
                  </pattern>
                </defs>
                <rect width={404} height={384} fill="url(#74b3fd99-0a6f-4271-bef2-e80eeafdf357)" />
              </svg>
              <svg
                className="absolute top-1/2 right-full transform -translate-y-1/2 -translate-x-32"
                width={404}
                height={384}
                fill="none"
                viewBox="0 0 404 384"
              >
                <defs>
                  <pattern
                    id="f210dbf6-a58d-4871-961e-36d5016a0f49"
                    x={0}
                    y={0}
                    width={20}
                    height={20}
                    patternUnits="userSpaceOnUse"
                  >
                    <rect x={0} y={0} width={4} height={4} className="text-gray-200" fill="currentColor" />
                  </pattern>
                </defs>
                <rect width={404} height={384} fill="url(#f210dbf6-a58d-4871-961e-36d5016a0f49)" />
              </svg>
              <svg
                className="absolute bottom-12 left-full transform translate-x-32"
                width={404}
                height={384}
                fill="none"
                viewBox="0 0 404 384"
              >
                <defs>
                  <pattern
                    id="d3eb07ae-5182-43e6-857d-35c643af9034"
                    x={0}
                    y={0}
                    width={20}
                    height={20}
                    patternUnits="userSpaceOnUse"
                  >
                    <rect x={0} y={0} width={4} height={4} className="text-gray-200" fill="currentColor" />
                  </pattern>
                </defs>
                <rect width={404} height={384} fill="url(#d3eb07ae-5182-43e6-857d-35c643af9034)" />
              </svg>
            </div>
          </div>
          <div className="relative px-4 sm:px-6 lg:px-8">
            <div className="text-lg max-w-prose mx-auto">
              <h1>
                <span className="mt-2 block text-3xl text-center leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl">
                  {post.title}
                </span>
              </h1>
              <hr className="mt-8 border-b-2 w-24 mx-auto border-gray-200" />
              <figure>
                <img
                  className="w-full h-72 rounded-lg mt-12"
                  src={urlFor(post.mainImage).width(100).url()} 
                  alt={post.title}
                />
                <figcaption className='text-gray-700 text-center pt-2'>Sagittis scelerisque nulla cursus in enim consectetur quam.</figcaption>
              </figure>
              <div className="mt-8 text-xl text-gray-500 leading-8 prose prose-indigo">
                <PortableText value={post.body} />
              </div>
            </div>
          </div>
        </div>
      )
    }

进入全屏模式 退出全屏模式

最后将src/App.js的内容替换为如下

import React from 'react';
import AllPosts from './components/AllPosts';
import OnePost from './components/OnePost';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import './App.css';

export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<AllPosts />} />
        <Route path=":slug" element={<OnePost />} />
      </Routes>
    </BrowserRouter>
  )
}

进入全屏模式 退出全屏模式

用理智优化你的 React 应用程序的 SEO

在本节中,我们将学习如何使用 Sanity 的功能通过实用技术构建一个对 seo 友好的 React 应用程序。

优化图像

正如我们之前所说,我们的网站性能对于 SEO 至关重要。图像是可能损害网站性能的资产,如果它们的格式或大小不正确。优化网站的过程可能既乏味又耗时。拥有一种自动方式至关重要,因此您最终不会花费数小时优化图像。

Sanity 拥有用于服务资产的全球内容交付网络 (CDN)。当我们上传我们的博客图片时,可以从 cdn.sanity.io 访问它们

当用户请求资产时,它由 Sanity 的后端系统处理,然后缓存在位于最终用户附近的服务器上。后续请求从缓存中提供,因此它们可以快速响应高质量的内容,而无需为每个单独的请求减慢或加载额外的资源。

让我们看一个例子。对于我下载的示例博客内容https://unsplash.com/photos/qWwpHwip31M

JPEG 格式的文件大小为 985 KB,尺寸为 5184 × 3456。我去了 Sanity Studio 并将其作为博客图片上传。在OnePost.js组件中,我们有以下内容

<img
  className="w-full h-72 rounded-lg mt-12"
  src={urlFor(post.mainImage).width(100).url()} 
  alt={post.title}
/>

进入全屏模式 退出全屏模式

正如您在 src 中看到的,我们定义了width100。这有助于我们减小文件大小和尺寸。

[屏幕截图 2022-02-08 在 17.10.32.png](https://res.cloudinary.com/practicaldev/image/fetch/s--LR3Y_9sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e84571f0-fba1-4f26-bc46-0b7ad40b196c/Screen_Shot_2022-02-08_at_17.10.32.png)

您可以在此处查看 CDN 中的文件https://cdn.sanity.io/images/a4zwcx9l/production/ffa97961aeffbde70f97ab81ece18dc80705907-5184x3456.jpg?wu003d100

标题

标题标签是用户在从搜索结果中点击进入您的网站时看到的重要 SEO 元素。这也是谷歌在确定页面内容时使用的主要因素之一,因此在此处使用相关关键字将帮助您在 SERP(搜索引擎结果页面)上排名更高。

为了能够添加标题和其他元标记,我们首先安装React Helmet

在项目的根目录在终端中运行以下命令

npm install --save react-helmet

进入全屏模式 退出全屏模式

接下来,让我们在 Sanity Studio 中添加 Meta 标题。在 Studio 中,单击发布并选择您要为其添加标题的博客。在 SEO 选项卡中,您可以填写SEO Title

最后,让我们在文件顶部导入Helmet并将 Meta 标题添加到OnePost.js组件

import React, {useState, useEffect} from 'react';
import sanityClient from '../client';
import imageUrlBuilder from '@sanity/image-url';
import { PortableText } from '@portabletext/react'
import { Helmet } from 'react-helmet';

export default function OnePost(){
            .
            .
            .
        return loading ? (
        <div>Loading...</div>
        ) : (
      <div>
        <Helmet>
          <title>{post.seoTitle}</title>
        </Helmet>
                .
                .
                .
      </div>
      )
}

进入全屏模式 退出全屏模式

描述

描述元标签是一个经常被忽视的 SEO 元素,但它会对您的点击率产生重大影响。根据谷歌的说法,这部分页面在对页面进行排名时不会被考虑在内;但是,如果您在此处使用关键字,它们将在包含它们的任何搜索中以粗体显示 - 所以请确保这些词是相关的!

接下来,让我们在 Sanity Studio 中添加元描述。在 Studio 中,单击发布并选择您要为其添加描述的博客。在 SEO 选项卡中,您可以填写 SEO 描述

[屏幕截图 2022-02-08 at 19.50.51.png](https://res.cloudinary.com/practicaldev/image/fetch/s--YWyGLmQM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2f597a5d-f29f-477a-8369-551fc9f4e5d2/Screen_Shot_2022-02-08_at_19.50.51.png)

最后让我们为OnePost.js个组件添加 Meta 描述

            .
            .
            .
import { Helmet } from 'react-helmet';

export default function OnePost(){
            .
            .
            .
      <div>
        <Helmet>
                    <title>{post.seoTitle}</title>
          <meta name="description" content={post.seoDescription} />
        </Helmet>
            .
            .
            .
      </div>
      )
}

进入全屏模式 退出全屏模式

打开图表

称为 og 是一种向 Facebook 和 Twitter 等社交媒体提供元信息的方式。它用于描述网页并告诉这些平台该页面包含哪些类型的内容,例如图像。

这些 Open Graph 标签与搜索引擎优化 (SEO) 无关,但仍然有助于在社交媒体或消息传递应用程序(如 WhatsApp 和 Telegram)上共享您的内容。

接下来,让我们在 Sanity Studio 中添加 Open graph 信息。在 Studio 中,单击发布并选择您要为其添加 og 信息的博客。在 SEO 选项卡中,您可以填写 Open Graph Title、Description 和 Image。

[屏幕截图 2022-02-08 at 20.20.26.png](https://res.cloudinary.com/practicaldev/image/fetch/s--7ReDKc6j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ad51aee2-e7fc-46e5-83cc-187e43fbd359/Screen_Shot_2022-02-08_at_20.20.26.png)

最后让我们为OnePost.js个组件添加 Open Graph 描述

            .
            .
            .
import { Helmet } from 'react-helmet';

export default function OnePost(){
            .
            .
            .
      <div>
        <Helmet>
                    <title>{post.seoTitle}</title>
                    <meta name="description" content={post.seoDescription} />
          <meta property='og:title' content={post.ogTitle} />
          <meta property='og:description' content={post.ogDescription} />
          <meta property='og:image' content={urlFor(post.ogImage).width(300).url()} />
        </Helmet>
            .
            .
            .
      </div>
      )
}

进入全屏模式 退出全屏模式

我们还能做些什么来改善我们的 SEO?

标题

标题用于组织页面内容并帮助用户理解其结构。它们还允许搜索引擎,如 Google、Bing 或 Yahoo! (实际阅读这些内容的人)知道为了访问者的方便,他们应该对您网站的哪些部分进行更重要的排名。

有 6 个不同的标题,H1 到 H6。 H1 标题应该代表您的网页关注的内容 - 它必须类似于标题标签。

标题用于组织页面上的内容并帮助用户理解其结构。它们还允许谷歌、必应或雅虎等搜索引擎! (阅读这些内容的人)知道为了方便访问者,您网站的哪些部分的重要性应该更高。

有 6 个不同的标题,H1 到 H6。 H1 标题应该代表您的网页关注的内容 - 它必须类似于标题标签。

src/components/OnePost.js组件中,我们有以下内容

<h1>
     <span className="mt-2 block text-3xl text-center leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl">
    {post.title}
     </span>
</h1>

进入全屏模式 退出全屏模式

*添加站点地图*

尽管向您的网站添加站点地图不再像以前那样重要,但它仍然是一个好主意。 Google 可以毫不费力地抓取您的网站,但添加站点地图仍然有助于确保您的所有内容都被看到。

有像react-router-sitemap-generator这样的插件可以为你做这件事。

服务器端渲染和静态站点生成

通过使用 React,我们可以构建单页应用程序。单页应用程序是加载单个 HTML 页面的应用程序,并且需要 Javascript 文件和 CSS 等必要资产才能运行该应用程序。与应用程序的任何交互只加载必要的内容,不需要重新加载页面。 SPA 与传统的 Web 应用程序相比具有更好的性能,但它可能对 SEO 具有挑战性,因为当搜索引擎抓取应用程序时,它会发现一个空的页面容器,其中没有对机器人有意义的内容,它应该等到 Javascript 加载到呈现页面内容。这可能会导致索引页面内容的延迟,或者爬虫可能会错过要索引的重要内容。

我们必须解决这个问题的最佳选择之一是使用预渲染技术提前生成 HTML 文件,而不是全部由客户端 Javascript 完成。在下面我们看到 2 个预渲染选项,React 开发人员必须改进 React SEO。

服务器端渲染 (SSR)

正如我们所说,React 网站通常是在客户端浏览器上生成的。与客户端渲染不同,SSR 背后的想法是在服务器上渲染初始 HTML 页面,而不是等待 Javascript 加载到浏览器上。所以服务器处理应用程序的初始渲染。服务器导入 React 应用程序根组件并将其呈现为 HTML 文件,并将呈现的 HTML 发送到客户端。

自己实现 SSR 是一个耗时且复杂的过程,强烈建议查看为 SSR 量身定制的next.js等 JavaScript 框架。

静态站点生成 (SSG)

SSG 与 SSR 类似,会提前生成静态 HTML 页面,而不是将其留给客户端浏览器。但是 SSG 与 SSR 之间的区别在于静态站点生成我们在构建期间生成 HTML 文件,这与在每个请求上生成 HTML 的服务器端渲染不同。我还建议查看next.js来构建 SSG React 应用程序。

结论

SEO 是确保您的网站/应用程序出现在搜索结果页面上的重要组成部分。

我们已经看到 Sanity 有很多功能可以帮助我们交付高性能的 React 应用程序,并为任何用户提供了一种方法来将重要的 SEO 元素添加到内容中,以提高在搜索引擎中的可见性和排名。

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐