はじめに
待ちに待ったSolidJS
のレンダリングフレームワークであるSolidStart
のバージョン1.0がリリースされました!
SolidStart 1.0: The Shape of Frameworks to Come
本記事では実際に使ってみた感じから、SolidStart
の特徴や使い方について紹介します。
SolidJS
とは
SolidJS
は、Reactに似た書き方で、Reactよりも高速なレンダリングを実現するフレームワークです。SolidJS
は過去にも記事で取り上げたのでこちらを参考にしてください。
ポイントとしては、以下の通りです。
- Reactに近い書き方
- Reactに近い標準機能(lazy, ref, Portal, Suspenseなど)
- 状態に応じて直接DOMを更新することによる高パフォーマンス
SolidStart
とは
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っぽいものを作ることは可能です。
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を簡単に作成することが可能です。
export function GET() {
// ...
}
export function POST() {
// ...
}
export function PATCH() {
// ...
}
export function DELETE() {
// ...
}
参照元: SolidStart公式ドキュメント
Single-Flight Mutations
これはページのHTMLとデータを同時に配信する機能です。例えば、一覧ページから詳細ページに移動する際に、コード分割したSPAでは、
- 新しいページのHTML(JavaScript、CSS)
- ページの詳細情報
の二つのリクエストがサーバーから返却される必要があります。SolidStart
では、これを一つのリクエストにまとめて返却してくれます。これにより通信量が最小限で済み、ページが表示されるまでの時間も短縮されます。
Data Loading
フルスタック開発の利点の一つとして、SolidStart
では本来サーバーで処理するような内容も同じコンポーネントのファイルに記述することが可能です。以下の例ではサーバーからユーザーの一覧を取得し、その情報を画面に反映するという処理が一つのファイルでなされています。ここで重要なのが、use server
というコメントで、この記述がある関数はクライアントサイドのソースには展開されません。これにより安全に、バックエンドとフロントエンドの処理を同時に記述することが可能になり開発体験が良くなります。
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公式ドキュメント
またClientOnly
というコンポーネントを使うことで、クライアントサイドのみで処理を行うことも可能です。DOM操作などを行う際にはこちらを使います。
import { clientOnly } from "@solidjs/start";
const ClientOnlyComp = clientOnly(() => import("../ClientOnlyComp"));
function IsomorphicComp() {
return <ClientOnlyComp />;
}
参照元: SolidStart公式ドキュメント
テンプレート
SolidStart
では簡単に開発が始められるように、テンプレートを複数提供しています。
参照元: SolidStart公式ドキュメント
TailwindやVitestなどのモジュールが既に組み込まれた状態で開発を始めることができます。(欲を言うと、このテンプレートが複数選択できるようになるともっと良いかもしれません。)
その他
これ以外にもHMR(ホットモジュールリプレースメント)やPreloadなど、メタフレームワークとして基礎的な機能も備わっています。
柔軟性
SolidStart
はパフォーマンスが良いだけでなく、柔軟な設定が可能になります。SolidStart
は以下のモジュールを組み合わせて構成されています。
参照元: SolidStart公式ドキュメント
- Vinxi: Viteを基盤としたバンドラーおよびサーバーランタイムで、開発環境とビルドプロセスをシンプルにします。
- Vite: 高速な開発サーバーとビルドツールで、リアルタイムのホットモジュールリプレースメント(HMR)を提供します。
- Nitro: サーバーAPIおよびプリセットを提供し、Cloudflare、Netlify、Vercelなどのプラットフォームに簡単にデプロイできます。
- Solid Router: 公式ルーターで、簡単にルーティングを設定できます。
SolidStart
ではこれらのモジュールに対して設定を行うことで、開発環境やビルドプロセスをカスタマイズすることが可能です。
Vite
以下の方法でビルド時にプラグインなどを読み込ませることが可能です。
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
vite: {
// Vite options
plugins: [],
},
});
参照元: SolidStart公式ドキュメント
Nitro
任意のデプロイ先にデプロイすることが可能です。SolidStart
からは標準で、Netlify、Vercel、Cloudflareなどのプラットフォームにデプロイするためのプリセットが提供されています。
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
server: {
preset: "netlify_edge",
},
});
参照元: SolidStart公式ドキュメント
APIフレームワーク統合
SolidStart
ではファイルベースのAPIルーティングだけでなく、tRPC
やGraphQL
などのAPIフレームワークを組み込むことも可能になっています。
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公式ドキュメント
その他
その他にもHTMLのメタデータやルーティングの方法(ファイルルーティング以外)なども柔軟に設定が可能です。
SolidStart
のデメリット
SolidStart
はまだリリースされたばかりで、各面において足りていない要素が多い印象です。
- GitHubのIssueが多い
- 公式ドキュメントが分かりづらい
- エコシステムが小さいため周辺ライブラリなどは少ない
- Next.jsのような成熟したフレームワークと比較すると機能が足りない
- next/image
さいごに
Next.js
がゼロコンフィグをうたっているのに対して、SolidStart
は柔軟な設定こそが強みだと感じました。
テンプレートやプリセットを使うことで設定に必要な工数を最小限に抑えつつ、プロジェクトに合わせて柔軟に構築することが可能です。
まだまだ課題もありますが、正式版ということで実用に向けての機能は十分だと思いました。
是非次のプロジェクトの選択肢としてSolidJS
/SolidStart
を検討してみてください。