使用 Gatsby、Netlify 和 Contentful 进行内容管理

2025-06-04

使用 Gatsby、Netlify 和 Contentful 进行内容管理

Gatsby、Netlify 和 Contentful——内容管理成功的三重组合

我使用 Gatsby 已经快六个月了。它很快就成了我构建静态网站的首选。它的优势非常明显。你可以获得:

  • 大量配置和样板都是开箱即用的。
  • 速度、SEO 和性能优化。
  • 伟大的社区、优秀的文档、不断发展的插件生态系统。
  • 我个人最喜欢的是 - 编写我想要的所有 React 和 GraphQL 代码。

至少可以说,这是一次非常棒的开发者体验。然而,在构建静态网站时,选择工具的主要考虑因素之一是网站内容的更新方式。许多老平台已经以各种方式解决了这个问题,其中最受欢迎的是 Wordpress。但借助 Gatsby、Netlify 和 Contentful 的三重优势,我们可以构建一个相当不错的传统 CMS 工具替代方案,同时保持 SEO 兼容性。

本文将向您展示如何设置一个系统来管理 Gatsby 网站上任意页面的内容。在本例中,我们将使用 Gatsby 强大的gatsby-nodeAPI 从 Contentful 中提取内容并动态生成页面。您还可以通过提供的graphql查询在任何现有页面上使用 Contentful 数据。

让我们开始吧。

你需要这个gatsby-cli工具才能开始使用。npm i -g gatsby在终端中运行,运行完成后,创建一个新项目

$ gatsby new gatsby-contentul-blog
Enter fullscreen mode Exit fullscreen mode

这将在名为 的文件夹中创建一个新的 Gatsby 项目gatsby-contentful-blogcd进入新项目并运行gatsby develop。现在你有了默认的 Gatsby 启动主页:

用你常用的文本编辑器打开项目,然后找到pages文件夹。我们来调整一下其中的一些内容index.js:(你可以直接复制粘贴进去)

    import React from "react";
    import { Link } from "gatsby";

    import Layout from "../components/layout";
    import Image from "../components/image";
    import SEO from "../components/seo";
    import "./index.css";

    const IndexPage = () => (
      <Layout>
        <SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
        <div className="home">
          <h1>Hello There</h1>
          <p>Welcome my awesome blog</p>
          <div>
            <div
              style={{
                maxWidth: `300px`,
                margin: "0 auto 1.45rem"
              }}
            >
              <Image />
            </div>
          </div>
          <Link to="/blogposts/">View all posts</Link>
        </div>
      </Layout>
    );

    export default IndexPage;
Enter fullscreen mode Exit fullscreen mode

接下来,找到 page-2.js 并将文件名更改为 blogposts.js。Gatsby 使用 pages 文件夹中任意文件的名称作为路由名称,并使导出的 React 组件在该路由上可用。这意味着我们现在有了一个 /blogposts 路由。我们稍后会回到这个文件,但与此同时,让我们也修改一下 gatsby-config.js 文件中的几个值。该文件位于项目根目录中。

siteMetadata: {
        title: `My Awesome Blog`,
        description: `An awesome blog displaying my awesome posts.`,
        author: `YOUR_NAME`,
    },
Enter fullscreen mode Exit fullscreen mode

太棒了!我们现在已经设置好了基本的网站。接下来,我们将前往Contentful网站创建一个新帐户。整个过程非常简单,很快就能完成。他们默认提供了一个示例空间,但我们还是为项目创建一个新的吧。

打开侧边栏,点击“创建空间”。选择“免费”选项,并随意命名你的空间。我将其命名为gatsby-blog。选择“空白”选项,点击“继续确认”,然后确认你的选项。

确认后,在仪表板上,点击标题栏中的“创建内容类型”按钮或“内容模型”按钮,并填写出现的表单。我们将内容类型命名为“博客文章”,API 标识符保持不变。您可以输入任何您想要的描述。

