著者は、 Write for DOnations プログラムの一環として、 InternetArchiveを選択して寄付を受け取りました。

序章

Webサイトまたはアプリケーションを構築する場合、多くの場合、最も困難なタスクの1つは、複数のソースからデータを取得し、それを統一された出力にまとめることです。 これを解決する一般的な方法は、サイトのさまざまな部分にまったく異なるビルドシステムを使用することですが、これにより複雑さが増し、均一性の実現が困難になる場合があります。 ここで、データ駆動型の静的サイトジェネレーター(SSG)であるGatsbyがソリューションを提供できます。

Gatsbyの主要な目的の1つは、開発者にとってこの問題を解決することであり、ソースプラグインがその主な方法です。 ソースプラグインは、特定のソースからGatsbyエコシステムへのデータの取り込みを処理するコードのバンドルです。 ソースは、Markdownファイル、データベース、公開されたデータフィード、またはAPIなどの完全に動的なリモートデータソースの場合と同様に、ローカルファイルシステムから取得できます。

このチュートリアルでは、独自のカスタムソースプラグインを作成して、実際のAPIから新しいデータをGatsbyに取り込みます。 また、Gatsby全体でアクセスできるようにデータをフォーマットし、チュートリアルの終わりまでに、新しい動的データソースから静的HTMLを構築する作業プロジェクトを作成します。

前提条件

始める前に、ここにあなたが必要とするいくつかのものがあります:

  • Gatsbyを実行してサイトを構築するためのNode.jsのローカルインストール。 インストール手順はオペレーティングシステムによって異なりますが、DigitalOceanには Ubuntu20.04およびmacOSのガイドがあり、最新リリースは公式Node.jsダウンロードページ[ X213X]。
  • Gatsbyで作業するためのJavaScriptにある程度精通している。 JavaScript言語は広大なトピックですが、出発点としては、JavaScriptでコーディングする方法シリーズが適しています。
  • Web API Node.js 、およびJSONにある程度精通している。
  • gatsby-starter-defaultからの足場となる新しいGatsbyプロジェクト。 この要件を満たし、新しいGatsbyプロジェクトを最初から構築するには、最初のGatsbyWebサイトのセットアップ方法チュートリアルのステップ1を参照してください。
  • このチュートリアルで説明されている以上に投稿のユーザーインターフェイス(UI)をカスタマイズする場合は、ReactとJSX、およびHTML要素にある程度精通している必要があります。

このチュートリアルは、Node.js v14.16.1、npm v6.14.12、Gatsby v3.13.0、およびnode-fetchv2.6.2でテストされました。

ステップ1—ファイルのスキャフォールディングと依存関係のインストール

何かを構築するときの最初のステップは、常にツールとパーツを整理することです。 このステップでは、必要なファイル構造を作成し、コードが依存する依存関係をインストールすることにより、ソースプラグインの初期ビルディングブロックを配置します。

これはローカルプラグインになるため、Gatsbyプロジェクト内にディレクトリを作成して、プラグインのソースコードをルートレベルのpluginsディレクトリに保持します。 これを行うには、ファイルブラウザで手動でフォルダを作成するか、プロジェクトのルートにあるコマンドラインからmkdirコマンドを使用します。

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

注: Gatsbyプロジェクトディレクトリの外部でプラグインを開発する場合は、それを行うことができますが、Gatsbyにファイルをサイトにプルさせるにはいくつかの追加手順が必要です。 詳細については、公式のGatsbyドキュメントをご覧ください。

次に、package.jsonファイルを作成して、このディレクトリを独自の依存関係を持つaNode.jsパッケージとしてマークする必要があります。 このファイルを作成し、いくつかの必須フィールドに事前に入力するには、次のコマンドを使用します。

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

このコマンドは、新しく作成したプラグインフォルダーに移動し、npm initを使用して新しいパッケージを初期化します。 -yフラグは、このプロジェクトに関係のないいくつかの質問をスキップし、package.jsonファイルに必要最小限の値を入力します。

package.jsonが存在するようになったので、プラグインに依存関係を追加して、機能のコーディングを容易にすることができます。 次のコマンドを使用して、このチュートリアルで必要となる唯一の追加の依存関係node-fetchをインストールします。

  1. npm install [email protected]^2

最後に、ソースプラグインのメインコードを保持するgatsby-node.jsファイルを作成します。

  1. touch gatsby-node.js

注: Gatsbyプラグインを頻繁に作成している場合は、プラグインテンプレートが役立つ場合があります。

