NxでGatsbyサイトを管理する

Nxのプラグイン一覧には載っていないのですが、Gatsbyプラグインも公式でリリースされています。

nx gコマンドがなかなか強力なので、使ってみました。

ワークスペース / アプリの立ち上げ

create-nx-workspaceはまだGatsbyをサポートしていません。(2021/1/14時点)そのため作成時にはemptyを指定します。

$ npx create-nx-workspace --cli=nx --preset=empty

その後、手動でアプリを作成しましょう。

$ yarn add -D @nrwl/gatsby 
 
$ npx nx g @nrwl/gatsby:app <app-name> 

ディレクトリ構成

ほぼ初期状態だとこのような形です。TypeScriptデフォルトなのが個人的に結構好みでした。

% tree -L 2 apps/gatsby/
 apps/gatsby/
 ├── README.md
 ├── gatsby-browser.js
 ├── gatsby-config.js
 ├── gatsby-node.js
 ├── gatsby-ssr.js
 ├── jest.config.js
 ├── package.json
 ├── public
 │   ├── favicon-32x32.png
 │   ├── icons
 │   ├── index.html
 │   ├── manifest.webmanifest
 │   ├── page-data
 │   ├── render-page.js
 │   ├── render-page.js.map
 │   └── static
 ├── src
 │   ├── Layout.tsx
 │   ├── images
 │   └── pages
 ├── tsconfig.json
 └── tsconfig.spec.json
 7 directories, 15 files

workspace.jsonに追加されるオブジェクトはこんな感じです。build / serve / lint / testコマンドが使えるみたいですね。

{
      "root": "apps/gatsby",
      "sourceRoot": "apps/gatsby/src",
      "projectType": "application",
      "generators": {},
      "targets": {
        "build": {
          "executor": "@nrwl/gatsby:build",
          "options": {
            "outputPath": "dist/apps/gatsby",
            "uglify": true,
            "color": true,
            "profile": false
          },
          "configurations": {
            "production": {}
          }
        },
        "serve": {
          "executor": "@nrwl/gatsby:server",
          "options": {
            "buildTarget": "gatsby:build"
          },
          "configurations": {
            "production": {
              "buildTarget": "gatsby:build:production"
            }
          }
        },
        "lint": {
          "executor": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["apps/gatsby/**/*.{ts,tsx,js,jsx}"]
          }
        },
        "test": {
          "executor": "@nrwl/jest:jest",
          "options": {
            "jestConfig": "apps/gatsby/jest.config.js",
            "passWithNoTests": true
          }
        }
      }
    }

ビルドディレクトリについて

Nxで管理しているものは、だいたいdist/配下にビルド結果を出力します。が、Gatsbyについてはapp/<app_name>/publicに吐き出されるという違いがあります。

dist配下に配置したい場合、gatsby-node.jsonPostBuildイベントを使ってファイルを移動させましょう。

以下はIssueで見つけたコードをベースにNx向けに手を加えたサンプルです。workspaceJSON.projects[<app_name>].targets.build.options.outputPathになることに注意しましょう。

const path = require('path');
const fs = require('fs');

const getBuildTarget = () => {
  const workspaceJSON = require('../../workspace.json');
  if (
    workspaceJSON &&
    workspaceJSON.projects &&
    workspaceJSON.projects.gatsby &&
    workspaceJSON.projects.gatsby.targets &&
    workspaceJSON.projects.gatsby.targets.build &&
    workspaceJSON.projects.gatsby.targets.build.options &&
    workspaceJSON.projects.gatsby.targets.build.options.outputPath
  ) {
    return path.join(
      process.env.NX_WORKSPACE_ROOT,
      workspaceJSON.projects.gatsby.targets.build.options.outputPath
    );
  }
  return path.join(__dirname, 'public');
};

const target = getBuildTarget();

exports.onPreInit = () => {
  if (process.argv[2] === 'build') {
    if (fs.existsSync(target)) fs.rmdirSync(target, { recursive: true });
    if (fs.existsSync(path.join(__dirname, 'public'))) {
      fs.renameSync(
        path.join(__dirname, 'public'),
        path.join(__dirname, 'public_dev')
      );
    }
  }
};

exports.onPostBuild = () => {
  if (fs.existsSync(path.join(__dirname, 'public'))) {
    fs.renameSync(path.join(__dirname, 'public'), target);
  }
  if (fs.existsSync(path.join(__dirname, 'public_dev'))) {
    fs.renameSync(
      path.join(__dirname, 'public_dev'),
      path.join(__dirname, 'public')
    );
  }
};

Comment