【SolidStart v1.0】ついにSolidJSでフルスタック開発！

## はじめに
待ちに待った`SolidJS`のレンダリングフレームワークである`SolidStart`のバージョン1.0がリリースされました！
[SolidStart 1.0: The Shape of Frameworks to Come](https://www.solidjs.com/blog/solid-start-the-shape-frameworks-to-come)
本記事では実際に使ってみた感じから、`SolidStart`の特徴や使い方について紹介します。

## `SolidJS`とは
https://www.solidjs.com/

`SolidJS`は、Reactに似た書き方で、Reactよりも高速なレンダリングを実現するフレームワークです。`SolidJS`は過去にも記事で取り上げたのでこちらを参考にしてください。
* [次のプロジェクトSolidJSで作りませんか？](https://qiita.com/tonio0720/items/ad2c33d9bea57435f5ea)
* [ReactもSvelteも大好きな私が思うSolidJSの良いところ](https://qiita.com/tonio0720/items/c28b4d37e6ab860ea04d)

ポイントとしては、以下の通りです。
* Reactに近い書き方
* Reactに近い標準機能（lazy, ref, Portal, Suspenseなど）
* 状態に応じて直接DOMを更新することによる高パフォーマンス

## `SolidStart`とは
https://start.solidjs.com/

ReactでいうNext.jsのような、`SolidJS`にサーバーサイドレンダリングやファイルベースルーティングを提供するためのメタフレームワークが`SolidStart`です。`SolidJS`の開発者でもあるRyan Carniato氏が開発したフレームワークです。長らくベータ版として開発がされてきましたが、この度晴れて正式版（v1.0）がリリースされました。`SolidJS`単体での開発と違って、どんなことができるのかをここでは紹介できればと思います。

## `SolidStart`メリット

### フルスタック開発
`SolidStart`の最大の利点は`SolidJS`を使ってフルスタックな開発が可能になったことです。`SolidJS`はReactと比較してもパフォーマンスなどの点で様々なメリットがありますが、メタフレームワークが存在しないことが`SolidJS`を採用しない一つの理由になっていました。`SolidJS`単体でWEBアプリを作る際には、
- バックエンドの開発には別途ExpressやFastifyなどのフレームワークが必要
- SPA（シングルページアプリケーション）しか作れない（※）

などのデメリットがあります。`SolidStart`の登場により、`SolidJS`でフルスタック開発が可能になり、フロントエンドとバックエンドの統合が容易になり、レンダリングについてもCSR/SSR/SSGという選択肢が増えました。

※本筋からは少し脱線しますが、`SolidJS`単体でもhydrate APIを使うことでSSRっぽいものを作ることは可能です。

```tsx
import { hydrate } from 'solid-js/web';
import App from './App';

import './index.css';

// entry point for browser
hydrate(() => <App />, document);
```

ただし、この方法ではHMRができなかったり設定が複雑になったりするため、`SolidStart`の登場の意味は大きいです。

### 開発体験とパフォーマンスの良さ
`SolidStart`は`SolidJS`単体や他のフレームワークよりも開発体験やパフォーマンスが良くなるように設計されています。

#### ファイルベースルーティング
これはNext.jsなどでもお馴染みですが、`SolidStart`ではファイルベースルーティングを行うことが可能です。これはページを追加するたびにルーティングの処理を追加しなくても、`routes`配下のファイルが自動的にページとして認識される仕組みです。ページをネストしたり、`[id].tsx`とすることでIDなどのパラメータとして扱う動的なルーティングも可能です。

バックエンド処理についてもファイルベースルーティングを採用しており、`routes/api`配下に以下のようなファイルを記述することでAPIを簡単に作成することが可能です。

```ts
export function GET() {
  // ...
}

export function POST() {
  // ...
}

export function PATCH() {
  // ...
}

export function DELETE() {
  // ...
}
```
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start)*

#### Single-Flight Mutations
これはページのHTMLとデータを同時に配信する機能です。例えば、一覧ページから詳細ページに移動する際に、コード分割したSPAでは、
- 新しいページのHTML（JavaScript、CSS）
- ページの詳細情報

の二つのリクエストがサーバーから返却される必要があります。`SolidStart`では、これを一つのリクエストにまとめて返却してくれます。これにより通信量が最小限で済み、ページが表示されるまでの時間も短縮されます。

#### Data Loading
フルスタック開発の利点の一つとして、`SolidStart`では本来サーバーで処理するような内容も同じコンポーネントのファイルに記述することが可能です。以下の例ではサーバーからユーザーの一覧を取得し、その情報を画面に反映するという処理が一つのファイルでなされています。ここで重要なのが、`use server`というコメントで、この記述がある関数はクライアントサイドのソースには展開されません。これにより安全に、バックエンドとフロントエンドの処理を同時に記述することが可能になり開発体験が良くなります。

```tsx
import { For } from "solid-js";
import { createAsync, cache } from "@solidjs/router";

type User = { name: string; email: string };

const getUsers = cache(async () => {
  "use server";
  return store.users.list();
}, "users");

export const route = {
  load: () => getUsers(),
};

export default function Page() {
  const users = createAsync(() => getUsers());

  return <For each={users()}>{(user) => <li>{user.name}</li>}</For>;
}
```
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/)*

また`ClientOnly`というコンポーネントを使うことで、クライアントサイドのみで処理を行うことも可能です。DOM操作などを行う際にはこちらを使います。

```tsx
import { clientOnly } from "@solidjs/start";

const ClientOnlyComp = clientOnly(() => import("../ClientOnlyComp"));

function IsomorphicComp() {
  return <ClientOnlyComp />;
}
```
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/)*