プラグインをサポートするファイル構造を作成し、初期の依存関係をインストールしたので、プラグインを見つけてロードする方法についてGatsbyに指示を与えることに移ります。

ステップ2—プラグインのロードと構成

Gatsbyプラグインまたはテーマの場合と同様に、Gatsbyは、プラグインをどこからどのようにロードするかについて指示を受ける必要があります。 これを行うには、GatsbyプロジェクトのルートにあるメインのGatsby構成ファイルgatsby-config.jsを編集します。 選択したエディターでファイルを開き、次の強調表示された行を追加します。

gatsby-config.js
module.exports = {
...
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-image`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `my-custom-source-plugin`,
    `gatsby-transformer-sharp`,
...

プラグインのソースコードはpluginsディレクトリにあるため、Gatsbyにロードさせるために必要なのは、そのフォルダ内にあるサブディレクトリの名前を渡すことだけです。 プラグインも現時点ではオプションを使用しないため、Gatsby構成ブロックでoptionsオブジェクトをプラグインに渡す必要はありません。

gatsby-config.jsを保存して、ファイルを終了します。

これで、カスタムソースプラグインをロードするようにGatsbyを構成し、実行するソースコードの場所を正確に指示しました。 次のステップでは、このソースコードを作成して、カスタムリモートソースからNode.jsランタイムにデータをプルします。

ステップ3—生データをNode.jsにプルする

前の手順では、カスタムソースプラグインのコードを読み込んで実行するようにGatsbyを構成しましたが、Gatsbyエコシステムに新しいデータを取り込むタスクを実行するには、このコードを構築する必要があります。 このステップでは、これを行うコードを記述し、node-fetchを介してリモートデータをフェッチし、将来のステップで使用できるように準備します。

ソースプラグインは、ローカルまたはリモートのほぼどこからでもデータをプルできますが、このチュートリアルでは、ソースプラグインは、ウィキペディアコンピュータープログラミングブックカテゴリから、それらのパブリックAPIを介してタイトルと抜粋を具体的にプルします。 ]。

pluginsディレクトリにあるmy-custom-source-plugin/gatsby-node.jsファイルを開き、次のコードを追加します。

plugins / my-custom-source-plugin / gatsby-node.js
const fetch = require('node-fetch').default

/**
 * Fetch a list of computer books from Wikipedia, with excerpts
 */
async function getWikiProgrammingBooks() {
  const BASE_ENDPOINT = "https://en.wikipedia.org/w/api.php?action=query&format=json&utf8=1&redirects=1";

  // Get list of books
  const listEndpoint = new URL(BASE_ENDPOINT);
  listEndpoint.searchParams.append('list', 'categorymembers');
  listEndpoint.searchParams.append("cmtitle", "Category:Computer_programming_books");
  listEndpoint.searchParams.append("cmlimit", "10");
  const listResults = await (await fetch(listEndpoint.toString())).json();


  // Extract out the page IDs from the list
  const pageIds = listResults.query.categorymembers.map((listing) => listing.pageid);

  // Fetch details for page IDs
  const extractEndpoint = new URL(BASE_ENDPOINT);
  extractEndpoint.searchParams.append("pageids", pageIds.join("|"));
  extractEndpoint.searchParams.append("prop", "extracts|info");
  extractEndpoint.searchParams.append("exintro", "");
  extractEndpoint.searchParams.append("explaintext", "");
  extractEndpoint.searchParams.append("inprop", "url");

  const bookResult = await (await fetch(extractEndpoint.toString())).json();

  return Object.values(bookResult.query.pages);
}

このコードでは、コンピュータープログラミングブックのリストを、それらのページID(Wikipedia内の一意のID)および抜粋/抜粋とともに返すために呼び出すことができる再利用可能な関数を作成しました。 関数の最初の部分では、特定のカテゴリ Computer Programming Books )に属するタイトルとIDの初期リストをフェッチするために使用する適切なAPIURLを作成します。 URLコンストラクターとインターフェイスは、クエリ文字列の変更を読みやすく管理しやすくするために使用されます。

node-fetchfetchメソッドを使用して、作成されたURLに対してGETリクエストを行います。これにより、書籍のタイトルとそのIDのリストが返されます。 その応答は、pageid値のみの配列に変換され、その後、ウィキペディアAPIを再度クエリするために使用され、今回は抽出およびメタ情報を要求します。指定されたページIDに対して生成された。 ウィキペディアAPIはこの形式を使用して、単一の文字列値を介して複数のIDを受け入れるため、ページIDはパイプ文字(|)で結合されます。

最後に、ページの抜粋の結果はオブジェクトとして返され、各書籍のリストは独自のIDでキーとしてネストされているため、Object.values()を使用してページIDキーを省略し、結果を変換しますそれらを返す前に配列に入れます。

この関数の出力をログに記録すると、次のようになります。

[
  {
    "pageid": 379671,
    "ns": 0,
    "title": "The C Programming Language",
    "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...",
    "fullurl": "https://en.wikipedia.org/wiki/The_C_Programming_Language",
    ...
  },
  ...
]

必ず変更を保存してください。ただし、次の手順でコードを追加するため、このファイルは開いたままにしてください。

この手順では、node-fetchを使用してリモートソースコンテンツを取得し、gatsby-node.jsファイル内で公開しました。 次のステップでは、コンテンツを正規化して、Gatsbyプロジェクト全体で使用する新しいGatsbyノードを作成します。

ステップ4—データの正規化とノードの作成

前の手順でリモートコンテンツを取得してgatsby-node.jsに移動したからといって、Gatsby全体でアクセスできるようになったわけではありません。 Gatsbyは、データを普遍的な方法で共有するために、ノードの概念を使用します。ノードは、統合されたGraphQLデータレイヤー間で共有されます。 このステップでは、これらのノードを作成し、それに合わせて新しいコンテンツをフォーマットします。

getWikiProgrammingBooks()を呼び出すことでウィキペディアから結果を取得してアクセスできるようになりましたが、これをGatsbyのノードシステムと統合するためのコードを追加する必要があります。 前の手順と同じgatsby-node.jsファイルに、ノードの生成を処理する次の新しいコードブロックを追加します。

plugins / my-custom-source-plugin / gatsby-node.js
const fetch = require('node-fetch').default

...

exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
  // Arbitrary node type constant
  const BOOK_TYPE = 'BookWikiPage';

  // Get books
  const bookResults = await getWikiProgrammingBooks();

  // Convert raw book results to nodes
  for (const book of bookResults) {
    actions.createNode({
      ...book,
      id: createNodeId(`${BOOK_TYPE}-${book.pageid}`),
      parent: null,
      children: [],
      internal: {
        type: BOOK_TYPE,
        contentDigest: createContentDigest(book)
      }
    })
  }
};

このコードブロックでは、getWikiProgrammingBooksによって返された各本を反復処理し、createNodeメソッドを介してそのためのGatsbyノードを作成しています。 createNodeに渡される各プロパティと値には重要性があり、検討する価値があります。

  • ...bookは、ウィキペディアAPIオブジェクトから作成中のGatsbyノードにキーと値のペアを拡散するために使用されます。 これは、book.titleからコピーされるため、後でnode.titleにアクセスできることを意味します。
  • idは、ギャツビー内でグローバルに一意の値です。 独自のプラグイン内で各書籍のIDを一意にするために、書籍の種類とWikipediaのページIDを組み合わせてID文字列を形成します。 ただし、他のプラグインが使用しているIDがわからないため、IDをcreateNodeIdに渡すというベストプラクティスを使用しました。これは、IDがグローバルに何かに変換されることを保証するGatsbyヘルパー関数です。個性的。
  • parentは、IDを介してノードを別のノードにリンクし、このノードを子としてマークするために使用できるフィールドです。 各本は独自のエンティティであり、他のノードに接続されていないため、これをnullのままにして、親がないことを示します。
  • childrenは、ノードをリンクする方法としてparentに似ていますが、IDの配列を取ります。 各本には子がないため、配列は空のままにしておきます。
  • internalは、Gatsbyの内部ノード管理システムおよびその他のプラグインに非常に固有のフィールドをグループ化するオブジェクトです。 公式フィールドのみを含めることができるため、bookオブジェクトをその中に拡散しませんでした。
  • typeは、作成しているノードのタイプを説明するグローバルに一意の文字列であり、後でGraphQLを介してノードをクエリするときに使用されます。
  • contentDigestはハッシュ文字列であり、ノードのコンテンツとGatsbycreateContentDigestヘルパーユーティリティから作成されます。 bookオブジェクトのプロパティが変更されるとハッシュ文字列が変更されるため、このフィールドは、ノードが変更されたことをGatsbyが検出するのに役立ちます。

ソースコンテンツを取得し、それを使用して新しいGatsbyノードを作成し、Gatsby環境全体で共有するコードを追加しました。 次のステップでは、これらのノードがGraphQLデータ層に表示され、クエリできることを確認します。

ステップ5—(オプション)GraphQLAPIを使用したノード出力の検査

これで、ソースコンテンツをGatsbyにプルし、それを使用して新しいノードを作成しました。 ブレークポイントまたはログステートメントを使用して手動でデバッグする代わりに、このステップでは、インタラクティブなGraphQL IDEを使用して、これらの新しいノードが作成され、GraphQLAPIでクエリできることを確認します。

Gatsbyプロジェクトのルートから次のコマンドを実行して、ローカル開発サーバーを起動します。

  1. npm run develop

注:このチュートリアルの執筆時点で、Gatsbyの依存関係チェーンの問題により、開発サーバーを起動しようとするとメッセージError: Cannot find module 'gatsby-core-utils'を返す可能性のあるエラーが発生しました。 このエラーが発生した場合は、次を実行してください。

  1. npm install gatsby-core-utils

これにより、Gatsbyコアユーティリティが再インストールされ、依存関係の問題が解決されます。 詳細については、このギャツビーエラーGitHubの問題を確認してください。

Gatsbyサイトのライブバージョンを起動することに加えて、developコマンドはローカルのGraphQLサーバーとIDEも公開します。 gatsby-node.jsのコードがすべての本のノードを作成していることを確認するには、このGraphQLクエリを使用して、本のタイトル、ページID、ギャツビーIDを取得します。

{
  allBookWikiPage {
    edges {
      node {
        title
        pageid
        id
      }
    }
  }
}

このクエリを実行するには、localhost:8000/___graphqlでインタラクティブなGraphQLIDEを開き、実行する前にクエリを左側に貼り付けるか、cURLを介してクエリを実行します。

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

応答JSONは次のようになります。

{
  "data": {
    "allBookWikiPage": {
      "edges": [
        {
          "node": {
            "title": "The C Programming Language",
            "pageid": 379671,
            "id": "818771ca-40aa-5cfd-b9e7-fddff093d5ec"
          }
        },
        ...
      ]
    }
  },
  "extensions": {}
}

新しいカスタムソースノードが作成され、GraphQLデータレイヤーでアクセス可能であることを確認したら、次のステップは、それらを使用して、サイトまたはアプリケーションの訪問者に表示されるコンテンツを作成することです。

ステップ6—(オプション)ノードに基づいてページを作成する

これまでのすべてのステップは、内部Gatsbyノードの作成に焦点を当てており、それらの作成と取得機能を検証する最後のステップも含まれています。 ただし、これらのノードは、Gatsbyプロジェクトで実行されているコードにのみ表示され、サイトやアプリケーションの訪問者には表示されません。 このステップでは、 React ページテンプレートファイルを追加してノードに接続し、ソースプラグインのコンテンツが実際の公開ウェブページに変わるようにします。

Gatsbyノードに基づいてページを作成する方法は複数ありますが、このチュートリアルでは、ファイルシステムルートAPI を使用します。これは、特別なファイル名構文に基づいてページを作成します。

まず、src/pages{BookWikiPage.title}.jsというファイル名の空のファイルを作成します。 中括弧は、ファイル名がファイルシステムルートAPIを使用していることをギャツビーに伝え、中括弧の内側にあるBookWikiPage.titleは、一意の本のタイトルごとにページを作成するようにギャツビーに伝えます。 pluginsディレクトリ内のファイルでは作業を行っていませんが、メインのGatsbyプロジェクト内で作業していることに注意してください。

次に、ブックノードを取得してWebページとして表示するコードをそのファイルに追加します。

src / pages / {BookWikiPage.title} .js
import { graphql } from "gatsby";
import * as React from "react";
import Layout from "../components/layout";
import Seo from "../components/seo";

export default function BookPageTemplate({ data: { bookWikiPage } }) {
  const { title, extract, fullurl } = bookWikiPage;
  return (
    <Layout>
      <Seo title={title} />
      <h1>{title}</h1>
      <blockquote>{extract}</blockquote>

      <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>
    </Layout>
  );
}

export const pageQuery = graphql`
  query ($id: String!) {
    bookWikiPage(id: { eq: $id }) {
      title
      extract
      fullurl
    }
  }
`;

コードの最後には、pageQueryというエクスポートされた変数があり、GatsbyGraphQLタグを使用します。 Gatsbyは、それに続く GraphQLクエリを評価し、結果をBookPageTemplate関数に渡します。

ReactコンポーネントであるBookPageTemplate関数は、GraphQLクエリの結果を取得し、値を JSX に埋め込むことにより、Webページの一部として表示します。 ]それが戻ること。 本のタイトルはページのメインの見出しとタイトルとして使用され、抜粋はブロック引用として表示され、完全なWikipediaエントリページへのリンクが下部に埋め込まれています。

また、宣言の前にexport defaultを使用して、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内でcreatePagesAPIを使用できます。

これらの新しいノードとそれに関連するページのリストを表示するには、専用のリストページも作成します。このページでは、すべての書籍が1か所に表示されます。 src/pagesの下に、books.jsというファイル名で新しいファイルを作成します。 次に、次のコードを追加します。

src / pages / books.js
import { graphql, Link } from "gatsby";
import * as React from "react";
import Layout from "../components/layout";
import Seo from "../components/seo";

export default function BookListingsPageTemplate({ data: { allBookWikiPage } }) {
  return (
    <Layout>
      <Seo title="Programming Books Listing" />
      <p>Here are some computer programming books that have their own Wikipedia entries:</p>

      {allBookWikiPage.edges.map((edge) => {
        const node = edge.node;
        return (
          <details key={node.title}>
            <summary>{node.title}</summary>

            <div className="details-body">
              <p>{node.extract}</p>
              <div className="links">
                <Link href={node.gatsbyPath}>Internal Page</Link>
                <a rel="noreferrer" href={node.fullurl}>Wikipedia Page</a>
              </div>
            </div>
          </details>
        )
      })}
    </Layout>
  );
}

export const pageQuery = graphql`
  query {
    allBookWikiPage {
      edges {
        node {
          title
          extract
          gatsbyPath(filePath: "/{BookWikiPage.title}")
          fullurl
        }
      }
    }
  }
`;

{BookWikiPage.title}.jsページテンプレートと同様に、このファイルもGraphQL pageQueryタグを使用して、GraphQLレイヤーからデータを取得し、Reactコンポーネントに渡します。 ただし、以前のテンプレートはIDに基づいて単一の本をレンダリングしましたが、このテンプレートは、以前に作成された個々の本のページにリンクしながら、すべての本のリストをレンダリングします。

各本のリストは<details>要素を使用します。これにより、リストを展開して本とリンクの完全な抜粋を表示したり、折りたたんでタイトルだけを表示したりできます。 ベストプラクティスに従って、配列を反復処理するときに、内部リンクに Gatsby Linkコンポーネントを使用し、外部リンクにaタグを使用して、keyに一意の値を渡します。

GraphQLクエリのgatsbyPath(filePath: "/{BookWikiPage.title}")文字列は、特別なgatsbyPath()関数を使用して、渡されたファイルシステムルートAPIファイル名に基づいて作成されるパブリックパスを取得します。

このファイルを保存して終了します。

注:コンポーネントのデータソースを変更すると、ホットリロード機能によって次のようなエラーが返されることがあります:error Cannot query field "gatsbyPath" on type "BookWikiPage" graphql/template-strings。 このエラーを修正するには、プロセスを終了してnpm run developを再度実行し、開発サーバーを手動で再起動します。

すべての本が1ページにあるため、折りたたみ可能なセクションでも少し混雑しているため、最後のステップは、訪問者がリストを読みやすくするためのスタイルを追加することです。 src/styles/books.cssに新しいスタイルシートファイルを作成します。 これは、ファイルブラウザで、またはGatsbyプロジェクトのルートからのコマンドラインを使用して実行できます。

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

次に、次のCSSをファイルに追加します。

src / styles / books.css
details {
  border: 1px dotted black;
  margin: 6px;
  padding: 6px;
}

.details-body {
  background-color: #eedeff;
  margin: 4px 0px 2px 12px;
  padding: 4px;
  border-radius: 4px;
}

.links {
  display: flex;
  justify-content: space-evenly;
}

このCSSは、各本のリストの周囲に境界線を追加し、リスト内の間隔と余白、および内部と外部の本のリンクの間に間隔を追加します。 CSSをファイルに追加したら、保存して閉じてから次に進みます。

最後に、書籍リストページテンプレートを更新して、このCSSファイルを次の場所にプルします。

src / pages / books.js
import { graphql, Link } from "gatsby";
import * as React from "react";
import Layout from "../components/layout";
import Seo from "../components/seo";
import "../styles/books.css";

新しく追加されたCSSインポート行を使用して、このファイルを保存して閉じます。

結果を確認するには、developコマンドを再度実行して開発サーバーを起動し、新しいページをプレビューします。

  1. npm 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サイトを作成する方法の残りの部分を確認してください。