2026年01月24日
Jクラブ経営情報ポータルを再構築 技術編
Jクラブ経営情報ポータルを具体的にどのように再構築したのかを、この記事で解説します。
プロジェクト構造を再編しました。旧サイトでは Gatsby 単体のプロジェクトとして制作していましたが、今回は Monorepo で構成しています。データ部分をパッケージとして扱い、ビルドしたパッケージを App 内でインポートする仕組みにしました。
.
├── apps
│ ├── vercel-api // APIプロジェクト (予定)
│ └── web // Next.jsプロジェクト
├── packages
│ ├── core // コアパッケージ
│ ├── data // データパッケージ
│ ├── eslint-config
│ ├── statistics // 統計パッケージ (experimental)
│ ├── typescript-config
│ └── utils // ユーティリティパッケージ
├── scripts // README.mdの自動生成などのスクリプト
├── eslint.config.mjs
├── package-lock.json
├── package.json
├── README.md
├── tsconfig.json
├── turbo.json
└── vitest.config.ts
以前のプロジェクト構造
旧サイトでは、CSVから生成した元のYAMLファイルを、GatsbyのSourceプラグインとTransformerプラグインで読み込む構成でした。Gatsby Node APIを使って読み込みの過程でデータを整形し、各ページのテンプレート内でGraphQLのクエリを用いてデータを読み込むという手順でデータ処理を行っていました。
Gatsbyが死んでいなければこの辺りも記事化できるのですが、もはや書き記す意味はないでしょう。
データパッケージ
ここでは、データパッケージの構造について簡単に書き記します。
データパッケージでは、datasetに格納された元のYAMLファイルをJSONファイルに加工・整形し、distディレクトリに出力しています。
packages/data/
├── __tests__
├── dataset // クラブ毎のYAMLファイルを格納
│ ├── albirex
│ │ ├── 2005.yml
│ │ ├── 2006.yml
│ │ ├── ...
│ │ └── 2024.yml
│ ├── antlers
│ ├── ardija
│ ├── ...
│ └── zweigen
├── dist // クラブ毎のJSONファイルを出力
│ ├── albirex
│ │ ├── 2005.json
│ │ ├── 2006.json
│ │ ├── ...
│ │ ├── 2024.json
│ │ ├── index.cjs
│ │ ├── index.d.ts
│ │ └── index.mjs
│ ├── antlers
│ ├── ardija
│ ├── ...
│ ├── zweigen
│ ├── index.cjs
│ ├── index.d.ts
│ └── index.mjs
├── scripts
├── src
├── eslint.config.mjs
├── package.json
├── tsconfig.json
├── tsdown-for-clubs.config.ts
└── tsdown.config.ts
distのルートにindexファイルを置き、各JSONファイルを読み込む関数を提供しています。
import {
getDataByClub,
getDataByYear,
} from "@cieloazul310/jclub-financial/data";
const mito = await getDataByClub("mitohollyhock");
// => Array(20) [FinancialDatum, FinancialDatum, ...]
const latest = await getDataByYear(2024);
// => Array(62) [FinancialDatum, FinancialDatum, ...]
それに加えて、クラブ毎のディレクトリにもエントリポイントとなるindexファイルを置き、クラブ単位でデータを読み込む関数も提供しています。
import { getData } from "@cieloazul310/jclub-financial/data/mitohollyhock";
const mito = await getData();
// => Array(20) [FinancialDatum, FinancialDatum, ...]
const latestDecades = await getData(2015, 2024);
// => Array(10) [FinancialDatum, FinancialDatum, ...]
内部でfsやpathを使用しているのでNode.js環境が前提になりますが、React Server Componentsでは利用可能です。
データの加工・整形と型安全性
YAMLからJSONへの加工・整形の際には、Zodを使って型安全性を担保しています。
元のファイルがYAMLなのは、旧サイトのリソースの再利用という側面もありますが、メンテナンス性を考慮してのことです。
パッケージとして配布
元のファイルがYAMLなのは、旧サイトのリソースの再利用という側面もありますが、メンテナンス性を考慮してのことです。
パッケージ名は現在、個人アカウント名である@cieloazul310のスコープを付けていますが、organizationを作成して専用のスコープを付けることも考えています。ただ、NPMのorganizationを個人で気軽に作ってよいのかわからず、躊躇しているところです。
きかいにおまかせ / 家主 (2023)
Jクラブ経営情報ポータル
Jリーグが毎年公開している「Jクラブ個別経営情報開示資料」のデータをクラブ別、年度別に表示したページ。損益計算書、貸借対照表、営業収入、営業費用、入場者数の項目別に表と解説を掲載。
https://cieloazul310.github.io/jclub-financial-table/