创建内容类型后,我们将开始向其中添加一些字段。字段是我们内容的基石。例如,如果您有一篇博客文章,那么它可能包含几个字段,例如标题正文标签图片。这将生成一个表单,稍后我们开始创建实际的博客文章时您将填写该表单。按照以下步骤创建标题字段。

  • 单击仪表板右侧的添加字段按钮。
  • 选择文本作为您想要的字段类型。

  • 添加另一个字段。选择“媒体”作为类型(而不是“文本”),并将其命名为“图像”
  • 选择“文本”作为类型,添加一个标签字段。输入标签名称,然后在下方屏幕上选择“列表”选项,因为我们将在此字段中存储标签列表。

  • 最后,创建一个 slug 字段。首先选择“文本”作为类型,并将其命名为 slug。这次,不要像上面那样点击“创建”,而是点击“创建并配置”。在下一个屏幕上,转到“外观”选项卡,并选择 slug 作为字段的显示方式。此外,在“验证”选项卡中,选择“唯一字段”,以确保没有两篇博客文章具有相同的 slug。

您的内容模型现在应该如下所示:

内容模型就像我们实际内容所遵循的模式。您可以创建各种类型的模型,例如案例研究、博客文章、产品数据、页面内容等等。

保存更改,然后点击页面顶部的“内容”按钮,然后选择“添加博客文章”。我将添加三篇包含占位符数据的文章,您可以随意添加任意数量的图片。对于图片,您可以从unsplash.com获取一些免费的开放许可图片。注意到slug输入标题时字段是如何自动生成的吗?这稍后会派上用场。

太棒了!虽然有点长,但我们已经完成了一半了……

至此,我们已经完成了最初的几篇博客文章,是时候将它们导入到我们的 Gatsby 网站了。为此,我们将使用 Gatsby 强大的 GraphQL API 来提取数据。接下来,让我们开始吧。

前往 Contentful 的设置页面,点击下拉菜单中的“API 密钥”选项。创建一个新的 API 密钥,并将详细信息保存在手边。

回到您的终端,安装我们需要开始提取 Contentful 数据的 Gatsby 插件。

$ yarn add gatsby-source-contentful
Enter fullscreen mode Exit fullscreen mode

我们将使用 Contentful 的内容交付 API,因为我们只想检索已发布的数据,所以请务必获取内容交付 API密钥而不是内容预览 API 密钥

在您的gatsby-config.js文件中,将配置对象添加到plugins数组:

plugins: [
        ...
    {
      resolve: `gatsby-source-contentful`,
      options: {
        spaceId: `YOUR_SPACE_ID`,
        accessToken: `YOUR_CONTENT_DELIVERY_API_KEY`
      }
    }
],
Enter fullscreen mode Exit fullscreen mode

此时您应该重新启动开发服务器以使新配置生效。当服务器重新启动时,gatsby-source-contentful的 GraphQL 查询将可供使用。

我们可以使用 Gatsby 提供的 GraphiQL 测试环境轻松测试一切是否正常。在浏览器中打开http://localhost:8000/___graphql,并将下面的查询粘贴到页面左侧窗口中运行。查询名称是 ,allContentfulBlogPost因为我们的内容模型名为Blog Post。如果我们将其命名为ProductCase Study,那么可用的查询将是allContentfulProductallContentfulCaseStudy