#### テンプレート
`SolidStart`では簡単に開発が始められるように、テンプレートを複数提供しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272803/f62d2aec-993d-6117-f849-f18c64c6cc00.png)
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/getting-started)*

TailwindやVitestなどのモジュールが既に組み込まれた状態で開発を始めることができます。（欲を言うと、このテンプレートが複数選択できるようになるともっと良いかもしれません。）

#### その他
これ以外にもHMR（ホットモジュールリプレースメント）やPreloadなど、メタフレームワークとして基礎的な機能も備わっています。

### 柔軟性
`SolidStart`はパフォーマンスが良いだけでなく、柔軟な設定が可能になります。`SolidStart`は以下のモジュールを組み合わせて構成されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272803/1946b70c-2a9a-5cf6-4951-9dbb01eeda3b.png)
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/getting-started)*

- **Vinxi**: Viteを基盤としたバンドラーおよびサーバーランタイムで、開発環境とビルドプロセスをシンプルにします。
- **Vite**: 高速な開発サーバーとビルドツールで、リアルタイムのホットモジュールリプレースメント（HMR）を提供します。
- **Nitro**: サーバーAPIおよびプリセットを提供し、Cloudflare、Netlify、Vercelなどのプラットフォームに簡単にデプロイできます。
- **Solid Router**: 公式ルーターで、簡単にルーティングを設定できます。

`SolidStart`ではこれらのモジュールに対して設定を行うことで、開発環境やビルドプロセスをカスタマイズすることが可能です。

#### Vite
以下の方法でビルド時にプラグインなどを読み込ませることが可能です。
```ts
import { defineConfig } from "@solidjs/start/config";

export default defineConfig({
  vite: {
    // Vite options
    plugins: [],
  },
});
```
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/getting-started)*

#### Nitro
任意のデプロイ先にデプロイすることが可能です。`SolidStart`からは標準で、Netlify、Vercel、Cloudflareなどのプラットフォームにデプロイするためのプリセットが提供されています。
```ts
import { defineConfig } from "@solidjs/start/config";

export default defineConfig({
  server: {
    preset: "netlify_edge",
  },
});
```
*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/getting-started)*

#### APIフレームワーク統合
`SolidStart`ではファイルベースのAPIルーティングだけでなく、`tRPC`や`GraphQL`などのAPIフレームワークを組み込むことも可能になっています。

```ts
import { type APIEvent } from "solid-start/api";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { appRouter } from "~/lib/router";

const handler = (event: APIEvent) =>
  fetchRequestHandler({
    endpoint: "/api/trpc",
    req: event.request,
    router: appRouter,
    createContext: () => ({})
  });

export const GET = handler;

export const POST = handler;
```

*参照元: [SolidStart公式ドキュメント](https://docs.solidjs.com/solid-start/building-your-application/api-routes)*

### その他
その他にもHTMLのメタデータやルーティングの方法（ファイルルーティング以外）なども柔軟に設定が可能です。


## `SolidStart`のデメリット
`SolidStart`はまだリリースされたばかりで、各面において足りていない要素が多い印象です。

- GitHubのIssueが多い
    - [GitHub Issue](https://github.com/solidjs/solid-start/issues)
- 公式ドキュメントが分かりづらい
- エコシステムが小さいため周辺ライブラリなどは少ない
- Next.jsのような成熟したフレームワークと比較すると機能が足りない
    - next/image

## さいごに
`Next.js`がゼロコンフィグをうたっているのに対して、`SolidStart`は柔軟な設定こそが強みだと感じました。
テンプレートやプリセットを使うことで設定に必要な工数を最小限に抑えつつ、プロジェクトに合わせて柔軟に構築することが可能です。
まだまだ課題もありますが、正式版ということで実用に向けての機能は十分だと思いました。
是非次のプロジェクトの選択肢として`SolidJS`/`SolidStart`を検討してみてください。

## 参考
* [SolidJS公式サイト](https://www.solidjs.com/)
* [SolidStart公式サイト](https://start.solidjs.com/)
* [GitHubリポジトリ](https://github.com/solidjs/solid-start)
    * [ベータ版(v0.6.0)のリリースノート](https://github.com/solidjs/solid-start/releases/tag/v0.6.0)
* [SolidStart 1.0: The Shape of Frameworks to Come](https://www.solidjs.com/blog/solid-start-the-shape-frameworks-to-come)