使用 Gatsby、Netlify 和 Contentful 进行内容管理
Gatsby、Netlify 和 Contentful——内容管理成功的三重组合
我使用 Gatsby 已经快六个月了。它很快就成了我构建静态网站的首选。它的优势非常明显。你可以获得:
- 大量配置和样板都是开箱即用的。
- 速度、SEO 和性能优化。
- 伟大的社区、优秀的文档、不断发展的插件生态系统。
- 我个人最喜欢的是 - 编写我想要的所有 React 和 GraphQL 代码。
至少可以说,这是一次非常棒的开发者体验。然而,在构建静态网站时,选择工具的主要考虑因素之一是网站内容的更新方式。许多老平台已经以各种方式解决了这个问题,其中最受欢迎的是 Wordpress。但借助 Gatsby、Netlify 和 Contentful 的三重优势,我们可以构建一个相当不错的传统 CMS 工具替代方案,同时保持 SEO 兼容性。
本文将向您展示如何设置一个系统来管理 Gatsby 网站上任意页面的内容。在本例中,我们将使用 Gatsby 强大的gatsby-node
API 从 Contentful 中提取内容并动态生成页面。您还可以通过提供的graphql
查询在任何现有页面上使用 Contentful 数据。
让我们开始吧。
你需要这个gatsby-cli
工具才能开始使用。npm i -g gatsby
在终端中运行,运行完成后,创建一个新项目
$ gatsby new gatsby-contentul-blog
这将在名为 的文件夹中创建一个新的 Gatsby 项目gatsby-contentful-blog
。cd
进入新项目并运行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;
接下来,找到 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`,
},
太棒了!我们现在已经设置好了基本的网站。接下来,我们将前往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
我们将使用 Contentful 的内容交付 API,因为我们只想检索已发布的数据,所以请务必获取内容交付 API密钥而不是内容预览 API 密钥。
在您的gatsby-config.js
文件中,将配置对象添加到plugins
数组:
plugins: [
...
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: `YOUR_SPACE_ID`,
accessToken: `YOUR_CONTENT_DELIVERY_API_KEY`
}
}
],
此时您应该重新启动开发服务器以使新配置生效。当服务器重新启动时,gatsby-source-contentful
的 GraphQL 查询将可供使用。
我们可以使用 Gatsby 提供的 GraphiQL 测试环境轻松测试一切是否正常。在浏览器中打开http://localhost:8000/___graphql,并将下面的查询粘贴到页面左侧窗口中运行。查询名称是 ,allContentfulBlogPost
因为我们的内容模型名为Blog Post。如果我们将其命名为Product或Case Study,那么可用的查询将是allContentfulProduct
或allContentfulCaseStudy
。
{
allContentfulBlogPost {
edges {
node {
id
slug
title
tags
image {
file {
url
}
}
}
}
}
}
该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);
});
};
此模块导出一个名为 的函数createPages
。该函数有两个参数:graphql 和一个 actions 对象。我们提取createPage
action,然后调用之前在 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
}
}
`;
在页面底部,我们导出一个 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
}
}
}
}
`;
现在这个模式应该很熟悉了。
在页面底部,我们导出一个 GraphQL 查询。该查询与我们gatsby-nod.js
生成博客文章页面时使用的查询相同。它会提取所有BlogPost类型的 Contentful 数据。Gatsby 会像单个博客文章页面一样,将查询结果保存在数据对象中供我们使用。不过,对于此页面,我们只需要id
、title
和slug
字段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;
}
现在我们有了博客,下一步就是部署它,让全世界都能看到。有了 Netlify,这超级简单。Netlify 与 GitHub 集成得非常好。在你的终端中,运行:
$ git init
转到您的 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
将代码推送到 GitHub 后,前往Netlify并创建一个帐户。在控制面板中,点击“从 Git 创建新站点”,选择GitHub作为提供商,然后按照您觉得合适的选项完成授权流程。
接下来,从提供的列表中选择一个 repo。如果找不到我们刚刚创建的 repo,请选择在 GitHub 上配置 Netlify 应用。这将打开一个弹出窗口,允许您选择要授权用于 Netlify 的 repo。按照提示操作,直到找到 repo。选择我们的博客项目后,您将被重定向到 Netlify 部署屏幕,现在您应该能够选择gatsby-contentful-blog-starter
repo。如您所见,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