なにこれ
Gatsby公式サイトのプラグインの章のまとめ。
プラグイン概要
Gatsbyプラグインは、Gatsbyの全処理を拡張および修正可能です。 例えば下記のようなことができます。
- 外部コンテンツ(CMS、ファイル、REST APIなど)を追加してGraphQLで扱えるようにする
- ファイル(Markdown、YAML、CSVなど)データをJSON形式にフォーマットする
- サードパーティーの機能(Google Analytics, Instagram)をGatsbyで作ったWebサイトに追加する
またnpmパッケージでモジュール化されているため、巨大で複雑なWebサイトでも簡潔に機能追加・管理が可能です。
公開プラグインを検索する
プラグイン一覧と個別仕様は GatsbyのPluginsで確認できます。 公式プラグインとコミュニティ提供のものをあわせると、なんと502個もあるようです。(2018/10/20現在)
プラグインの使い方
プラグインはnpmパッケージで公開されています。 まずはnpmインストールしましょう。
下記はgatsby-transformer-jsonの例
npm install --save gatsby-transformer-json
次にgatsby-config.js
のplugins
配列に追加してください。
module.exports = {
plugins: [`gatsby-transformer-json`],
}
オプションも指定できます。
下記のようにgatsby-config.js
を書き換えましょう。
module.exports = {
plugins: [
// オプションなしで指定する場合は下記のようにプラグイン名を文字列で指定しましょう。
"gatsby-plugin-react-helmet",
// オプションありの場合は、オブジェクトで指定します。
{
resolve: `gatsby-source-filesystem`,
// オプションはさらにオブジェクトで指定します。
options: {
path: `${__dirname}/src/data/`,
name: "data",
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
// プラグイン自体を拡張するプラグインを指定できます。
// その場合はオプションのpluginsにプラグインを定義しましょう。
plugins: [`gatsby-remark-smartypants`],
},
},
{
resolve: "gatsby-plugin-offline",
// 下記のように空オプションの場合は、プラグイン名を文字列で指定した場合と同じです。
options: {
plugins: [],
},
},
],
}
ローカルのプラグインを使う場合
自作プラグインなどは、npm公開せずともplugins
フォルダに配置すると使えます。
module.exports = {
plugins: [`gatsby-local-plugin`],
}
他フォルダに起きたいならフォルダパスを指定しましょう。
module.exports = {
plugins: [
{ resolve: require.resolve(`/path/to/gatsby-local-plugin`), }, ],
}
プラグインの作り方
- npmパッケージ、ローカルプラグインどちらの形式もOKです。
package.json
とgatsby-config.js
が必要です。- Gatsby API(Node、サーバーサイドレンダリング、ブラウザの3種類)を必要に応じて実装しましょう。
作成するファイル
※[必須]と記載がないものについては任意です。
- package.json --- [必須]ローカルプラグインの場合は空オブジェクトでも可。
- name GraphQLのデータ構造におけるプラグインの識別子です。未指定の時はプラグインのフォルダ名になります。
- version キャッシュ管理用です。これが変わるとキャッシュがクリアされます。未指定の時は、gatsby- *ファイルの内容のMD5ハッシュになります。ローカルプラグインを開発中の場合は、不用意なキャッシュを避けるため指定しないほうが良いでしょう。
- keywords 検索用に指定してください。ここで
gatsby
とgatsby-plugin
の2つを指定してnpm公開すると、Plugins | Gatsbyのリストに追加できます。
- 以下3ファイルはプラグインが拡張・修正したい機能に応じて作成してください。
- gatsby-browser.js -- ブラウザAPIの実装を定義します。
- gatsby-node.js -- ノードAPIの実装を定義します。
- gatsby-ssr.js -- サーバーサイドレンダリングAPIの実装を定義します。
命名規約
タイプごとに推奨する命名規約があります。
gatsby-source-*
--- 外部コンテンツ(WordPress、MongoDB、ファイル)からデータをロードするタイプの場合gatsby-transformer-*
--- データをJSON形式に変換するタイプの場合gatsby-[plugin-name]-*
--- 特定のプラグインを拡張する場合- 例: gatsby-remark-images ※gatsby-transformer-remarkを拡張するプラグイン
gatsby-plugin-*
--- 上記以外の場合
ローカルプラグイン
plugins
配下にプラグイン名のフォルダを作ります。
plugins
└── my-own-plugin
└── package.json
この状態ではプラグイン用のgatsby-config.js
を定義していないので、プロジェクトはプラグインを自動認識できません。
プロジェクトのgatsby-config.js
にプラグイン名(フォルダ名)を指定しましょう。
module.exports = {
plugins: [
'my-own-plugin',
]
}
なおプラグインのソースコードはBabelでトランスコンパイルされないので注意してください。
新しいJavaScript文法を使いたい場合はプラグインフォルダ配下にsrc
フォルダを作って配下にコード格納し、Babelでビルドした資産をプラグインフォルダ配下に出力するなどの工夫が必要です。
どういう場合にプラグインを作るか
なんでもかんでもプラグイン化するわけではありません。
JavaScriptやReact.jsの機能(ライブラリ)を追加する場合などはプラグインを作らなくてよいのです。以下に例を示します。
- 一般的な機能を提供するJavaScriptパッケージ(lodashやaxiosなど)を使う場合
- React.jsのUIライブラリ(Ant DesignやMaterial UIなど)を使う場合
- 統合可視化ライブラリ(HighchartsやD3.jsなど)を使う場合
プラグインはGatsby APIをパッケージ化して最低限の設定で済むようにするのが目的です。
例えばStyled Components
を使う場合、自分でGatsby APIを使ってサーバーサイドレンダリング対応を組み込めますが、
この対応はプラグイン化すべきです。実際これはGatsby-plugin-styled-components
というプラグインがあります。
Source PluginとTransformer Plugin
主要なプラグインのタイプの2つにSource PluginとTransformer Pluginがあり両者は連携して機能します。
例えばマークダウンファイルの場合、
Source Pluginのgatsby-source-filesystemがファイルからFileノードを供給し、Transformer Pluginのgatsby-transformer-remarkがFileノードをMarkdownRemarkノードに変換します。
なおFileノードはファイルの生の内容とメディアタイプを含みます。 メディアタイプは必須項目ではありませんが、Source Pluginで生成したノードが生データ(Transformer Plugin未処理のデータ)であることを示す手段です。 メディアタイプでSource PluginとTransformer Pluginの橋渡しを行い、データ読み込みと加工を分離することで、各プラグインを小さく保つことができるのです。
Source Pluginの作り方
npmパッケージとして作成します。package.json
とgatsby-node.js
を作りましょう。
gatsby-node.js
は下記のような感じです。
exports.sourceNodes = async ({ actions }) => {
const { createNode } = actions
// データを生成(ここではデータを外部から取得する例を示す)
const data = await fetch(REMOTE_API)
// データからノードを生成
data.forEach(datum => createNode(processDatum(datum)))
// 生成したノードをリターン
return
}
NOTE: Gatby APIの実装詳細は、sourceNodes、createNodeを参照してください。 ここでは例示していませんが、gatsby-node-helpersを使うとAPIの実装が簡単になるので記述量が大きくなるようなら、使ってみることをお勧めします。
ノード間参照を定義する
プラグインが出力するノートにおいて、ノード間の参照を定義することでより複雑な構造を定義します。 これらの実現方法は2つあります。
(1) Transformation relationships
gatsby-transformer-remark
では、Fileノードが親、MarkdownRemarkノードが子という関係を定義し、
親ノードのマークダウン文字列、子ノードでHTMLに変換しています。
これらの関係はcreateParentChildLink
を使って定義します。具体的な実装方法についてはgatsby-transformer-remarkを参照してください。
なお子ノードは親ノードからの派生なので、親ノードが削除時は全ての子ノードが削除されます。
(2) Foreign-key relationships
別々のオブジェクト(型定義も全く別々)を紐付ける方法です。
この場合Transformation relationshipsと異なり、片方のオブジェクトが削除されても関係するオブジェクトは削除されません。
Transformer Plugin
通常のNPMパッケージとして作成します。package.json
とgatsby-node.js
を作りましょう。
変換後ノードの型定義
gatsby-node.js
で変換後ノードの型定義をsetFieldsOnGraphQLNodeTypeに指定します。
exports.setFieldsOnGraphQLNodeType = require(`./extend-node-type`)
NOTE: setFieldsOnGraphQLNodeTypeの詳細はAPIリファレンス参照
キャッシュの取り扱い
変換処理はコストがかかるため、ビルドするたびに作り直さずにすむようにGatsbyのグローバルキャッシュ機能を使います。 キャッシュキーには少なくとも関連リソースのcontentDigestが必要です。 たとえば、gatsby-transformer-remarkは、HTMLノードに下記のようにキャッシュキーを指定しています。
const htmlCacheKey = node =>
`transformer-remark-markdown-html-${
node.internal.contentDigest
}-${pluginsCacheStr}-${pathPrefixCacheStr}`
キャッシュへのアクセスは下記のようにします。
const cachedHTML = await cache.get(htmlCacheKey(markdownNode))
cache.set(htmlCacheKey(markdownNode), html)
プラグインの公開方法
プラグインのpackage.jsonのkeywordにgatsby
とgatsby-plugin
をつけてnpm公開すれば、
最大12時間後にライブラリ一覧のインデックスにいったん追加されます。
その後公式サイトのデイリービルドが走ると、ようやくプラグインが一覧に追加され、
GatsbyのPluginsで見れるようになります。
NOTE: せっかく公開するなら検索しやすいようにgatsby
とgatsby-plugin
以外にもキーワードを指定しましょう。例えばMarkdown MathJax transformerは下記のように指定しています。
"keywords": [
"gatsby",
"gatsby-plugin",
"gatsby-transformer-plugin",
"mathjax",
"markdown",
]
まとめ
Gatsbyはプラグイン機構が非常に考えぬかれたスマートな形をしていますね。
機能追加時もnpmインストールしてgatsby-config.js
に設定を追加するだけなのでコードがとてもスッキリするなぁという印象でした。
プラグイン公開時も、npmパッケージでkeywordにgatsby
とgatsby-plugin
をつけるだけというシンプルさも見逃せません。
なお今回Source Plugin Tutorialのページは見ていませんが、
自作プラグインを公開する時はこのページを参考にしたいと思います🍅