UnJSエコシステム完全ガイド - Nitro, H3, ofetch, etc.
UnJSエコシステムとは
UnJSの特徴
- フレームワーク非依存: どこでも使える汎用ライブラリ
- TypeScript完全対応: 型安全性が高い
- モダンなAPI設計: 直感的で使いやすい
- 高いパフォーマンス: 効率的な実装
- 活発な開発: 継続的な改善とメンテナンス
主要なライブラリ
- Nitro: サーバーレスフレームワーク
- H3: HTTPフレームワーク
- ofetch: より良いfetch API
- unimport: 自動インポート
- unbuild: ライブラリビルドツール
- ufo: URL処理ユーティリティ
- defu: オブジェクトマージユーティリティ
Nitro - ユニバーサルサーバーフレームワーク
Nitroは、あらゆるプラットフォームにデプロイできるサーバーレスアプリケーションフレームワークです。
Nitroのセットアップ
npx giget@latest nitro my-nitro-app
cd my-nitro-app
npm install
npm run dev
基本的なAPI作成
// routes/hello.ts
export default defineEventHandler((event) => {
return {
message: 'Hello from Nitro!',
timestamp: new Date().toISOString(),
};
});
パラメータの処理
// routes/users/[id].ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id');
return {
userId: id,
name: `User ${id}`,
};
});
クエリパラメータの処理:
// routes/search.ts
export default defineEventHandler((event) => {
const query = getQuery(event);
const { q, page = 1, limit = 10 } = query;
return {
query: q,
page: Number(page),
limit: Number(limit),
results: [], // 実際の検索結果
};
});
POSTリクエストの処理
// routes/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
// バリデーション
if (!body.name || !body.email) {
throw createError({
statusCode: 400,
message: 'Name and email are required',
});
}
// データベースに保存(例)
const user = {
id: generateId(),
name: body.name,
email: body.email,
createdAt: new Date().toISOString(),
};
return user;
});
ミドルウェア
// middleware/auth.ts
export default defineEventHandler((event) => {
const token = getHeader(event, 'authorization');
if (!token) {
throw createError({
statusCode: 401,
message: 'Unauthorized',
});
}
// トークン検証
const user = verifyToken(token);
event.context.user = user;
});
特定のルートにのみ適用:
// routes/api/protected.ts
export default defineEventHandler(async (event) => {
// ミドルウェアで設定されたユーザー情報にアクセス
const user = event.context.user;
return {
message: 'Protected data',
user,
};
});
データベース統合(Drizzle ORM)
// utils/db.ts
import { drizzle } from 'drizzle-orm/better-sqlite3';
import Database from 'better-sqlite3';
const sqlite = new Database('sqlite.db');
export const db = drizzle(sqlite);
// routes/api/posts.get.ts
import { db } from '~/utils/db';
import { posts } from '~/db/schema';
export default defineEventHandler(async (event) => {
const allPosts = await db.select().from(posts);
return allPosts;
});
キャッシング
// routes/api/expensive-operation.ts
export default defineCachedEventHandler(
async (event) => {
// 重い処理
const result = await performExpensiveOperation();
return result;
},
{
maxAge: 60 * 60, // 1時間キャッシュ
getKey: (event) => {
// キャッシュキーのカスタマイズ
const userId = event.context.user?.id;
return `expensive-op-${userId}`;
},
}
);
H3 - ミニマルHTTPフレームワーク
H3は、Nitroの基盤となっているHTTPフレームワークです。単独でも使用できます。
H3のセットアップ
npm install h3
基本的なサーバー
import { createApp, createRouter, defineEventHandler } from 'h3';
import { createServer } from 'node:http';
const app = createApp();
const router = createRouter();
router.get('/hello', defineEventHandler(() => {
return { message: 'Hello from H3!' };
}));
router.post('/users', defineEventHandler(async (event) => {
const body = await readBody(event);
return { created: true, user: body };
}));
app.use(router);
createServer(app).listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
エラーハンドリング
import { createError } from 'h3';
router.get('/error', defineEventHandler(() => {
throw createError({
statusCode: 500,
statusMessage: 'Internal Server Error',
message: 'Something went wrong',
});
}));
// グローバルエラーハンドラー
app.use(defineEventHandler((event) => {
event.node.res.on('error', (error) => {
console.error('Response error:', error);
});
}));
CORS設定
import { handleCors } from 'h3';
app.use(defineEventHandler((event) => {
handleCors(event, {
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization'],
});
}));
ofetch - 改良版fetch API
ofetchは、ネイティブfetchのラッパーで、より使いやすく強力な機能を提供します。
基本的な使い方
import { ofetch } from 'ofetch';
// GET リクエスト
const data = await ofetch('https://api.example.com/users');
// 自動的にJSONパース
console.log(data);
クエリパラメータ
const users = await ofetch('https://api.example.com/users', {
query: {
page: 1,
limit: 20,
sort: 'name',
},
});
// → https://api.example.com/users?page=1&limit=20&sort=name
POSTリクエスト
const newUser = await ofetch('https://api.example.com/users', {
method: 'POST',
body: {
name: 'John Doe',
email: 'john@example.com',
},
});
// 自動的にJSON.stringify()される
エラーハンドリング
try {
const data = await ofetch('https://api.example.com/data');
} catch (error) {
console.error('Request failed:', error.data);
console.error('Status:', error.status);
}
インターセプター
const api = ofetch.create({
baseURL: 'https://api.example.com',
async onRequest({ request, options }) {
// リクエスト前の処理
const token = await getAuthToken();
options.headers = {
...options.headers,
Authorization: `Bearer ${token}`,
};
},
async onResponse({ response }) {
// レスポンス後の処理
console.log('Response received:', response.status);
},
async onResponseError({ response }) {
// エラーレスポンスの処理
if (response.status === 401) {
await refreshToken();
}
},
});
const data = await api('/users');
リトライ機能
const data = await ofetch('https://api.example.com/data', {
retry: 3,
retryDelay: 1000, // 1秒待機
});
タイムアウト
const data = await ofetch('https://api.example.com/slow-endpoint', {
timeout: 5000, // 5秒でタイムアウト
});
unimport - 自動インポート
unimportは、よく使う関数やライブラリを自動的にインポートしてくれるツールです。
Viteでの使用
// vite.config.ts
import { defineConfig } from 'vite';
import Unimport from 'unimport/unplugin';
export default defineConfig({
plugins: [
Unimport.vite({
imports: [
// Vue 3の関数
{
from: 'vue',
imports: ['ref', 'computed', 'reactive', 'watch'],
},
// カスタム関数
{
from: './utils/helpers',
imports: ['formatDate', 'formatCurrency'],
},
],
}),
],
});
使用例:
// インポート不要!
const count = ref(0);
const doubled = computed(() => count.value * 2);
const formatted = formatDate(new Date());
プリセット
Unimport.vite({
presets: [
'vue',
'vue-router',
'pinia',
],
});
unbuild - ライブラリビルドツール
unbuildは、TypeScriptライブラリを簡単にビルドできるツールです。
セットアップ
npm install -D unbuild
// package.json
{
"scripts": {
"build": "unbuild"
}
}
設定ファイル
// build.config.ts
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
entries: ['src/index'],
declaration: true,
clean: true,
rollup: {
emitCJS: true,
},
});
複数エントリポイント
export default defineBuildConfig({
entries: [
'src/index',
'src/client',
'src/server',
],
declaration: true,
});
ufo - URL処理ユーティリティ
ufoは、URLの解析・操作を簡単にするライブラリです。
URLの解析
import { parseURL } from 'ufo';
const parsed = parseURL('https://example.com/path?foo=bar#hash');
console.log(parsed);
// {
// protocol: 'https:',
// host: 'example.com',
// pathname: '/path',
// search: '?foo=bar',
// hash: '#hash'
// }
URLの結合
import { joinURL } from 'ufo';
const url = joinURL('https://example.com', 'api', 'users');
// → https://example.com/api/users
クエリパラメータの操作
import { withQuery, getQuery } from 'ufo';
const url = withQuery('https://api.example.com/search', {
q: 'javascript',
page: 1,
});
// → https://api.example.com/search?q=javascript&page=1
const query = getQuery('https://example.com?foo=bar&baz=qux');
// → { foo: 'bar', baz: 'qux' }
相対URLの解決
import { resolveURL } from 'ufo';
const absolute = resolveURL('https://example.com/path', '../other');
// → https://example.com/other
defu - オブジェクトマージユーティリティ
defuは、デフォルト値を持つオブジェクトマージを行います。
基本的な使い方
import { defu } from 'defu';
const defaults = {
theme: 'light',
fontSize: 14,
features: {
darkMode: false,
animations: true,
},
};
const userConfig = {
theme: 'dark',
features: {
darkMode: true,
},
};
const config = defu(userConfig, defaults);
// {
// theme: 'dark',
// fontSize: 14,
// features: {
// darkMode: true,
// animations: true
// }
// }
配列のマージ
import { defuArrayFn } from 'defu';
const merged = defuArrayFn(
{ tags: ['new'] },
{ tags: ['default', 'tags'] }
);
// { tags: ['new', 'default', 'tags'] }
実践例: フルスタックアプリケーション
UnJSライブラリを組み合わせた実践的な例:
// server/api/users/[id].ts
import { ofetch } from 'ofetch';
import { withQuery } from 'ufo';
import { defu } from 'defu';
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id');
const query = getQuery(event);
// デフォルト設定とマージ
const options = defu(query, {
include: 'posts',
limit: 10,
});
// 外部APIを呼び出し
const url = withQuery(`https://api.example.com/users/${id}`, options);
const user = await ofetch(url);
return user;
});
// composables/useApi.ts
import { ofetch } from 'ofetch';
export function useApi() {
const api = ofetch.create({
baseURL: '/api',
async onRequest({ options }) {
const token = localStorage.getItem('token');
if (token) {
options.headers = {
...options.headers,
Authorization: `Bearer ${token}`,
};
}
},
async onResponseError({ response }) {
if (response.status === 401) {
// 認証エラー処理
navigateTo('/login');
}
},
});
return {
getUsers: () => api('/users'),
getUser: (id: string) => api(`/users/${id}`),
createUser: (data: any) => api('/users', { method: 'POST', body: data }),
};
}
まとめ
UnJSエコシステムは、モダンなJavaScript/TypeScript開発を効率化する強力なツール群です:
- Nitro: ユニバーサルサーバーフレームワーク
- H3: 軽量HTTPフレームワーク
- ofetch: 改良版fetch API
- unimport: 自動インポート
- unbuild: ライブラリビルドツール
- ufo: URL処理ユーティリティ
- defu: オブジェクトマージ
これらのライブラリは独立して使用できますが、組み合わせることでさらに強力な開発環境を構築できます。ぜひプロジェクトで活用してみてください。