Ataru Kodaka Site

2021-03-06

スクラッチから始めるGatsby[6] テーマ機能に切り分ける

cover image

やること

  • スターターからテーマに
  • 機能的なものとコンテンツを切り分け

src/components/*.js などの機能と、content/posts/ などのコンテンツがごっちゃになっちゃうのは 管理上イヤンなので分ける。

ディレクトリを用意

作業用ルートの下に、

  • テーマ機能を作り込むパッケージ: ./gatsby-theme-aksite
  • コンテンツを入れて実際に試す環境: ./site

の2つを作る:

作業用ルート

private: true を入れた package.json を作り、workspaces に 上記2つのディレクトリを指定:

yarn init -yp
package.json
{
  "name": "g-theme-root",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [    "site",    "gatsby-theme-aksite"  ]}

テーマディレクトリ(gatsby-theme-aksite)

作業用ルートの下にテーマディレクトリを作成し、yarn init で package.json を作り、'name' をディレクトリ名と合わせます。

mkdir gatsby-theme-aksite
cd gatsby-theme-aksite
yarn init -y 
vi package.json
gatsby-theme-aksite/package.json
{
    "name": "gatsby-theme-aksite",    ...

テスト環境ディレクトリ(site)

作業用ルートの下にテスト環境ディレクトリを作ります。 公式のシンプルなスターターを持ってくるのが一番ラクです。

cd ..
gatsby new site https://github.com/gatsbyjs/gatsby-starter-hello-world

前項と同様に "name"を変更します

site/package.json
{
    name: "site",    ....

作るテーマをプラグインとして組み込みます:

yarn workspace site add gatsby-theme-aksite
site/gatsby-config.js
module.exports = {
  plugins: [`gatsby-theme-aksite`]
}

ここまででこんな感じのツリーになります:

.
├── gatsby-theme-aksite
│   ├── node_modules
│   └── package.json
├── node_modules
├── package.json
└── site
    ├── node_modules
    └── package.json

いよいよ開発環境を立ち上げます:

yarn workspace site develop

Hello world が出ました。ここからテーマの方に機能を加えていきます。

既存スターターからの変更点

基本的には、既存スターターの

  • gatsby-*.js とsrc/ 以下を gatsby-theme-aksite に
  • content/ と static/ を site に

持っていきます。ただし、いくつか変更する必要があります:

path.resolve から require.resolve に

gatsby-node.js のテンプレートを参照する部分を、 サンプル通りに作ってると path.resolve() を使ってるはずですが、それだと テーマの方を探してくれません。なので require.resolve() に変更します。

gatsby-theme-aksite/gatbsy-node.js
const createMdxPages = ({ nodes, actions }) => {
    const { createPage } = actions
        nodes.forEach(node => {
        createPage({
            path: node.fields.slug,
            component: require.resolve(`./src/template/post-template.js`),            context: {
                slug: node.fields.slug,
            },
        })
    })

source-filesystem

ソースを拾う部分でも、__dirname でパスを指定してしまうとテーマの方しか見ないので、 その部分は取り除きます。

gatsby-theme-aksite/gatsby-config.js
module.exports = {
  plugins: [
    .....
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `posts`,
        path: `content/posts`,      }
    },

options 指定

テーマにオプションを渡す場合は、site の方の gatsby-config.js で指定します:

site/gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-theme-aksite`,
      options: {        contentPath: `content/posts-test`      }    }
  ],
}

テーマの方でそれを拾うには、gatsby-config.js で exportするのをコールバック関数とし、 それの引数として options を受け取ります:

gatsby-theme-aksite/gatsby-config.js
module.exports = (options) => {  return {
    plugins: [
      {
        resolve: `gatsby-source-filesystem`,
        options: {
          name: `posts`,
          path: options.contentPath || `content/posts`,        }
      },

参考サイト

連載記事