Preact実践ガイド2025 - 3kBの軽量React代替で高速Webアプリを構築
Preact v10.26.9で実現する超軽量フロントエンド開発。Reactからの移行手順、パフォーマンス比較、実際のプロジェクトでの活用法まで、モバイルファーストな時代に必須の軽量化技術を完全網羅します。
わずか3kBで実現する高速なReact代替ライブラリPreactを徹底解説。本番環境での導入方法、パフォーマンス最適化、React互換レイヤーの活用法まで、実践的な知識を完全網羅します。
Preact は、Reactの現代的な API を保ちながら、わずか3kBのバンドルサイズを実現する軽量フレームワークです。2025 年 6 月時点で 37,000 以上の GitHubスターを獲得し、パフォーマンスを重視する多くのプロダクションサイトで採用されています。
React + ReactDOM = 約45kB (gzipped)
モバイル環境での遅延
3kBで同等の機能を実現
主要ライブラリとの互換性確立
特徴 | Preact | React | 差異 |
---|---|---|---|
バンドルサイズ | 3kB | 45kB | -93% |
Virtual DOM | 薄い抽象化 | フル機能 | 高速化 |
ブラウザ互換性 | IE11+ | IE11+ | 同等 |
エコシステム | compat経由 | ネイティブ | 互換レイヤー |
学習曲線 | 低い | 中程度 | React経験者は即座に使用可 |
パフォーマンス | 優秀 | 良好 | 軽量化による高速化 |
# npmでインストール
npm install preact
# TypeScript使用時
npm install -D @types/node
# React互換レイヤー(必要に応じて)
npm install preact-compat
<!-- 開発版 -->
<script type="module">
import { h, render } from 'https://unpkg.com/preact?module';
const App = () => h('h1', null, 'Hello Preact!');
render(h(App), document.body);
</script>
<!-- プロダクション版 -->
<script src="https://unpkg.com/preact/dist/preact.min.js"></script>
# Viteプロジェクトの作成
npm create vite@latest my-preact-app -- --template preact
# TypeScript版
npm create vite@latest my-preact-app -- --template preact-ts
cd my-preact-app
npm install
npm run dev
チャートを読み込み中...
// webpack.config.js
module.exports = {
resolve: {
alias: {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
"react/jsx-runtime": "preact/jsx-runtime"
}
}
};
// vite.config.js
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
export default defineConfig({
plugins: [preact()],
resolve: {
alias: {
react: 'preact/compat',
'react-dom': 'preact/compat'
}
}
});
import { h } from 'preact';
import { memo } from 'preact/compat';
// メモ化されたコンポーネント
const ExpensiveList = memo(({ items }) => {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}, (prevProps, nextProps) => {
// カスタム比較関数
return prevProps.items.length === nextProps.items.length;
});
// 遅延ロード
import { lazy, Suspense } from 'preact/compat';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
// 必要な機能のみをインポート
import { render } from 'preact';
import { useState } from 'preact/hooks';
// 不要な機能を避ける
// ❌ import * as preact from 'preact';
// ✅ import { h, render } from 'preact';
// プロダクションビルドの最適化
// package.json
{
"scripts": {
"build": "vite build --minify terser",
"analyze": "vite-bundle-visualizer"
}
}
import { h, createContext } from 'preact';
import { useContext, useReducer } from 'preact/hooks';
const StateContext = createContext();
function stateReducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
return { ...state, count: state.count - 1 };
default:
return state;
}
}
export function StateProvider({ children }) {
const [state, dispatch] = useReducer(stateReducer, { count: 0 });
return (
<StateContext.Provider value={{ state, dispatch }}>
{children}
</StateContext.Provider>
);
}
export const useAppState = () => useContext(StateContext);
import { create } from 'zustand';
import { h } from 'preact';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
function Counter() {
const { count, increment, decrement } = useStore();
return (
<div>
<h2>{count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
import { signal, computed } from '@preact/signals';
// シグナルの作成
const count = signal(0);
const doubled = computed(() => count.value * 2);
function Counter() {
return (
<div>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onClick={() => count.value++}>
Increment
</button>
</div>
);
}
import { h } from 'preact';
import { Router, Route, Link } from 'preact-router';
import { createHashHistory } from 'history';
// ページコンポーネント
const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;
const Profile = ({ user }) => <h1>Profile: {user}</h1>;
// ルーティング設定
function App() {
return (
<div>
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/profile/john">Profile</Link>
</nav>
<Router history={createHashHistory()}>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/profile/:user" component={Profile} />
</Router>
</div>
);
}
// server.js
import express from 'express';
import { h } from 'preact';
import render from 'preact-render-to-string';
import App from './App';
const app = express();
app.get('*', (req, res) => {
const html = render(<App url={req.url} />);
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Preact SSR</title>
</head>
<body>
<div id="app">${html}</div>
<script src="/bundle.js"></script>
</body>
</html>
`);
});
app.listen(3000);
// クライアント側のハイドレーション
import { h, hydrate } from 'preact';
import App from './App';
// SSRされたコンテンツをハイドレート
if (typeof window !== 'undefined') {
hydrate(<App />, document.getElementById('app'));
}
モバイル Web アプリケーションで Preact を採用することで、初期ロード時間を 50%削減し、ユーザーエンゲージメントが大幅に向上しました。
preact/debug
をインポートするclassName
ではなく class
を使用createRef
または useRef
を使用ComponentChildren
型を使用Preact は、パフォーマンスとバンドルサイズを重視するプロジェクトに最適な選択肢です。Reactの知識をそのまま活かしながら、93%のサイズ削減を実現できます。
特に以下のようなケースで Preact の採用を検討してください: