型のある Rails が欲しいと思い開発を始めてから１年、TypeScript 向けフレームワークを公開しました

私は Accella という、TypeScript 向け Web フレームワークのバージョン 1.0 を 2025 年 2 月に公開しました。
この記事では Accella の簡単な紹介の後、これまでの開発内容とその設計意図などを時系列に沿って整理します。

## Accella とは

Accella は TypeScript 用サーバーサイド向けの Web アプリケーションフレームワークです。
以下に公式サイト( https://accella.dev/ja )の冒頭から特徴を抜粋します。

> - サーバーファースト
>   - 従来のフルスタック MVC フレームワークの流れを汲んだ機能実装がなされています。Astro をベースにしており、クライアントにはサーバーでレンダリング済みの HTML を返します。アーキテクチャをシンプルに保つことで、開発効率とユーザー体験を向上させます。
> - ORM との連携
>   - Active Record パターンで実装された Accel Record を ORM として採用しています。フレームワークと ORM の連携により、特にデータベースの CRUD 操作を中心とした処理の開発効率を高めます。
> - 型安全
>   - テーブル操作からテンプレートレンダリングまで、TypeScript による型安全な開発環境を提供します。

フレームワークの詳細は[公式サイト](https://accella.dev/ja)を見てみてください。アプリケーション開発時のサンプルコードや他のフレームワークとの比較なども掲載しています。

## 設計意図と経緯

時系列に沿って Accella の開発開始から公開に至るまでの経緯を整理します。特に設計の意図に関わる部分を中心にまとめています。

### ORM ライブラリの開発から開始

Accella の開発は 2024 年 1 月に始まりました。当時、私は OSS 活動に取り組んでみたいと思うと同時に「TypeScript にも Ruby on Rails くらい開発効率の高いフレームワークが欲しい」と考えていました。

ここで言う「Rails 的な開発効率の高さ」に求めていた要素は以下のようなものです

- (SPA ではなく)SSR(Server-Side Rendering)で動く MPA(Multi-Page Applications)の開発をベースとする
- RDB に対する CRUD 関連の機能を少ない記述量で実現できる
- MVC(Model-View-Controller) の領域をカバーするフレームワーク

既存のフレームワークを調査しましたが、これらの要素を十分に満たすと思えるものが見つかりませんでした。
分析を進めると、Rails の Active Record のような高機能な ORM が必要だと感じ、まず TypeScript 用の ORM の開発からプロジェクトを開始しました。

このあたりの動機については以下の記事で詳しく書いています。

[TypeScript で書ける型安全な Ruby on Rails を求め、ORM の開発を始めた - Qiita](https://qiita.com/koyopro/items/748ddd27aa32ff14c95f)

### テーブル定義とマイグレーションに Prisma を利用

ORM を開発するにあたり、テーブル定義とマイグレーションの実現方法を検討しました。

Prisma の[ジェネレーター](https://www.prisma.io/docs/orm/prisma-schema/overview/generators)機能を使うと、Prisma のテーブル定義ファイルから任意のコードを生成できることがわかりました。[Kysely](https://kysely.dev/)のようなクエリビルダーライブラリでも、必要な型定義ファイルを出力する際に Prisma ジェネレーターが利用できたりします。
そこで今回の ORM では、テーブル定義とマイグレーションを Prisma で行い、必要なファイルを Prisma ジェネレーターで自動生成する仕組みを採用しました。
Rails のマイグレーションは差分ファイルを作る方式ですが、個人的には Prisma のようにスキーマファイルから自動でマイグレーションファイルを生成する方が便利だと感じていることも理由の一つです。

### ORM への同期 API の採用

通常、JavaScript/TypeScript 向けライブラリでは DB 操作などの外部アクセスに非同期 API が使われます。しかし開発を進める中で、ORM のインターフェースを同期 API として設計した方が良いと考えるようになりました。

Promise を返す非同期 API は、`await`をつけて完了を待つ記述方法が一般的です。

```ts
const user = await User.first(); // データーベースから先頭のUserを取得する
```

非同期 API ではライブラリのインターフェースが制限され、Rails の Active Record のような使い勝手を実現するのが難しいことがわかりました。そこで、`await`をつけなくとも処理を呼び出せる同期 API を採用しました。これは ORM の開発で最も設計や実装に苦労した部分ですが、最も特徴が現れる部分でもあります。

同期 API に関する話題は以下の記事により詳細を書いているので、興味のある方は見てみてください。

- [TypeScript の新しい ORM に同期 API を採用した理由 - Qiita](https://qiita.com/koyopro/items/b11be652ee95426f244e)
- [サーバーサイド TypeScript でも、非同期処理を使わないという選択肢が必要なのではないか - Qiita](https://qiita.com/koyopro/items/2724c764181cbc60b236)
- [TypeScript で同期的に DB アクセスをするための技術 - Qiita](https://qiita.com/koyopro/items/a304b8103b2c649511aa)
- [非同期処理を同期的に実行できる JS/TS 用ライブラリを公開した - Qiita](https://qiita.com/koyopro/items/48187c95a32cc439f293)

### Accel Record として ORM を公開

2024 年 4 月に ORM ライブラリ「Accel Record」のバージョン 1.0 を公開しました。
テーブルに対する CRUD 操作を中心とする機能を実装し、同期 API に加えて、永続化前後でモデルの型が変わるなど型安全面でも特徴があります。

[Active Record パターンを採用した TypeScript 用 ORM「Accel Record」の紹介 - Qiita](https://qiita.com/koyopro/items/917c2c98db3de7518849)

その後、ORM としての機能を追加していきました。このあたりの機能も、かなり Rails の Active Record を意識しています。

- バリデーション
- ファクトリー
- バルクインサート
- シリアライズ
- トランザクション
- 国際化(I18n)
- コールバック
- PostgreSQL のサポート
- パスワード認証
- スコープ
- 高度な検索
- ロック
- 複合キーサポート
- Form オブジェクト

### レンダリングに Astro コンポーネントを利用

Rails では、Active Record が持つ情報をもとにページングやフォームを簡単に作れます。Accella でもそのような機能を実現し、さらに(Rails だと erb のような)View のテンプレートも型安全に記述できるようにしたいと思っていました。
従来のサーバーサイド JS 向けテンプレートエンジン(EJS、Pug など)ではこれは実現できなさそうでした。そこで候補に挙がってきたのが Astro です。[Astro コンポーネント](https://docs.astro.build/ja/basics/astro-components/)を利用すると、サーバーサイドのテンプレートレンダリングでも React や Vue のように型安全に記述できることがわかりました。

2024 年 8 月頃までに ORM 側の機能が充実してきたため、その後は ORM と連携してフォームを組み立てる機能等を Astro コンポーネントを使って実装しました：

- ページネーション
- フォーム
- リクエストパラメータのパース処理
- セッション管理
- CSRF 対策

### Astro へのコミット

Astro コンポーネントをテンプレートエンジンとして利用するには、Astro を Accella のベースとする必要があります。MVC(Model-View-Controller)の考え方でいうと、Model は Accella の独自 ORM が担当し、View と Controller は Astro の機能が担当する形になりました。

なので機能開発中は Astro をよく触ることになるのですが、その際に見つけた課題に対応することで Astro のコミュニティにも貢献することができました。

Rails ではデフォルトでセッション情報を cookie に保存します。Astro でもセッション情報を cookie に保存できるライブラリを作って Reddit で紹介したところ、好意的なリアクションを多くもらえました。
[I just published "Astro Cookie Session", middleware for managing sessions using cookies on Astro. : r/astrojs](https://www.reddit.com/r/astrojs/comments/1fxl8od/i_just_published_astro_cookie_session_middleware/)

その他にも Astro 本体のリポジトリに 2 件、不具合修正の Pull Request を出して取り込んでもらうことができました。

### フレームワークとしての整備

2024 年 11 月頃は、これまで作ってきた機能をフレームワークとして使えるような整備をしています。
Rails の`rails new`のように、`npm create`ですぐにアプリケーション開発を始められる環境を目指しました。

環境構築直後から開発用に SQLite を使うことや、テーブルへの読み書きを含むテストが実行できることなど、主にデータベース周りのセットアップが完了した状態になるような整備を行っています。Accella ではテストフレームワークに Vitest を利用していますが、Vitest ではマルチプロセス(またはマルチスレッド)でテストが実行されるため、複数のテスト用データベースを適切に準備するなどの工夫が必要でした。

最終的に`npm create accella`を実行するだけで、データベースを利用した開発をすぐに始められる環境を整えることができました。

### ドキュメントの整備とバージョン 1.0 公開

2025 年 1 月からは Accella のドキュメントサイトを準備し、スタートガイドの作成とともに使いづらい部分や不具合を修正していきました。
Astro Starlight で作成したドキュメントを Netlify で配信する形にしたのですが、かなり進めやすかったです。

そうして 2025 年 2 月 26 日に、Accella のバージョン 1.0 を公開しました。

こちらも Reddit で紹介を投稿したところ、多くの反応をもらうことができました。
[Introducing Accella: A Full-Stack Framework Built on Astro : r/astrojs](https://www.reddit.com/r/astrojs/comments/1j48lmd/introducing_accella_a_fullstack_framework_built/)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62874/2415e648-996e-4023-90ad-59bfb1cb7248.png" width="400" />

## 今後の開発

バージョン 1.0 を公開し、ドキュメントも整備したことで一旦は他の人にも使ってみてもらえる状態になりました。
「TypeScript にも Ruby on Rails くらい開発効率の高いフレームワークが欲しい」という当初の動機に対して、一つの方向性を作れたと思います。
特に「Active Record パターン」と「同期 API」を特徴とする ORM は、サーバーサイド JS に新しい選択肢を提供できるのではないかと考えています。

現在は、ORM のモデルと紐づけて簡単に S3 にファイルをアップロードできる、CarierWave ライクなライブラリを開発中です。

今後は以下の機能も開発したいと考えています：

- データベースの初期(シード)データを効率的に管理できる(Seed Fu ライクな)ライブラリ
- 内部向け管理画面を簡単に作成できる(Active Admin ライクな)ライブラリ

興味を持ってくれた方はリポジトリにスターをいただけると嬉しいです。
https://github.com/koyopro/accella

最後まで読んでいただき、ありがとうございました。