{
  allContentfulBlogPost {
    edges {
      node {
        id
    slug
        title
        tags
        image {
          file {
            url
          }         
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

gatsby-source-contentful插件使用我们在文件中提供的键来处理所有来自 Contentful API 的后台获取操作gatsby-config。然后,它为我们提供了一个语义命名的 GraphQL 查询。

如果一切正常,您应该会在 GraphiQL 窗口右侧的结果窗口中以 JSON 格式看到您添加的内容。

现在我们已经将 Gatsby 博客与 Contentful 数据连接起来,可以开始构建博客页面了。Gatsby 提供了一个名为 的文件gatsby-node.js。此文件可用于动态添加页面到您的网站。Gatsby 运行时,它会查看此处的代码并创建您指定的任何页面。在此gatsby-node.js文件中,我们输入以下代码:

const path = require(`path`);
const slash = require(`slash`);

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions;
  // we use the provided allContentfulBlogPost query to fetch the data from Contentful
  return graphql(
    `
      {
        allContentfulBlogPost {
          edges {
            node {
              id
              slug
            }
          }
        }
      }
    `
  ).then(result => {
      if (result.errors) {
        console.log("Error retrieving contentful data", result.errors);
      }

      // Resolve the paths to our template
      const blogPostTemplate = path.resolve("./src/templates/blogpost.js");

      // Then for each result we create a page.
      result.data.allContentfulBlogPost.edges.forEach(edge => {
        createPage({
          path: `/blogpost/${edge.node.slug}/`,
          component: slash(blogPostTemplate),
          context: {
                        slug: edge.node.slug,
            id: edge.node.id
          }
        });
      });
    })
    .catch(error => {
      console.log("Error retrieving contentful data", error);
    });
};
Enter fullscreen mode Exit fullscreen mode

此模块导出一个名为 的函数createPages。该函数有两个参数:graphql 和一个 actions 对象。我们提取createPageaction,然后调用之前在 GraphiQL 实践中运行的 Graphql 查询。我们获取结果,并为每个结果(每篇博文)调用该createPage函数。此函数接受一个配置对象,Gatsby 会在渲染页面时读取该对象。我们将路径设置为连接后的字符串"/blogpost"加上slug。请注意,我们还引用了一个位于 的模板文件./src/templates/blogpost.js,不用担心,我们很快就会创建该文件。

此时,关闭服务器并重新启动。如果您输入了无效路由,例如,http://localhost:8000/some-non-existent-route/您将看到 Gatsby 的开发 404 页面。此页面列出了所有路由,并且您可以看到新创建的页面已设置完毕。

明白我们为什么选择使用唯一的 slug 字段了吗?每篇文章都必须有唯一的路由,使用 slug 比在 URL 中使用无意义的 ID 字符串美观得多。此外,由于 Gatsby 生成的是静态网站,可以包含站点地图,因此让路由名称与你想要排名的内容类型相匹配,对 SEO 来说更有利。

现在我们可以集中精力构建实际的页面。

templates在你的文件夹中创建一个文件夹src,并添加一个名为 的文件blogpost.js。这将是我们的模板组件,每次 Gatsby 调用文件createPage中的函数时都会使用它gatsby-node.js

注意:如果出现任何错误,请务必重启服务器。我们正在进行大量配置工作,Gatsby 可能需要重启才能正常运行。

import React from "react";
import { Link, graphql } from "gatsby";
import Layout from "../components/layout";
import SEO from "../components/seo";

const BlogPost = ({ data }) => {
  const { title, body, image, tags } = data.contentfulBlogPost;
  return (
    <Layout>
      <SEO title={title} />
      <div className="blogpost">
        <h1>{title}</h1>
        <img alt={title} src={image.file.url} />
        <div className="tags">
          {tags.map(tag => (
            <span className="tag" key={tag}>
              {tag}
            </span>
          ))}
        </div>
        <p className="body-text">{body.body}</p>
        <Link to="/blogposts">View more posts</Link>
        <Link to="/">Back to Home</Link>
      </div>
    </Layout>
  );
};

export default BlogPost;

export const pageQuery = graphql`
  query($slug: String!) {
    contentfulBlogPost(slug: { eq: $slug }) {
      title
      slug
      body {
        body
      }
      image {
        file {
          url
        }
      }
      tags
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

在页面底部,我们导出一个 Graphql 查询。Gatsby 会在运行时运行此查询,并将包含 Contentful 数据的data prop 传递给BlogPost。请注意,在本例中,我们查询的是单篇文章,并将 slug 作为过滤参数传递。我们实际上是在请求与传入的 slug ( contentfulBlogPost(slug: { eq: $slug })) 匹配的文章。这个 slug 之所以可用,是因为我们将其作为页面上下文传入了 中gatsby-config.js

剩下的就是 React 的简单易懂了。我们创建一个组件,并使用data prop 填充页面内容。目前还没有样式,但稍后我们会讲到。

我们现在需要一个页面来列出所有可用的博客文章页面。我们不能每次需要阅读博客文章时都依赖 404 页面!

让我们回到我们在该项目开始时创建的文件夹blogposts.js中的文件并对其进行调整。pages

import React from "react";
import { Link, graphql } from "gatsby";

import Layout from "../components/layout";
import SEO from "../components/seo";

const BlogPosts = ({ data }) => {
  const blogPosts = data.allContentfulBlogPost.edges;
  return (
    <Layout>
      <SEO title="Blog posts" />
            <h1>{"Here's a list of all blogposts!"}</h1>
      <div className="blogposts">
        {blogPosts.map(({ node: post }) => (
          <div key={post.id}>
            <Link to={`/blogpost/${post.slug}`}>{post.title}</Link>
          </div>
        ))}
        <span className="mgBtm__24" />
        <Link to="/">Go back to the homepage</Link>
      </div>
    </Layout>
  );
};

export default BlogPosts;

export const query = graphql`
  query BlogPostsPageQuery {
    allContentfulBlogPost(limit: 1000) {
      edges {
        node {
          id
          title
          slug
          body {
            body
          }
          image {
            file {
              url
            }
          }
          tags
        }
      }
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

现在这个模式应该很熟悉了。

在页面底部,我们导出一个 GraphQL 查询。该查询与我们gatsby-nod.js生成博客文章页面时使用的查询相同。它会提取所有BlogPost类型的 Contentful 数据。Gatsby 会像单个博客文章页面一样,将查询结果保存在数据对象中供我们使用。不过,对于此页面,我们只需要idtitleslug字段tags

现在,让我们添加一些非常基本的样式。为了方便示例,我们只在文件末尾添加几行代码layout.css,但在实际项目中,您可能不想这样做。您可以根据自己的习惯选择合适的方法。

/* Add these lines to the end of the layout.css file */
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600");
html {
  font-family: "Open Sans";
}

header {
  /* We use !important here to override
  the inline styles just for this example.
  in production code, avoid using it where
  possible*/
  background-color: cadetblue !important;
}

header div {
  text-align: center;
}

header div h1 {
  font-weight: 600;
}

.home {
  text-align: center;
}

.home img {
  margin: auto;
}

.blogpost {
  font-size: 18px;
  width: 35em;
}

h1 {
  font-weight: 400;
  margin-top: 48px;
  font-family: "Open Sans";
}

img {
  margin-bottom: 8px;
}

.tags {
  margin-bottom: 24px;
}

.tags span.tag {
  font-weight: bold;
  margin-right: 8px;
  background: cadetblue;
  padding: 2px 12px;
  border-radius: 4px;
  color: white;
  font-size: 12px;
}

.blogpost p.body-text {
  margin-bottom: 32px;
}

p {
  line-height: 1.8;
  color: #929191;
  font-weight: 300;
}

.blogpost a {
  display: block;
  margin-bottom: 8px;
}

.blogposts a {
  display: block;
  margin-bottom: 8px;
}

footer {
  margin-top: 120px;
}

.mgBtm__24 {
  display: inline-block;
  margin-bottom: 24px;
}
Enter fullscreen mode Exit fullscreen mode

现在我们有了博客,下一步就是部署它,让全世界都能看到。有了 Netlify,这超级简单。Netlify 与 GitHub 集成得非常好。在你的终端中,运行:

    $ git init
Enter fullscreen mode Exit fullscreen mode

转到您的 GitHub 并创建一个名为 的新存储库gatsby-contentful-blog-starter,然后按照命令推送到现有存储库。

    $ git add .
    $ git commit -m 'initial commit'
    $ git remote add origin git@github.com:YOUR_GITUHB_USERNAME/gatsby-contentful-blog-starter.git
    $ git push -u origin master
Enter fullscreen mode Exit fullscreen mode

将代码推送到 GitHub 后,前往Netlify并创建一个帐户。在控制面板中,点击“从 Git 创建新站点”,选择GitHub作为提供商,然后按照您觉得合适的选项完成授权流程。

接下来,从提供的列表中选择一个 repo。如果找不到我们刚刚创建的 repo,请选择在 GitHub 上配置 Netlify 应用。这将打开一个弹出窗口,允许您选择要授权用于 Netlify 的 repo。按照提示操作,直到找到 repo。选择我们的博客项目后,您将被重定向到 Netlify 部署屏幕,现在您应该能够选择gatsby-contentful-blog-starterrepo。如您所见,Netlify 知道如何构建 Gatsby 网站,因此您只需单击页面末尾的部署网站按钮即可。Netlify 只需极少的配置即可轻松运行 Gatsby 网站。您的新网站应该在几分钟内准备就绪。 还记得我们如何关闭服务器并重新启动它以获取新数据吗?好吧,我们不想每次有人在 Contenful 中添加或更改内容时都必须手动触发重新部署。解决方案是使用 Contentful 的钩子来触发 Netlify 自动重新部署我们的网站(是的,这个三人标签团队考虑了所有事情)。



这意味着您每添加一篇新博文,新的页面都会自动添加到您的博客中。此外,如果您使用了 Gatsby 站点地图插件,则在部署站点地图重新生成时,新页面也会包含在站点地图中,从而更轻松地进行关键词排名,并以最少的麻烦帮助您进行 SEO 工作。

在 Netify 上,单击“站点设置”,然后在左侧菜单中选择“构建和部署”。找到“添加构建钩子”按钮并单击它,为构建钩子命名(我使用“ contentful ”),然后单击“保存”。

现在复制buildhook url 并返回到你的 Contentful 仪表盘。点击设置下拉菜单并选择“Webhooks”。Webhooks 界面右下角已经有一个 Netlify 的模板。点击它。 在出现的表单中,添加 Netlify 构建钩子 url,然后点击“创建 Webhook”

现在回到“内容”页面并添加一篇新的博客文章。点击“发布”后,Contentful 会立即调用你提供的构建钩子函数。这会导致 Netlify 重新部署你的网站。Gatsby 会重新加载 Contentful 数据,其中包含你添加的新文章,并根据新文章创建一个新页面。

就这样!一路走来,我们终于用三个很棒的工具搭建了一个可以运行的博客,它们配合得非常好。现在,你可以添加更多内容类型和页面,扩展网站,或者从头开始一个新项目。祝你一切顺利!

附言:我知道这篇文章很长,如果你遇到任何困难,我很乐意解答你的问题。如果有问题,请在下方评论区留言,或者在 Twitter 上关注我@thebabscraig,我很乐意和你一起学习。我也希望在 Instagram 上与其他开发者联系,所以也可以在 Instagram 上关注我@thebabscraig

文章来源:https://dev.to/thebabscraig/content-management-with-gatsby-netlify-and-contentful-3kbg
PREV
您最不想遇到的 5 大 CORS 问题 什么是 CORS? 不存在访问控制允许来源标头 响应中的访问控制允许来源标头不得为通配符 * 对预检请求的响应未通过访问控制检查 响应中的访问控制允许凭据标头为“ ”,当请求凭据模式为“include”时,该标头必须为“true” 专业提示 我的应用仍然在控制台中显示 CORS 问题,但不知道哪里出了问题 总结 ✨
NEXT
From Zero to DevOps Engineer - DevOps Roadmap for YOUR specific background 🔥 What is DevOps? What is the DevOps skillset? What is YOUR zero or starting point? 🤔 Starting as a Systems Administrator 🧑🏽‍💻 Starting as a Software Developer 👩‍💻 Starting as a Test Automation Engineer👨🏼‍💻 Starting as a Network Engineer🧑🏻‍💻 DevOps Bootcamp considering these different backgrounds 💡 Starting with no or little IT background 🙉 Summary - DevOps Roadmap