如何在 Gatsby 中创建自定义源插件

_作者选择了 Internet Archive以作为 Write for Donations计划的一部分接收捐款。

介绍

在构建一个网站或应用程序时,最困难的任务往往是从多个来源提取数据并将其合并到一个统一的输出中。解决此问题的一种常见方法是为网站的不同部分使用完全不同的构建系统,但这有时会增加复杂性,同时使统一性更难实现。

盖茨比的核心目标之一是为开发人员解决这个问题,源插件是它做的主要方式。 source plugin 是一个代码包,处理从给定的来源将数据带入盖茨比生态系统。

在本教程中,您将建立自己的自定义源插件,从真实世界的API将新数据带入Gatsby,您还将格式化数据,以便可以访问整个Gatsby,并在教程结束时,有一个工作项目,从您的新动态数据源中构建静态HTML。

前提条件

在开始之前,这里有一些你需要的东西:

  • 当地安装Node.js,用于运行Gatsby并建设你的站点。 安装程序因操作系统而异,但DigitalOcean有Ubuntu 20.04macOS的指南,您总是可以在官方节点.js下载页上找到最新的发布. *一些熟悉的JavaScript,在加兹比工作. JavaScript语言是一个可扩展的话题,但好的起步点是我们[JavaScript中的How To Code (https://www.digitalocean.com/community/tutorial_series/how-to-code-in-javascript)系列.
  • 对网络APIsNode.jsJSON有些熟悉。
  • 一个新的Gatsby项目,由`gatsby-starter-default'制取。 为了满足这一要求,并从零开始建设新的Gatsby项目,您可以参考[如何设置您的第一个Gatsby网站] (https://andsky.com/tech/tutorials/how-to-set-up-your-first-gatsby-website) 教程中的步骤1 .
  • 如果您想要自定义您职位的用户界面(UI),超出本教程所涵盖的范围,则需要熟悉反应和JSX以及HTML元素. .

本教程已在 Node.js v14.16.1, npm v6.14.12, Gatsby v3.13.0 和 'node-fetch' v2.6.2 上测试。

步骤 1 — 扫描文件和安装依赖

在构建某些东西时,第一步是始终把你的工具和零部件排序起来. 在这个步骤中,你将通过创建必要的文件结构和安装你的代码将依赖的依赖性来设置源插件的初始构建块。

由于这将是一个本地插件,在您的Gatsby项目中创建一个目录,以便将插件的源代码保存在根级‘插件’目录中。

1mkdir -p plugins/my-custom-source-plugin

注意:如果您想在Gatsby项目目录之外开发您的插件,您可以这样做,但需要一些额外的步骤来让Gatsby将文件拖入您的网站。

接下来,您需要创建一个 package.json 文件,将该目录标记为 Node.js 包 具有自己的依赖性。

1cd plugins/my-custom-source-plugin
2npm init -y

此命令导航到您新创建的插件文件夹,然后使用npm init来初始化新包. -y 旗帜跳过了对该项目不相关的某些问题,并用最低要求的值填写了package.json 文件。

现在 package.json 已经存在,你可以将依赖性添加到你的插件中,这将使编码功能更容易。 继续安装你在本教程中所需的唯一额外依赖性, node-fetch,使用以下命令:

1npm install node-fetch@^2

最后,创建gatsby-node.js文件,最终将包含源插件的主要代码:

1touch gatsby-node.js

注意:如果您经常构建 Gatsby 插件,您可能会发现 他们的插件模板有帮助。

现在你已经创建了支持你的插件的文件结构,并安装了最初的依赖,你将继续向Gatsby提供如何找到和加载你的插件的指示。

步骤 2 – 加载和配置插件

与任何Gatsby插件或主题一样,Gatsby必须被指示从哪里和如何下载插件. 要做到这一点,您可以编辑Gatsby的主要配置文件 gatsby-config.js,该文件位于您的Gatsby项目的根部。

 1[label gatsby-config.js]
 2module.exports = {
 3...
 4  plugins: [
 5    `gatsby-plugin-react-helmet`,
 6    `gatsby-plugin-image`,
 7    {
 8      resolve: `gatsby-source-filesystem`,
 9      options: {
10        name: `images`,
11        path: `${__dirname}/src/images`,
12      },
13    },
14    `my-custom-source-plugin`,
15    `gatsby-transformer-sharp`,
16...

由于您的插件的源代码生活在插件目录中,所有需要让盖茨比加载的都是通过子目录的名称,在那里它可以在该文件夹中找到。

保存gatsby-config.js并退出文件。

您现在已经配置了 Gatsby 来加载自定义源插件,并告诉它具体在哪里找到它应该执行的源代码。

第3步:将原始数据拖入Node.js

在之前的步骤中,您配置了Gatsby来加载和执行自定义源插件的代码,但您仍然需要构建此代码来完成将新数据带入Gatsby生态系统的任务。

源插件可以从几乎任何地方提取数据,无论是本地还是远程,但在本教程中,您的源插件将专门从 维基百科的 计算机编程书籍 类别中提取标题和摘要,通过 他们的公共API)。

在您的插件目录中打开my-custom-source-plugin/gatsby-node.js文件,并添加以下代码:

 1[label plugins/my-custom-source-plugin/gatsby-node.js]
 2const fetch = require('node-fetch').default
 3
 4/**
 5 * Fetch a list of computer books from Wikipedia, with excerpts
 6 */
 7async function getWikiProgrammingBooks() {
 8  const BASE_ENDPOINT = "https://en.wikipedia.org/w/api.php?action=query&format=json&utf8=1&redirects=1";
 9
10  // Get list of books
11  const listEndpoint = new URL(BASE_ENDPOINT);
12  listEndpoint.searchParams.append('list', 'categorymembers');
13  listEndpoint.searchParams.append("cmtitle", "Category:Computer_programming_books");
14  listEndpoint.searchParams.append("cmlimit", "10");
15  const listResults = await (await fetch(listEndpoint.toString())).json();
16
17  // Extract out the page IDs from the list
18  const pageIds = listResults.query.categorymembers.map((listing) => listing.pageid);
19
20  // Fetch details for page IDs
21  const extractEndpoint = new URL(BASE_ENDPOINT);
22  extractEndpoint.searchParams.append("pageids", pageIds.join("|"));
23  extractEndpoint.searchParams.append("prop", "extracts|info");
24  extractEndpoint.searchParams.append("exintro", "");
25  extractEndpoint.searchParams.append("explaintext", "");
26  extractEndpoint.searchParams.append("inprop", "url");
27
28  const bookResult = await (await fetch(extractEndpoint.toString())).json();
29
30  return Object.values(bookResult.query.pages);
31}

在此代码中,您创建了一个可重复使用的功能,可以调用以返回计算机编程书籍列表,连同他们的页面ID(维基百科中唯一的ID)和节录/摘录. 在函数的第一部分,您会建立正确的API URL,用于获取标题和ID的初始列表属于特定类别 (计算机编程书 ). [URL构建器和接口] (https://developer.mozilla.org/en-US/docs/Web/API/URL)用于使修改查询字符串更加可读和可管理.

您使用 [node- faction] (https://www.npmjs.com/package/node-fetch ) 的 fetch 方法向构建的 URL 请求GET , URL 返回带有其身份的书名列表 。 然后,该答复变成仅仅是`pageid'值的[阵 (https://andsky.com/tech/tutorials/understanding-arrays-in-javascript),随后用于再次查询维基百科API,这次请求为给定的页面ID生成摘录meta info. 页面ID由管字符(QQ)相接,因为维基百科API使用此格式通过单一字符串值接受多个ID.

最后,由于页面摘要的结果返回为 object,每个书籍列表都嵌入其自己的ID作为密钥,您可以使用Object.values()省略页面ID密钥,然后将结果转换为数组,然后返回它们。

如果你要登录这个函数的输出,它会看起来像这样:

 1[
 2  {
 3    "pageid": 379671,
 4    "ns": 0,
 5    "title": "The C Programming Language",
 6    "extract": "The C Programming Language (sometimes termed K&R, after its authors' initials) is a computer programming book written by Brian Kernighan and Dennis Ritchie...",
 7    "fullurl": "https://en.wikipedia.org/wiki/The_C_Programming_Language",
 8    ...
 9  },
10  ...
11]

请确保保存您的更改,但保持这个文件打开,因为您将在下一步添加更多的代码。

在此步骤中,您使用node-fetch来获取远程源内容并将其暴露在gatsby-node.js文件中。

第4步:数据正常化和节点创建

在上一步中提取远程内容并将其带入gatsby-node.js并不意味着它现在可以在整个Gatsby中访问;为了以通用方式共享数据,Gatsby使用( nodes 的概念)(https://www.gatsbyjs.com/docs/reference/graphql-data-layer/node-interface/),这些内容在 统一的GraphQL数据层之间共享。

虽然你现在可以通过拨打getWikiProgrammingBooks()来获取和访问维基百科的结果,但你仍然需要添加代码来整合它与Gatsby的节点系统(https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/)。

 1[label plugins/my-custom-source-plugin/gatsby-node.js]
 2const fetch = require('node-fetch').default
 3
 4...
 5
 6exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
 7  // Arbitrary node type constant
 8  const BOOK_TYPE = 'BookWikiPage';
 9
10  // Get books
11  const bookResults = await getWikiProgrammingBooks();
12
13  // Convert raw book results to nodes
14  for (const book of bookResults) {
15    actions.createNode({
16      ...book,
17      id: createNodeId(`${BOOK_TYPE}-${book.pageid}`),
18      parent: null,
19      children: [],
20      internal: {
21        type: BOOK_TYPE,
22        contentDigest: createContentDigest(book)
23      }
24    })
25  }
26};

在这个代码块中,你正在重复getWikiProgrammingBooks返回的每本书,并通过createNode方法(https://www.gatsbyjs.com/docs/reference/config-files/actions/# createNode)为其创建一个Gatsby节点。

*.book'用于从您创建的维基百科 API 对象中的密钥值对 [扩展] (https://andsky.com/tech/tutorials/understanding-destructuring-rest-parameters-and-spread-syntax-in-javascript# spread)。 这意味着以后您可以访问Node.title',因为它将从`book.title'复制。

  • " id " 是盖茨比内部全球独特的价值。 为了让每本书的ID在自己插件中独有,您正在将书型与维基百科的页面ID合并,形成ID字符串. 然而,由于你无法确定其他插件使用的ID是什么,所以你采用了将ID传递给"创建NodeId"的最佳做法,这是一种Gatsby的帮助器功能,可以确保ID转化为全球独有的东西.
  • " 父母 " 是指可以用来通过身份证将节点与另一个节点连接起来,将这个节点标为儿童。 由于每本书都是自己的实体,与其他节点没有联系,所以你把本作`null',表示本作没有父母。
  • " 儿童 " 与 " 父母 " 相似,是连接节点的一种方式,但需要一系列身份证。 由于每本书都没有孩子,所以你让阵列空了.
  • 内部是一个将高度适合Gatsby内部节点管理系统和其他插件的字段组合在一起的对象。 它只能包含正式字段,这就是为什么你没有将 " 书 " 对象撒入其中。 *`类型'是一个全球独特的字符串,它描述了您正在创建的节点类型,以后通过GraphQL查询节点时将使用.
  • ContentDigest'是一个散列字符串,由节点和Gatsbycreate ContentDigest'的辅助工具所建。 此字段帮助Gatsby检测节点改变时, 因为如果修改了 book 对象的任何属性, 散列会改变 。 .

您刚刚添加了代码,该代码将收集您的源内容,并与其创建新的Gatsby节点,在Gatsby环境中共享它们。

步骤 5 — (可选) 使用 GraphQL API 检查节点输出

到目前为止,您已经将源内容拖到Gatsby中,并使用它来创建新的节点. 作为手动调试突破点或日志声明的替代方法,在此步骤中,您将使用交互式GraphQL IDE来验证这些新的节点正在创建并可以通过GraphQL API进行查询。

继续运行并启动本地开发服务器,从您的 Gatsby 项目的根源运行此命令:

1npm run develop

注意: 在写本教程时,Gatsby 的依赖链出现了错误,在尝试启动开发服务器时可能会返回错误:找不到gatsby-core-utils模块的消息。

1npm install gatsby-core-utils

这将重新安装 Gatsby 核心实用程序,并解决依赖问题. 有关此问题的更多信息,请参阅 GitHub 问题此 Gatsby 错误

除了启动您的Gatsby网站的实时版本外,开发命令还暴露了本地的GraphQL服务器和IDE。 要验证在gatsby-node.js中的代码正在创建所有图书节点,您将使用此GraphQL查询来获取图书标题、页面ID和Gatsby ID:

 1{
 2  allBookWikiPage {
 3    edges {
 4      node {
 5        title
 6        pageid
 7        id
 8      }
 9    }
10  }
11}

要运行此查询,要么在localhost:8000/___graphql 打开交互式 GraphQL IDE,然后在执行之前将查询粘贴到左侧,要么通过 cURL 查询:

1curl --location --request POST 'http://localhost:8000/___graphql' \
2--header 'Content-Type: application/json' \
3--data-raw '{
4    "query": "{ allBookWikiPage { edges { node { title pageid id } } } }"
5}'

答案 JSON将看起来像这样:

 1{
 2  "data": {
 3    "allBookWikiPage": {
 4      "edges": [
 5        {
 6          "node": {
 7            "title": "The C Programming Language",
 8            "pageid": 379671,
 9            "id": "818771ca-40aa-5cfd-b9e7-fddff093d5ec"
10          }
11        },
12        ...
13      ]
14    }
15  },
16  "extensions": {}
17}

验证了您的新自定义源节点已创建并可在 GraphQL 数据层中访问,下一步是使用它们为网站或应用程序的访问者创建可见的内容。

步骤 6 — (可选) 基于节点创建页面

到目前为止,所有之前的步骤都专注于创建内部Gatsby节点,包括验证它们的创建和可检索的最后一步. 然而,这些节点仅可见于您的Gatsby项目中运行的代码,而不是您的网站或应用程序的访问者。

基于Gatsby节点创建页面有几种方法,但对于本教程,您将使用File System Route API(https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/),基于特殊的文件名语法创建页面。

首先,在src/pages中创建一个空的文件,其文件名为{BookWikiPage.title}.js。 弯曲的夹子告诉盖茨比,该文件名正在使用 File System Route API,而在夹子里,BookWikiPage.title告诉盖茨比为每个独特的书籍标题创建一个页面。

接下来,将代码添加到该文件中,该文件将取代图书节点,并将其显示为网页:

 1[label src/pages/{BookWikiPage.title}.js]
 2import { graphql } from "gatsby";
 3import * as React from "react";
 4import Layout from "../components/layout";
 5import Seo from "../components/seo";
 6
 7export default function BookPageTemplate({ data: { bookWikiPage } }) {
 8  const { title, extract, fullurl } = bookWikiPage;
 9  return (
10    <Layout>
11      <Seo title={title} />
12      <h1>{title}</h1>
13      <blockquote>{extract}</blockquote>
14
15      <i>This article uses material from the Wikipedia article <a href={fullurl} target="_blank" rel="noreferrer">"{title}"</a>, which is released under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share-Alike License 3.0</a>.</i>
16    </Layout>
17  );
18}
19
20export const pageQuery = graphql`
21  query ($id: String!) {
22    bookWikiPage(id: { eq: $id }) {
23      title
24      extract
25      fullurl
26    }
27  }
28`;

在代码的末尾有一个导出变量,名为「pageQuery」,它使用了 Gatsby GraphQL 标签.Gatsby 将评估随后的 GraphQL 查询并将结果传递到「BookPageTemplate」函数。

BookPageTemplate函数是 React 组件,然后将 GraphQL 查询的结果显示为网页的一部分,将这些值嵌入到它返回的 JSX中。本书的标题被用作页面的主要标题和标题,摘要被显示为块引用,并在底部嵌入完整维基百科入口页面的链接。

您还将BookPageTemplate函数标记为默认导出,使用导出默认在其声明之前,因为Gatsby预计会找到负责生产最终渲染页面的React组件,作为每个页面模板文件的默认导出。

将 React 模板代码添加到文件中后,保存更改并关闭它. 导航到 http://localhost:8000/the-c-programming-language/ 以显示样本页面:

Screenshot showing a book listing page generated for "The C Programming Language"

<$>[注] 注: 对于基于节点创建网页的更多手动方法,您可以使用gatsby-node.js内部的CreatePages API(https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/# createPages)。

要显示这些新节点及其相关页面的列表,您还将创建一个专用列表页面,该页面将显示所有书籍在一个位置。在src/pages下方,创建一个名为books.js的新文件。

 1[label src/pages/books.js]
 2import { graphql, Link } from "gatsby";
 3import * as React from "react";
 4import Layout from "../components/layout";
 5import Seo from "../components/seo";
 6
 7export default function BookListingsPageTemplate({ data: { allBookWikiPage } }) {
 8  return (
 9    <Layout>
10      <Seo title="Programming Books Listing" />
11      <p>Here are some computer programming books that have their own Wikipedia entries:</p>
12
13      {allBookWikiPage.edges.map((edge) => {
14        const node = edge.node;
15        return (
16          <details key={node.title}>
17            <summary>{node.title}</summary>
18
19            <div className="details-body">
20              <p>{node.extract}</p>
21              <div className="links">
22                <Link href={node.gatsbyPath}>Internal Page</Link>
23                <a rel="noreferrer" href={node.fullurl}>Wikipedia Page</a>
24              </div>
25            </div>
26          </details>
27        )
28      })}
29    </Layout>
30  );
31}
32
33export const pageQuery = graphql`
34  query {
35    allBookWikiPage {
36      edges {
37        node {
38          title
39          extract
40          gatsbyPath(filePath: "/{BookWikiPage.title}")
41          fullurl
42        }
43      }
44    }
45  }
46`;

类似于{BookWikiPage.title}.js 页面模板,此文件还使用 GraphQL `pageQuery' 标签从 GraphQL 层中提取数据并将其传输到 React 组件中。

每个书籍列表使用一个<细节>元素,这允许列表扩展以显示书籍和链接的完整摘要,或崩溃以显示仅标题。

GraphQL 查询中的 gatsbyPath(filePath: "/{BookWikiPage.title}") 字符串使用特殊的 gatsbyPath() 函数来检索基于传输的 File System Route API 文件名而创建的公共路径。

保存和退出此文件。

注意:在更改组件的数据源时,热重加功能有时会返回如下错误: error 无法在键入BookWikiPage graphql/template-strings 的gatsbyPath`查询字段。

所有的书在一个页面上,即使有可崩溃的部分,事情已经变得有点拥挤,所以最后一步是添加一些风格,让游客更容易阅读列表。在src/styles/books.css创建一个新的风格表文件。你可以在你的文件浏览器中或从你的Gatsby项目的根部使用命令行:

1mkdir -p ./src/styles
2touch ./src/styles/books.css

接下来,将以下 CSS添加到文件中:

 1[label src/styles/books.css]
 2details {
 3  border: 1px dotted black;
 4  margin: 6px;
 5  padding: 6px;
 6}
 7
 8.details-body {
 9  background-color: #eedeff;
10  margin: 4px 0px 2px 12px;
11  padding: 4px;
12  border-radius: 4px;
13}
14
15.links {
16  display: flex;
17  justify-content: space-evenly;
18}

此 CSS 添加了围绕每个图书列表的边界,在列表中的间隔和边界,以及内部和外部图书链接之间的间隔。

最后,更新图书列表页面模板以将此 CSS 文件拖入:

1[label src/pages/books.js]
2import { graphql, Link } from "gatsby";
3import * as React from "react";
4import Layout from "../components/layout";
5import Seo from "../components/seo";
6import "../styles/books.css";

使用新添加的 CSS 导入行保存和关闭此文件。

要查看结果,请再次运行开发命令,将开发服务器带上并预览新页面:

1npm run develop

您现在可以访问您的书籍列表页面在`localhost:8000/books/``。

Screenshot showing the book listings page, using the template file in the tutorial. Each section can be expanded to show the excerpt and links or collapsed to show just the title.

您现在不仅从头开始构建了一个Gatsby源插件,还使用它来基于React模板生成页面。

结论

通过遵循本教程中的步骤,您现在已经完成了创建一个自定义源插件,将外部内容带入您的Gatsby项目,并使用它来为您的网站提供新页面。

如果您对遵循最佳实践和学习更先进的源代码插件概念感兴趣,这里有一些可能对您感兴趣的领域:

如果您想了解更多关于 Gatsby 的信息,请参阅 如何使用 Gatsby.js 系列创建静态 Web 站点的其余部分。

Published At
Categories with 技术
comments powered by Disqus