SolidJS アドオン&エコシステム最新事情

SolidJS は 2025 年において、React の代替として注目を集める軽量で高性能な JavaScript フレームワークです。きめ細かなリアクティビティシステムと優れたパフォーマンスで、多くの開発者から支持されています。
この記事では、SolidJS のエコシステムの現状から、状態管理、ルーティング、UI コンポーネント、開発ツールまで、2024 年から 2025 年にかけての最新動向を詳しくご紹介します。SolidJS を導入検討中の方や、既存プロジェクトの拡張を考えている方に役立つ情報をお届けいたします。
SolidJS エコシステムの現状
SolidJS エコシステムは急速な成長を遂げており、2024 年には重要な転換点を迎えました。React や Vue ほど大きくはないものの、活発なコミュニティと継続的な開発により、実用的なライブラリが充実してきています。
エコシステムの成長状況
mermaidflowchart TD
community[SolidJSコミュニティ] --> hackathon[SolidHack ハッカソン]
community --> fellowship[Solid Fellowship プログラム]
hackathon --> components[コンポーネントライブラリ開発]
fellowship --> devtools[開発ツール整備]
fellowship --> docs[ドキュメント改善]
components --> kobalte[Kobalte]
components --> hope[Hope UI]
components --> solid_ui[Solid UI]
devtools --> debugger[Solid Rewind]
devtools --> browser_ext[ブラウザ拡張機能]
SolidJS コミュニティは、OpenCollective を通じて SolidHack ハッカソンを 2 回開催し、不足していたエコシステムの部分を補完しました。また、Solid Fellowship プログラムにより、開発ツールやドキュメント整備に資金を提供しています。
2025 年の位置づけ
現在の SolidJS は、以下の特徴により注目されています。
項目 | 詳細 |
---|---|
パフォーマンス | 直接的な DOM 更新により、React より高速なレンダリング |
TypeScript 対応 | 標準で TypeScript をサポート |
バンドルサイズ | コンパイル時最適化により小さなバンドルサイズ |
学習コスト | React ライクな構文で習得しやすい |
状態管理アドオン
SolidJS の状態管理は、内蔵されたリアクティブプリミティブが中心となっています。外部ライブラリに依存することなく、効率的な状態管理を実現できます。
Solid Signal Store
SolidJS の状態管理の核となるのが、createSignal を中心としたリアクティブシステムです。
javascriptimport { createSignal, createEffect } from 'solid-js';
// 基本的なSignalの使用
const [count, setCount] = createSignal(0);
// リアクティブな計算値
const doubled = () => count() * 2;
// 副作用の定義
createEffect(() => {
console.log(`カウント: ${count()}, 2倍値: ${doubled()}`);
});
このコードでは、count の値が変更されるたびに、doubled と createEffect が自動的に再実行されます。
Solid Context
複数コンポーネント間での状態共有には、Solid Context を活用します。
typescriptimport {
createContext,
useContext,
createSignal,
} from 'solid-js';
import type { ParentComponent } from 'solid-js';
// コンテキストの型定義
interface AppContextType {
user: () => string;
setUser: (name: string) => void;
}
// コンテキストの作成
const AppContext = createContext<AppContextType>();
typescript// プロバイダーコンポーネントの実装
const AppProvider: ParentComponent = (props) => {
const [user, setUser] = createSignal('');
return (
<AppContext.Provider value={{ user, setUser }}>
{props.children}
</AppContext.Provider>
);
};
// コンテキストを使用するコンポーネント
const UserProfile = () => {
const context = useContext(AppContext);
return (
<div>
<p>ユーザー名: {context?.user()}</p>
<button
onClick={() => context?.setUser('新しいユーザー')}
>
ユーザー変更
</button>
</div>
);
};
外部状態管理ライブラリとの連携
SolidJS は、既存の状態管理ライブラリとの連携も可能です。
typescript// Zustandライクなストア実装例
import { createSignal } from 'solid-js';
interface CounterStore {
count: () => number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
const createCounterStore = (): CounterStore => {
const [count, setCount] = createSignal(0);
return {
count,
increment: () => setCount((c) => c + 1),
decrement: () => setCount((c) => c - 1),
reset: () => setCount(0),
};
};
図で理解できる要点:
- Signal ベースの状態管理で依存関係を自動追跡
- Context を使った階層的な状態共有
- 外部ライブラリとの柔軟な連携
ルーティングソリューション
SolidJS のルーティングは、@solidjs/router を中心に発展しており、2024 年には大幅な機能拡張が行われました。
Solid Router v2 の最新機能
2024 年にリリースされた Solid Router v2 では、以下の新機能が追加されました。
typescriptimport { Router, Route, A } from '@solidjs/router';
import { lazy } from 'solid-js';
// 遅延ロードコンポーネント
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const UserProfile = lazy(
() => import('./pages/UserProfile')
);
typescript// ルーターの基本設定
const App = () => {
return (
<Router>
<nav>
<A href='/'>ホーム</A>
<A href='/about'>概要</A>
<A href='/user/123'>ユーザー</A>
</nav>
<Route path='/' component={Home} />
<Route path='/about' component={About} />
<Route path='/user/:id' component={UserProfile} />
</Router>
);
};
ファイルベースルーティング
SolidStart と組み合わせることで、Next.js ライクなファイルベースルーティングが利用できます。
rubysrc/
routes/
index.tsx // '/' にマップ
about.tsx // '/about' にマップ
user/
[id].tsx // '/user/:id' にマップ
profile.tsx // '/user/profile' にマップ
typescript// src/routes/user/[id].tsx
import { useParams } from '@solidjs/router';
export default function UserDetail() {
const params = useParams();
return (
<div>
<h1>ユーザーID: {params.id}</h1>
<p>ユーザーの詳細情報を表示します</p>
</div>
);
}
動的ルーティングの実装
動的ルーティングでは、パラメータやクエリストリングを効率的に処理できます。
typescriptimport {
useParams,
useSearchParams,
} from '@solidjs/router';
import { createResource } from 'solid-js';
const ProductDetail = () => {
const params = useParams();
const [searchParams] = useSearchParams();
// 動的データの取得
const [product] = createResource(
() => params.id,
async (id) => {
const response = await fetch(`/api/products/${id}`);
return response.json();
}
);
return (
<div>
<h1>{product()?.name}</h1>
<p>カテゴリ: {searchParams.category || 'なし'}</p>
</div>
);
};
mermaidsequenceDiagram
participant User as ユーザー
participant Router as SolidRouter
participant Component as コンポーネント
participant API as APIサーバー
User->>Router: /user/123?tab=profile
Router->>Component: パラメータ解析
Component->>API: ユーザーデータ取得
API->>Component: JSONレスポンス
Component->>User: レンダリング完了
この図は、動的ルーティングでのデータフローを示しています。ユーザーがアクセスすると、ルーターがパラメータを解析し、コンポーネントが必要なデータを取得してレンダリングします。
UI コンポーネントライブラリ
SolidJS の UI エコシステムは 2024 年に大きく成熟し、様々な用途に対応したコンポーネントライブラリが登場しました。
Solid UI
Solid UI は、Kobalte と Tailwind CSS を組み合わせた美しいデザインのコンポーネントライブラリです。
bashyarn add @solid-ui/core @solid-ui/components
typescriptimport {
Button,
Card,
TextField,
} from '@solid-ui/components';
import { createSignal } from 'solid-js';
const LoginForm = () => {
const [email, setEmail] = createSignal('');
const [password, setPassword] = createSignal('');
const handleSubmit = (e: Event) => {
e.preventDefault();
console.log('ログイン:', email(), password());
};
return (
<Card class='max-w-md mx-auto p-6'>
<h2 class='text-2xl font-bold mb-4'>ログイン</h2>
<form onSubmit={handleSubmit} class='space-y-4'>
<TextField
label='メールアドレス'
value={email()}
onInput={(e) => setEmail(e.currentTarget.value)}
type='email'
required
/>
<TextField
label='パスワード'
value={password()}
onInput={(e) =>
setPassword(e.currentTarget.value)
}
type='password'
required
/>
<Button
type='submit'
variant='primary'
class='w-full'
>
ログイン
</Button>
</form>
</Card>
);
};
Kobalte
Kobalte は、アクセシビリティを重視した低レベルコンポーネントライブラリです。WAI-ARIA ガイドラインに完全準拠しています。
bashyarn add @kobalte/core
typescriptimport { Button, Dialog } from '@kobalte/core';
import { createSignal } from 'solid-js';
const ConfirmDialog = () => {
const [isOpen, setIsOpen] = createSignal(false);
return (
<>
<Button.Root onClick={() => setIsOpen(true)}>
削除
</Button.Root>
<Dialog.Root open={isOpen()} onOpenChange={setIsOpen}>
<Dialog.Portal>
<Dialog.Overlay class='dialog-overlay' />
<Dialog.Content class='dialog-content'>
<Dialog.Title class='dialog-title'>
確認
</Dialog.Title>
<Dialog.Description class='dialog-description'>
この操作は元に戻せません。本当に削除しますか?
</Dialog.Description>
<div class='dialog-buttons'>
<Dialog.CloseButton class='button button-secondary'>
キャンセル
</Dialog.CloseButton>
<Button.Root class='button button-danger'>
削除実行
</Button.Root>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
</>
);
};
Hope UI
Hope UI は、Chakra UI ライクなデザインシステムを提供する包括的なコンポーネントライブラリです。
bashyarn add @hope-ui/solid
typescriptimport {
HopeProvider,
Box,
SimpleGrid,
Card,
CardHeader,
CardBody,
Text,
Badge,
} from '@hope-ui/solid';
const ProductGrid = () => {
const products = [
{
id: 1,
name: 'ノートパソコン',
price: 89800,
category: 'PC',
},
{
id: 2,
name: 'マウス',
price: 2980,
category: 'アクセサリ',
},
{
id: 3,
name: 'キーボード',
price: 12800,
category: 'アクセサリ',
},
];
return (
<HopeProvider>
<SimpleGrid
columns={{ base: 1, md: 2, lg: 3 }}
spacing={4}
>
{products.map((product) => (
<Card key={product.id} variant='elevated'>
<CardHeader>
<Text size='lg' fontWeight='bold'>
{product.name}
</Text>
<Badge colorScheme='info'>
{product.category}
</Badge>
</CardHeader>
<CardBody>
<Text
fontSize='2xl'
color='green.500'
fontWeight='bold'
>
¥{product.price.toLocaleString()}
</Text>
</CardBody>
</Card>
))}
</SimpleGrid>
</HopeProvider>
);
};
カスタムコンポーネントライブラリ構築
独自のデザインシステムを構築する場合の基本的なアプローチです。
typescript// components/Button/Button.tsx
import { splitProps, JSX } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import './Button.css';
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
as?: keyof JSX.IntrinsicElements;
children: JSX.Element;
}
export const Button = (
props: ButtonProps &
JSX.ButtonHTMLAttributes<HTMLButtonElement>
) => {
const [local, others] = splitProps(props, [
'variant',
'size',
'as',
'children',
'class',
]);
const classes = () => {
const baseClasses = 'btn';
const variantClass = `btn--${
local.variant || 'primary'
}`;
const sizeClass = `btn--${local.size || 'md'}`;
const customClass = local.class || '';
return `${baseClasses} ${variantClass} ${sizeClass} ${customClass}`;
};
return (
<Dynamic
component={local.as || 'button'}
class={classes()}
{...others}
>
{local.children}
</Dynamic>
);
};
図で理解できる要点:
- Solid UI は美しいデザインと使いやすさを両立
- Kobalte はアクセシビリティ重視の低レベルプリミティブを提供
- Hope UI は包括的なデザインシステムを実現
開発ツール&ユーティリティ
SolidJS の開発体験を向上させるツール群が 2024 年に大きく進歩しました。
Solid DevTools
Solid DevTools は、SolidJS アプリケーションのデバッグを支援するブラウザ拡張機能です。
typescript// 開発環境でのDevToolsセットアップ
import { render } from 'solid-js/web';
import { DEV } from 'solid-js';
if (DEV) {
// DevToolsの初期化
import('solid-devtools').then(({ attachDevtools }) => {
attachDevtools();
});
}
render(() => <App />, document.getElementById('root')!);
DevTools の主な機能:
機能 | 説明 |
---|---|
コンポーネントツリー | リアルタイムでコンポーネント階層を表示 |
Signal 追跡 | Signal の値変更を時系列で追跡 |
パフォーマンス監視 | レンダリング回数と実行時間を計測 |
State Inspector | 現在の状態を詳細に検査 |
Vite プラグイン
SolidJS の Vite プラグインには、開発効率を向上させる機能が豊富に含まれています。
javascript// vite.config.js
import { defineConfig } from 'vite';
import solid from 'vite-plugin-solid';
export default defineConfig({
plugins: [
solid({
// Hot Module Replacement の設定
hot: true,
// TypeScript の型チェック
typescript: true,
// 開発サーバー用の設定
dev: true,
}),
],
server: {
port: 3000,
open: true,
},
build: {
target: 'esnext',
},
});
TypeScript サポート強化
SolidJS 2.0 では、TypeScript サポートがさらに強化されました。
typescript// 厳密な型定義の例
import { Component, JSX, createSignal } from 'solid-js';
interface User {
id: number;
name: string;
email: string;
}
interface UserListProps {
users: User[];
onUserSelect: (user: User) => void;
}
const UserList: Component<UserListProps> = (props) => {
const [selectedId, setSelectedId] = createSignal<
number | null
>(null);
const handleUserClick = (user: User): void => {
setSelectedId(user.id);
props.onUserSelect(user);
};
return (
<div class='user-list'>
{props.users.map((user) => (
<div
key={user.id}
class={`user-item ${
selectedId() === user.id ? 'selected' : ''
}`}
onClick={() => handleUserClick(user)}
>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
))}
</div>
);
};
typescript// ジェネリクス型を使った再利用可能なコンポーネント
interface ListProps<T> {
items: T[];
renderItem: (item: T, index: number) => JSX.Element;
keyExtractor: (item: T) => string | number;
}
function List<T>(props: ListProps<T>): JSX.Element {
return (
<div class='list-container'>
{props.items.map((item, index) => (
<div
key={props.keyExtractor(item)}
class='list-item'
>
{props.renderItem(item, index)}
</div>
))}
</div>
);
}
mermaidflowchart LR
dev[開発者] --> vite[Vite + Solid Plugin]
vite --> hmr[HMR]
vite --> typecheck[TypeScript Check]
vite --> devtools[Solid DevTools]
hmr --> browser[ブラウザ]
typecheck --> ide[IDE/エディタ]
devtools --> debugger[デバッグ情報]
browser --> feedback[即座のフィードバック]
ide --> errors[型エラー検出]
debugger --> insight[パフォーマンス分析]
この開発フローでは、Vite プラグインが中心となって、HMR、型チェック、デバッグツールを連携させ、効率的な開発環境を提供します。
メタフレームワーク
SolidJS のメタフレームワークは、2024 年 5 月の SolidStart 1.0 リリースにより大きな転換点を迎えました。
SolidStart
SolidStart 1.0 は、Next.js の SolidJS 版として位置づけられる包括的なメタフレームワークです。
bash# SolidStartプロジェクトの作成
yarn create solid-start my-app
cd my-app
yarn dev
SolidStart の基本的なプロジェクト構造:
arduinomy-app/
src/
routes/
index.tsx
about.tsx
api/
users.ts
components/
Header.tsx
app.tsx
entry-client.tsx
entry-server.tsx
vite.config.ts
app.config.ts
Solid App Router
SolidStart は内蔵の App Router を提供し、ファイルベースルーティングを実現します。
typescript// src/routes/blog/[slug].tsx
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
interface BlogPost {
title: string;
content: string;
publishedAt: string;
}
export default function BlogPost() {
const params = useParams();
const [post] = createResource(
() => params.slug,
async (slug): Promise<BlogPost> => {
const response = await fetch(`/api/posts/${slug}`);
if (!response.ok) {
throw new Error('記事が見つかりません');
}
return response.json();
}
);
return (
<article>
<h1>{post()?.title}</h1>
<time>{post()?.publishedAt}</time>
<div innerHTML={post()?.content} />
</article>
);
}
typescript// src/routes/api/posts/[slug].ts
import { APIEvent } from '@solidjs/start/server';
export async function GET({ params }: APIEvent) {
const { slug } = params;
// データベースから記事を取得
const post = await getPostBySlug(slug);
if (!post) {
return new Response('記事が見つかりません', {
status: 404,
});
}
return new Response(JSON.stringify(post), {
headers: {
'Content-Type': 'application/json',
},
});
}
async function getPostBySlug(slug: string) {
// 実際のデータベース操作
return {
title: `記事: ${slug}`,
content: '<p>記事の内容</p>',
publishedAt: new Date().toISOString(),
};
}
SSR/SSG 対応状況
SolidStart は、Server-Side Rendering と Static Site Generation の両方をサポートしています。
typescript// SSRでのデータ取得
import { createResource } from 'solid-js';
import { isServer } from 'solid-js/web';
export default function HomePage() {
const [data] = createResource(async () => {
if (isServer) {
// サーバー側でのデータ取得
const response = await fetch(
'http://localhost:3000/api/data'
);
return response.json();
} else {
// クライアント側でのデータ取得
const response = await fetch('/api/data');
return response.json();
}
});
return (
<div>
<h1>ホームページ</h1>
<div>データ: {JSON.stringify(data())}</div>
</div>
);
}
javascript// app.config.ts - SSG設定
import { defineConfig } from '@solidjs/start/config';
export default defineConfig({
ssr: true,
prerender: {
routes: [
'/',
'/about',
'/blog/first-post',
'/blog/second-post',
],
},
server: {
experimental: {
islands: true, // アイランドアーキテクチャのサポート
},
},
});
mermaidstateDiagram-v2
[*] --> Build
state "SSR\nssr: true" as SSR
state "SSG\nprerender: true" as SSG
state "SPA\nssr: false" as SPA
Build --> SSR
Build --> SSG
Build --> SPA
SSR --> ServerRendering
SSG --> StaticGeneration
SPA --> ClientRendering
ServerRendering --> Hydration
StaticGeneration --> OptionalHydration
ClientRendering --> [*]
Hydration --> Interactive
OptionalHydration --> Interactive
Interactive --> [*]
この状態図は、SolidStart の様々なレンダリング戦略を示しています。設定に応じて、SSR、SSG、SPA のいずれかを選択でき、それぞれ適切なハイドレーション戦略が適用されます。
テスト環境
SolidJS のテスト環境は 2024 年に大幅に改善され、実用的なテストツールが充実しました。
Solid Testing Library
Solid Testing Library は、React Testing Library にインスパイアされたテストユーティリティです。
bashyarn add -D @solidjs/testing-library @testing-library/jest-dom
typescript// __tests__/Counter.test.tsx
import {
render,
fireEvent,
screen,
} from '@solidjs/testing-library';
import '@testing-library/jest-dom';
import { Counter } from '../src/components/Counter';
describe('Counter Component', () => {
test('初期値が0で表示される', () => {
render(() => <Counter />);
expect(
screen.getByText('カウント: 0')
).toBeInTheDocument();
});
test('増加ボタンをクリックするとカウントが増える', async () => {
render(() => <Counter />);
const incrementButton = screen.getByText('増加');
fireEvent.click(incrementButton);
expect(
screen.getByText('カウント: 1')
).toBeInTheDocument();
});
test('減少ボタンをクリックするとカウントが減る', async () => {
render(() => <Counter initialValue={5} />);
const decrementButton = screen.getByText('減少');
fireEvent.click(decrementButton);
expect(
screen.getByText('カウント: 4')
).toBeInTheDocument();
});
});
typescript// テスト対象のCounterコンポーネント
import { createSignal } from 'solid-js';
interface CounterProps {
initialValue?: number;
}
export const Counter = (props: CounterProps) => {
const [count, setCount] = createSignal(
props.initialValue || 0
);
return (
<div>
<p>カウント: {count()}</p>
<button onClick={() => setCount((c) => c + 1)}>
増加
</button>
<button onClick={() => setCount((c) => c - 1)}>
減少
</button>
</div>
);
};
Vitest との統合
Vitest は SolidJS プロジェクトで推奨されるテストランナーです。
javascript// vitest.config.js
import { defineConfig } from 'vitest/config';
import solid from 'vite-plugin-solid';
export default defineConfig({
plugins: [solid()],
test: {
environment: 'jsdom',
setupFiles: ['./src/test-setup.ts'],
globals: true,
},
});
typescript// src/test-setup.ts
import '@testing-library/jest-dom';
typescript// __tests__/api.test.ts
import { describe, it, expect, vi } from 'vitest';
import { createResource } from 'solid-js';
// APIフェッチ関数のテスト
describe('API Functions', () => {
it('ユーザーデータを正しく取得する', async () => {
const mockUser = { id: 1, name: 'テストユーザー' };
// fetchをモック
global.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockUser),
});
const [user] = createResource(async () => {
const response = await fetch('/api/users/1');
return response.json();
});
// リソースの解決を待つ
await new Promise((resolve) => {
const checkResolved = () => {
if (user.state === 'ready') {
resolve(user());
} else {
setTimeout(checkResolved, 10);
}
};
checkResolved();
});
expect(user()).toEqual(mockUser);
expect(fetch).toHaveBeenCalledWith('/api/users/1');
});
});
E2E テストソリューション
Playwright や Cypress を使用した E2E テストの設定例です。
bashyarn add -D @playwright/test
typescript// e2e/example.spec.ts
import { test, expect } from '@playwright/test';
test('ホームページが正しく表示される', async ({ page }) => {
await page.goto('/');
// タイトルの確認
await expect(page).toHaveTitle(/SolidJS App/);
// ヘッダーの確認
const heading = page.getByRole('heading', {
name: 'Welcome to SolidJS',
});
await expect(heading).toBeVisible();
});
test('ユーザー登録フローのテスト', async ({ page }) => {
await page.goto('/register');
// フォームの入力
await page.fill('[data-testid="username"]', 'testuser');
await page.fill(
'[data-testid="email"]',
'test@example.com'
);
await page.fill(
'[data-testid="password"]',
'password123'
);
// 送信ボタンのクリック
await page.click('[data-testid="submit-button"]');
// 成功メッセージの確認
await expect(
page.getByText('登録が完了しました')
).toBeVisible();
// リダイレクトの確認
await expect(page).toHaveURL('/dashboard');
});
javascript// playwright.config.js
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
use: {
baseURL: 'http://localhost:3000',
},
webServer: {
command: 'yarn dev',
port: 3000,
reuseExistingServer: !process.env.CI,
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
],
});
図で理解できる要点:
- Solid Testing Library でコンポーネント単体テストを実現
- Vitest による JavaScript/TypeScript 統合テスト環境
- Playwright での E2E テストによる包括的なテスト戦略
パフォーマンス最適化ツール
SolidJS の最大の魅力の一つは優れたパフォーマンスです。2024 年にはさらなる最適化ツールが登場しました。
Bundle サイズ最適化
SolidJS は、コンパイル時最適化により小さなバンドルサイズを実現します。
javascript// vite.config.js - バンドル最適化設定
import { defineConfig } from 'vite';
import solid from 'vite-plugin-solid';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
solid(),
visualizer({
filename: 'dist/stats.html',
open: true,
}),
],
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['solid-js'],
ui: ['@kobalte/core', '@hope-ui/solid'],
},
},
},
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
},
});
バンドル分析のためのスクリプト:
typescript// scripts/bundle-analysis.ts
import { analyzeBundle } from 'rollup-plugin-analyzer';
const analyzeBundleSize = async () => {
const analysis = await analyzeBundle('./dist');
console.log('Bundle Size Analysis:');
console.log(`Total size: ${analysis.totalSize} KB`);
console.log(`Gzipped size: ${analysis.gzippedSize} KB`);
analysis.modules.forEach((module) => {
if (module.size > 10000) {
// 10KB以上のモジュール
console.log(
`Large module: ${module.name} (${module.size} bytes)`
);
}
});
};
コード分割戦略
効果的なコード分割により、初期ロード時間を短縮できます。
typescript// ルートレベルでのコード分割
import { lazy, Suspense } from 'solid-js';
import { Router, Route } from '@solidjs/router';
// 遅延ロードコンポーネント
const HomePage = lazy(() => import('./pages/HomePage'));
const ProductsPage = lazy(
() => import('./pages/ProductsPage')
);
const AdminPanel = lazy(() => import('./pages/AdminPanel'));
const App = () => {
return (
<Router>
<Suspense fallback={<div>読み込み中...</div>}>
<Route path='/' component={HomePage} />
<Route path='/products' component={ProductsPage} />
<Route path='/admin' component={AdminPanel} />
</Suspense>
</Router>
);
};
typescript// コンポーネントレベルでの動的インポート
import { createSignal, lazy, Show } from 'solid-js';
const HeavyChartComponent = lazy(
() => import('./HeavyChart')
);
const Dashboard = () => {
const [showChart, setShowChart] = createSignal(false);
return (
<div>
<h1>ダッシュボード</h1>
<button onClick={() => setShowChart(true)}>
チャートを表示
</button>
<Show when={showChart()}>
<Suspense
fallback={<div>チャート読み込み中...</div>}
>
<HeavyChartComponent />
</Suspense>
</Show>
</div>
);
};
リアクティビティ最適化
SolidJS のリアクティビティシステムを効率的に使用するためのベストプラクティスです。
typescript// メモ化による最適化
import { createSignal, createMemo, For } from 'solid-js';
interface Item {
id: number;
name: string;
category: string;
price: number;
}
const ProductList = () => {
const [items, setItems] = createSignal<Item[]>([]);
const [searchTerm, setSearchTerm] = createSignal('');
const [selectedCategory, setSelectedCategory] =
createSignal('all');
// 重い計算処理をメモ化
const filteredItems = createMemo(() => {
const term = searchTerm().toLowerCase();
const category = selectedCategory();
return items().filter((item) => {
const matchesSearch = item.name
.toLowerCase()
.includes(term);
const matchesCategory =
category === 'all' || item.category === category;
return matchesSearch && matchesCategory;
});
});
// カテゴリーリストもメモ化
const categories = createMemo(() => {
const uniqueCategories = new Set(
items().map((item) => item.category)
);
return ['all', ...Array.from(uniqueCategories)];
});
return (
<div>
<input
type='text'
placeholder='商品を検索...'
value={searchTerm()}
onInput={(e) =>
setSearchTerm(e.currentTarget.value)
}
/>
<select
value={selectedCategory()}
onChange={(e) =>
setSelectedCategory(e.currentTarget.value)
}
>
<For each={categories()}>
{(category) => (
<option value={category}>{category}</option>
)}
</For>
</select>
<div class='product-grid'>
<For each={filteredItems()}>
{(item) => (
<div class='product-card' key={item.id}>
<h3>{item.name}</h3>
<p>{item.category}</p>
<p>¥{item.price.toLocaleString()}</p>
</div>
)}
</For>
</div>
</div>
);
};
typescript// バッチ更新による最適化
import { batch, createSignal } from 'solid-js';
const useCounter = () => {
const [count, setCount] = createSignal(0);
const [lastUpdated, setLastUpdated] = createSignal(
new Date()
);
const increment = () => {
// 複数の更新をバッチ化
batch(() => {
setCount((c) => c + 1);
setLastUpdated(new Date());
});
};
const reset = () => {
batch(() => {
setCount(0);
setLastUpdated(new Date());
});
};
return { count, lastUpdated, increment, reset };
};
mermaidflowchart TD
source[データソース] --> signal[Signal]
signal --> memo[Memo/Derived]
signal --> effect[Effect]
memo --> component[コンポーネント]
effect --> sideeffect[副作用]
component --> dom[DOM更新]
sideeffect --> api[API呼び出し]
subgraph optimization[最適化ポイント]
memo2[重い計算のメモ化]
batch2[バッチ更新]
lazy2[遅延ロード]
end
memo --> memo2
signal --> batch2
component --> lazy2
この図は、SolidJS のリアクティビティシステムと最適化ポイントを示しています。Signal から派生した Memo と Effect が効率的に DOM 更新と副作用を処理し、各段階で最適化が可能です。
まとめ
SolidJS のエコシステムは 2024 年から 2025 年にかけて飛躍的な発展を遂げており、本格的な Web アプリケーション開発に十分な成熟度に達しています。
エコシステムの成熟度
SolidJS は以下の分野で特に優れた進歩を見せています:
状態管理: 内蔵のリアクティブプリミティブにより、外部ライブラリなしで効率的な状態管理を実現。createSignal と createEffect の組み合わせで、複雑なアプリケーション状態も管理できます。
ルーティング: Solid Router v2 の登場により、Next.js レベルの機能を提供。ファイルベースルーティングと動的ルーティングにより、大規模アプリケーションにも対応可能です。
UI コンポーネント: Kobalte、Hope UI、Solid UI など、用途に応じた選択肢が充実。アクセシビリティ重視からデザインシステムまで、幅広いニーズに対応しています。
2025 年の展望
SolidJS は以下の理由で今後さらなる成長が期待されます:
- パフォーマンス優位性: React を上回るレンダリング性能により、UX を重視するプロジェクトで採用が加速
- 学習コストの低さ: React 経験者なら短期間で習得可能な構文とコンセプト
- TypeScript 完全サポート: 型安全性を重視する現代の開発トレンドに合致
- SolidStart 1.0: メタフレームワークの安定版リリースにより、エンタープライズ導入の障壁が解消
導入時の考慮点
SolidJS 導入を検討される際は、以下の点をご考慮ください:
- チーム習熟度: React の知識があれば短期間で習得可能
- エコシステム成熟度: 必要なライブラリが揃っているかの事前確認
- 長期サポート: コミュニティの活発さと継続的な開発体制の確認
SolidJS エコシステムは、現在進行形で成長を続けており、2025 年には更なる飛躍が予想されます。パフォーマンスを重視し、モダンな開発体験を求めるプロジェクトにとって、SolidJS は最適な選択肢の一つとなるでしょう。
関連リンク
- article
SolidJS アドオン&エコシステム最新事情
- article
SolidJS のカスタムフック(create*系)活用事例集
- article
SolidJS で多言語化(i18n)対応を行う
- article
SolidJS のパフォーマンス計測&プロファイリング
- article
SolidJS でグローバルスタイルを管理する方法
- article
SolidJS アプリのディレクトリ構成と設計原則
- article
【実践】NestJS で REST API を構築する基本的な流れ
- article
TypeScript × GitHub Copilot:型情報を活かした高精度コーディング
- article
Motion(旧 Framer Motion)Variants 完全攻略:staggerChildren・when で複雑アニメを整理する
- article
JavaScript のオブジェクト操作まとめ:Object.keys/entries/values の使い方
- article
GitHub Actions で CI/CD パイプラインを構築する方法
- article
Nginx インストール完全ガイド:Linux・macOS・Windows・Docker 対応
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- blog
失敗を称賛する文化はどう作る?アジャイルな組織へ生まれ変わるための第一歩
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来