Open5

SolidJS周辺エコシステムまとめ

eyemono.moeeyemono.moe

基本的には https://www.solidjs.com/ecosystemにまとまっているため、ここでは個人的によく使うものをピックアップして簡単にまとめる。
https://www.solidjs.com/ecosystem

随時更新予定

プロジェクトセットアップ

そもそもSolidJSを使ったプロジェクトを作成する場合、基本的にはViteベースのテンプレートを使用する(SSRしたい場合については後述)。主に以下の2手段が用意されている。

公式テンプレートから作成

公式のQuick startで紹介されている方法。https://github.com/solidjs/templatesにあるtemplateをdegitで持ってくる形で環境構築をする。
https://github.com/solidjs/templates

npx degit solidjs/templates/ts my-app

上記のTypeScriptテンプレートの他にも、tailwindやvitestなどを使用しているテンプレートも用意されている。

create-viteから作成

Viteの"Getting Started"で紹介されている方法。(筆者はこちらをよく使っている)

pnpm create vite my-app --template solid-ts

公式のTypeScriptテンプレートとほぼ同じ内容でプロジェクトが作成される。

必須ライブラリ

前述したテンプレート内で使用されているライブラリについて軽く触れておく。

SolidJS

https://github.com/solidjs/solid

SolidJS本体ライブラリ。一見Reactに似ているが内部実装は全くの別物。ReactはVDOMの差分計算を行って実際のDOMを更新しているが、SolidJSではSignalベースの状態管理を行いeffectやjsx内でSignalをトラッキングすることでreactivityを実現している(詳細はhttps://docs.solidjs.com/concepts/intro-to-reactivityを参照のこと)。

babel-preset-solid

https://github.com/solidjs/solid/tree/main/packages/babel-preset-solid

SolidJS用のJSX compiler Babelプラグイン。前述のセットアップ手順に従った場合、vite-plugin-solidの中でbabel-preset-solidが使用されているため、直接このプラグインを扱うことはないはず。ただし"Viteを使わずにSolidでJSXを扱いたい場合"などはこれを直接使用する(そんなことある?)。

ReactでのJSXがReact.createElementに変換されるのと異なり、SolidJSではJSXがネイティブのDOMに変換されるが、この辺りのもろもろをやってくれているのがbabel-preset-solid(の中で使用されているBabel Plugin JSX DOM Expressions)。

eyemono.moeeyemono.moe

スタイリング

公式ドキュメント:Class and style - SolidDocs

https://docs.solidjs.com/concepts/components/class-style

下記のようにinlineでのスタイリングや、cssをimportしてclassを指定する形でスタイリングが可能。

// String
<div style="color: red;">This is a red div</div>

// Object
<div style={{ color: "red" }}>This is a red div</div>

// import css
import "./card.css";
...
<div class="container">...</div>

(Viteテンプレートからプロジェクトを作成した場合)Vite自体が.scss,.sass,.less,.styl,.stylusファイルをサポートしているため、これらをimportして使用することもできる(https://ja.vitejs.dev/guide/features#css-pre-processors)。

CSS in JS系

↓jay-es氏のスクラップにも詳細にまとめられているためぜひこちらもご覧ください↓

https://zenn.dev/jay_es/scraps/ddbf3f77de57f4

vanilla-extract

https://github.com/vanilla-extract-css/vanilla-extract

ビルド時にCSSファイルを吐き出すZero-runtime css in jsライブラリ。Viteプラグインが用意されているためSolidJS+Viteなプロジェクトで使用可能(https://vanilla-extract.style/documentation/integrations/vite/)。

*.css.tsファイルにオブジェクト形式でスタイルを記述してexportし、jsx内のclassに指定して使用する。

macaron css

https://github.com/macaron-css/macaron

前述のvanilla-extractを内部で使用しているZero-runtime css in jsライブラリ。vanilla-extractではスタイルを*.css.tsの別ファイルに書いてexportする必要があったが、こちらはコンポーネントを記述したjsxファイル内に直接スタイルを記述することができる。また、styled関数を用いて直接コンポーネントを作成することが可能。

Panda CSS

https://github.com/chakra-ui/panda

ビルド時にCSSファイルを吐き出すZero-runtime css in jsライブラリ。tailwindcssのような中間ユーティリティcssが生成されるのが特徴的。SolidJSで使用可能:公式インストールガイド

classにcss関数を使ってオブジェクト記法でスタイルを書くのが基本だが、Style propsを用いて直接JSXのpropsとしてスタイルを書くことも可能。panda.config.ts内でjsxFramework: 'solid'と指定することでSolidJSのJSXでもstyle propsが使用可能。

Utility-first CSS系

tailwindcss

https://github.com/tailwindlabs/tailwindcss

言わずと知れたutility-first CSSフレームワーク。SolidJSでも使用可能で、公式のInstallガイドも用意されている。

UnoCSS

https://github.com/unocss/unocss

tailwindcssやwindicssからインスピレーションを得て作られたAtomic CSS Engine。高い柔軟性・拡張性が特徴。Viteプラグインを介してSolidJSで使用可能:https://unocss.dev/integrations/vite

eyemono.moeeyemono.moe

コンポーネントライブラリ

headless

スタイルがついておらず、主に機能のみを提供しているコンポーネントライブラリ。基本的には上述したスタイリングライブラリどれにも対応している。

Kobalte

https://github.com/kobaltedev/kobalte

SolidJS用コンポーネントライブラリ。SolidJSのみをターゲットにしたコンポーネントライブラリの中では最も人気な印象。

corvu

https://github.com/corvudev/corvu

SolidJS用コンポーネントライブラリ。まだまだ開発初期段階ではあるが、Kobalteには無いコンポーネントやutilityが提供されており、要件によってはこちらを採用するのも有りかも。

Ark UI

https://github.com/chakra-ui/ark

framework-agnosticなUI コンポーネントライブラリ。React, SolidJS, Vueで利用可能。豊富なコンポーネントが用意されている。
zagという、ステートマシーンを用いた状態管理を行っているUIライブラリをベースに作成されている。

styled

SUID

https://github.com/swordev/suid

MUIをSolidJSに移植したライブラリ。ReactからSolidJSへコードの変換を行う@suid/codemodが開発・活用されている。

SolidUI

https://github.com/sek-consulting/solid-ui

shadcn/uiのSolidJSへの非公式移植版。shadcn/uiと同様、コンポーネントライブラリではなくRe-usable componentsを自称しており、Kobaltecorvuをtailwindcssでスタイリングしたコンポーネントをコピペして利用する。CLIも用意されており、半自動でプロジェクトにコンポーネントを追加することも可能。

Park UI

https://github.com/cschroeter/park-ui

上述したArk UIを、Panda CSS/Tailwind CSSでスタイリングすることで作成されたコンポーネントライブラリ。@park-ui/cliを介してプロジェクト内にコンポーネントファイルを自動生成する。仕組み的には上述のSolidUI(というかshadcn/ui)と似ている。

eyemono.moeeyemono.moe

ユーティリティ系ライブラリ

Solid Primitives

https://primitives.solidjs.community

https://github.com/solidjs-community/solid-primitives

VueにおけるVueUseのような、便利関数群を提供しているライブラリ。
筆者は@solid-primitives/scheduled@solid-primitives/storageをよく使っている。便利。

I18n

@solid-primitives/i18n

https://primitives.solidjs.community/package/i18n

I18n用のライブラリもSolid Primitivesで提供されている。
使い方もシンプルで、i18nextなどと大差無い。

import * as i18n from "@solid-primitives/i18n";
import en from "./locales/en.js";
import ja from "./locales/ja.js";

const dictionaries = {
  en,
  ja
};

const [locale, setLocale] = createSignal<Locale>("en");

const dict = createMemo(() => i18n.flatten(dictionaries[locale()]));

export const useTranslation = () => i18n.translator(dict);

const App: Component = () => {
  const t = useTranslation();

  return (
    <div>{t("hello")}</div>
  )
}

テンプレート機能にも対応している。

const dict = {
  hello: "hello {{ name }}!",
};
const t = i18n.translator(() => dict, i18n.resolveTemplate)
t("hello", { name: "John" }); // => 'hello John!'
eyemono.moeeyemono.moe

フォームフレームワーク

Modular Forms

https://modularforms.dev

https://github.com/fabian-hiller/modular-forms

SolidJSに対応したフォームライブラリ。Qwik, Preact, Reactにも対応している。
使い方はシンプルで、大体以下の通り。

  1. フォーム内容の型を定義
  2. createFormでフォームの状態を保持するstoreを作成
  3. Fieldコンポーネントを使って入力欄を定義
  4. FormコンポーネントでonSubmitを定義
import { createForm, SubmitHandler } from '@modular-forms/solid';

type LoginForm = {
  email: string;
  password: string;
};

export default function App() {
  const [loginForm, { Form, Field }] = createForm<LoginForm>();

  const handleSubmit: SubmitHandler<LoginForm> = (values, event) => {
    // Runs on client
  };

  return (
    <Form onSubmit={handleSubmit}>
      <Field name="email">
        {(field, props) => <input {...props} type="email" />}
      </Field>
      <Field name="password">
        {(field, props) => <input {...props} type="password" />}
      </Field>
      <button type="submit">Login</button>
    </Form>
  );
}

zodまたはValibotでのバリデーションにも対応している(ModularFormsとValibotはともにFabianHiller氏によって作成されたもの)。

公式ドキュメントでKobalteを使用した際のコード例が紹介されているのもありがたい。