Forestry (TinaCMS)
Git-basedのヘッドレスCMS。JAMstackワークフローに最適化された開発者ファーストのCMS。
CMS
Forestry (TinaCMS)
概要
Forestryは、Git-basedのヘッドレスCMSとして開発者に愛されていましたが、2023年4月22日にサービスを終了し、その後継としてTinaCMSが開発されています。
詳細
Forestry.ioは、JAMstackワークフローに最適化されたGit-basedのヘッドレスCMSとして、多くの開発者に支持されていました。Gitリポジトリと直接連携し、MarkdownやYAMLファイルを管理する直感的なインターフェースを提供していました。しかし、Forestryチームは次世代のビジョンとしてTinaCMSの開発に注力することを決定し、2023年4月にForestryのサービスを終了しました。
TinaCMSは、Forestryの良い点を引き継ぎながら、より高度な機能を提供しています。特に注目すべきは、ビジュアル編集機能とTypeScriptによる型安全性です。React製のモダンなアーキテクチャを採用し、Next.jsやGatsbyなどの静的サイトジェネレータとのシームレスな統合を実現しています。GitHubやGitLabとの統合により、開発者フレンドリーなワークフローを維持しながら、非技術者でも使いやすいビジュアルエディタを提供しています。
メリット・デメリット
メリット
- Git-basedワークフロー: バージョン管理と開発フローが統合
- ビジュアル編集: リアルタイムプレビューとclick-to-edit機能
- 型安全性: TypeScriptによる完全な型サポート
- オープンソース: カスタマイズ可能でベンダーロックインなし
- モダンな開発体験: React/TypeScriptベースの最新技術スタック
- 柔軟な認証: ローカル開発とクラウド認証の両方をサポート
- GraphQL API: 効率的なデータフェッチング
デメリット
- Forestryからの移行が必要: 既存Forestryユーザーは移行作業が発生
- 学習コスト: 新しいコンセプトとAPIの習得が必要
- React専用: 他のフレームワークとの統合は限定的
- 初期設定の複雑さ: 環境構築に技術的知識が必要
- エコシステムの規模: Forestryと比べてまだ発展途上
主要リンク
- TinaCMS公式サイト
- TinaCMS Documentation
- TinaCMS GitHub
- Forestry to TinaCMS Migration Guide
- TinaCMS Community
- TinaCMS Starter Templates
使い方の例
TinaCMSプロジェクトの初期化(Forestry移行)
# 新規プロジェクト作成
npx create-tina-app@latest my-site
# 既存Forestryプロジェクトの移行
npx @tinacms/cli init
# "Migrate your .forestry folder?"に"y"と回答
# 開発サーバー起動
npm run dev
スキーマ定義(TypeScript)
// .tina/schema.ts
import { defineSchema } from "@tinacms/cli";
export default defineSchema({
collections: [
{
label: "Blog Posts",
name: "post",
path: "content/posts",
fields: [
{
type: "string",
label: "Title",
name: "title",
required: true,
},
{
type: "string",
label: "Body",
name: "body",
isBody: true,
ui: {
component: "textarea",
},
},
{
type: "reference",
label: "Author",
name: "author",
collections: ["author"],
},
],
},
],
});
データベース設定(Git Provider)
// tina/database.ts
import { createDatabase, createLocalDatabase } from "@tinacms/datalayer";
import { GitHubProvider } from "tinacms-gitprovider-github";
import { MongodbLevel } from "mongodb-level";
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === "true";
export default isLocal
? createLocalDatabase()
: createDatabase({
gitProvider: new GitHubProvider({
branch: process.env.GITHUB_BRANCH,
owner: process.env.GITHUB_OWNER,
repo: process.env.GITHUB_REPO,
token: process.env.GITHUB_PERSONAL_ACCESS_TOKEN,
}),
databaseAdapter: new MongodbLevel({
collectionName: "tinacms",
dbName: "tinacms",
mongoUri: process.env.MONGODB_URI,
}),
});
Next.jsでの統合
// pages/_app.tsx
import { TinaEditProvider } from 'tinacms/dist/edit-state'
import TinaCMS from 'tinacms'
function MyApp({ Component, pageProps }) {
return (
<TinaEditProvider
editMode={
<TinaCMS
apiURL={process.env.NEXT_PUBLIC_TINA_API_URL}
{...pageProps}
>
{(livePageProps) => <Component {...livePageProps} />}
</TinaCMS>
}
>
<Component {...pageProps} />
</TinaEditProvider>
)
}
export default MyApp
バックエンド認証設定
// pages/api/tina/[...routes].ts
import { TinaNodeBackend, LocalBackendAuthProvider } from "@tinacms/datalayer";
import { TinaAuthJSOptions, AuthJsBackendAuthProvider } from "tinacms-authjs";
import databaseClient from "../../../tina/__generated__/databaseClient";
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === "true";
const handler = TinaNodeBackend({
authProvider: isLocal
? LocalBackendAuthProvider()
: AuthJsBackendAuthProvider({
authOptions: TinaAuthJSOptions({
databaseClient: databaseClient,
secret: process.env.NEXTAUTH_SECRET,
}),
}),
databaseClient,
});
export default handler;
ビジュアル編集の実装
// components/VisualEditor.tsx
import { useTina } from 'tinacms/dist/react'
import { useVisualEditing } from '@tinacms/vercel-previews'
export const BlogPost = (props) => {
const { data: tinaData } = useTina(props)
// ビジュアル編集を有効化
const data = useVisualEditing({
data: tinaData,
query: props.query,
variables: props.variables,
enabled: true,
stringEncoding: true, // 文字列に自動的にメタデータを追加
})
return (
<article>
<h1>{data.post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.post.body }} />
</article>
)
}