ブログ
OXCフルスタック実践:ゼロから超高速フロントエンド開発環境を構築
OXCの6つのコアモジュールを組み合わせて、完全な超高速フロントエンド開発環境を構築し、Rustツールチェーンがもたらすパフォーマンスの飛躍を体験しましょう。
LibDoc Team 2026年3月14日 OXC 連載 61 分で読める
#oxc
#rust
#フロントエンドツールチェーン
#開発環境
#パフォーマンス最適化
OXCフルスタック実践:ゼロから超高速フロントエンド開発環境を構築
最後までお読みいただきありがとうございます!これまでの7つの記事で、OXCの6つのコアモジュールを一つずつ学んできました:
- Oxlint:コードチェック、ESLintより50倍速い
- Oxfmt:コードフォーマット、Prettierより20倍速い
- Parser:コード解析、Babel Parserより20倍速い
- Transformer:コード変換、Babelより18倍速い
- Minifier:コード圧縮、Terserより5倍速い
- Resolver:モジュール解決、enhanced-resolveより5倍速い
今日は、これらのモジュールを組み合わせて、完全な超高速フロントエンド開発環境を構築します!
6つのコアモジュールを振り返る
実践を始める前に、各モジュールの核心価値を素早く振り返りましょう:
| モジュール | 用途 | 代替ツール | 典型的なシーン |
|---|---|---|---|
| Oxlint | コードチェック | ESLint | 開発時のリアルタイムチェック、CIパイプライン |
| Oxfmt | コードフォーマット | Prettier | 保存時の自動フォーマット、コミット前のフォーマット |
| Parser | コード解析 | @babel/parser | コードツールの構築、AST分析 |
| Transformer | コード変換 | Babel | TypeScriptコンパイル、JSX変換 |
| Minifier | コード圧縮 | Terser | 本番環境のバンドル最適化 |
| Resolver | モジュール解決 | enhanced-resolve | カスタムビルドツール、パスエイリアス |
適用シーンまとめ
開発フェーズ
├── Oxlint → リアルタイムコードチェック
├── Oxfmt → 保存時フォーマット
└── Resolver → モジュールパス解決
ビルドフェーズ
├── Parser → コードを解析してASTを生成
├── Transformer → TypeScript/JSX変換
├── Resolver → 依存関係の解決
└── Minifier → 本番コードの圧縮
実践:完全なワークフローを構築
ゼロから始めて、OXCフルスタックを使用するフロントエンドプロジェクトを構築しましょう。
ステップ1:プロジェクトの作成
mkdir oxc-project
cd oxc-project
npm init -y
ステップ2:依存関係のインストール
# コア依存関係
npm install @oxc/parser @oxc/transform @oxc/minifier @oxc/resolver oxlint oxfmt --save-dev
# TypeScript
npm install typescript --save-dev
# 開発サーバー(オプション)
npm install vite --save-dev
ステップ3:プロジェクト構造の作成
oxc-project/
├── src/
│ ├── components/
│ │ ├── Button.tsx
│ │ └── index.ts
│ ├── utils/
│ │ ├── date.ts
│ │ └── index.ts
│ ├── App.tsx
│ └── main.ts
├── dist/
├── oxlint.json
├── .oxfmtrc
├── tsconfig.json
└── package.json
ステップ4:Oxlintの設定
oxlint.json を作成:
{
"rules": {
"no-unused-vars": "error",
"no-console": "warn",
"no-debugger": "error",
"no-var": "error",
"prefer-const": "warn",
"eqeqeq": ["error", "always"]
}
}
ステップ5:Oxfmtの設定
.oxfmtrc を作成:
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always"
}
ステップ6:TypeScriptの設定
tsconfig.json を作成:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
ステップ7:サンプルコードの作成
src/components/Button.tsx:
import React from "react";
interface ButtonProps {
children: React.ReactNode;
onClick?: () => void;
variant?: "primary" | "secondary";
}
export function Button({ children, onClick, variant = "primary" }: ButtonProps) {
const baseStyles =
"px-4 py-2 rounded font-medium transition-colors focus:outline-none focus:ring-2";
const variantStyles = {
primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
secondary:
"bg-gray-200 text-gray-800 hover:bg-gray-300 focus:ring-gray-400",
};
return (
<button className={`${baseStyles} ${variantStyles[variant]}`} onClick={onClick}>
{children}
</button>
);
}
src/utils/date.ts:
/**
* 日付をフォーマット
*/
export function formatDate(date: Date, format = "YYYY-MM-DD"): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return format.replace("YYYY", String(year)).replace("MM", month).replace("DD", day);
}
/**
* 相対時間を取得
*/
export function getRelativeTime(date: Date): string {
const now = new Date();
const diff = now.getTime() - date.getTime();
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}日前`;
if (hours > 0) return `${hours}時間前`;
if (minutes > 0) return `${minutes}分前`;
return "たった今";
}
src/App.tsx:
import React from "react";
import { Button } from "@/components/Button";
import { formatDate } from "@/utils/date";
export function App() {
const today = new Date();
const handleClick = () => {
console.log("Button clicked!");
};
return (
<div className="min-h-screen bg-gray-100 p-8">
<h1 className="text-3xl font-bold text-gray-900 mb-4">OXC Demo Project</h1>
<p className="text-gray-600 mb-4">今日は:{formatDate(today)}</p>
<div className="space-x-4">
<Button onClick={handleClick}>Primary Button</Button>
<Button variant="secondary">Secondary Button</Button>
</div>
</div>
);
}
src/main.ts:
import React from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";
const container = document.getElementById("root");
if (container) {
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
}
ステップ8:npmスクリプトの設定
package.json を更新:
{
"name": "oxc-project",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "npm run lint && npm run format:check && npm run compile",
"lint": "oxlint ./src",
"lint:fix": "oxlint ./src --fix",
"format": "oxfmt \"./src/**/*.{ts,tsx,js,jsx}\" --write",
"format:check": "oxfmt \"./src/**/*.{ts,tsx,js,jsx}\" --check",
"compile": "node scripts/build.js",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@oxc/parser": "^0.15.0",
"@oxc/transform": "^0.15.0",
"@oxc/minifier": "^0.15.0",
"@oxc/resolver": "^0.15.0",
"oxlint": "^0.15.0",
"oxfmt": "^0.15.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
}
完全なビルドスクリプト
scripts/build.js を作成:
// scripts/build.js
import { transformSync } from "@oxc/transform";
import { minifySync } from "@oxc/minifier";
import { Resolver } from "@oxc/resolver";
import { parseSync } from "@oxc/parser";
import fs from "fs";
import path from "path";
const config = {
srcDir: "./src",
outDir: "./dist",
extensions: [".ts", ".tsx", ".js", ".jsx"],
target: "es2020",
};
// リゾルバーを作成
const resolver = new Resolver({
projectRoot: process.cwd(),
alias: {
"@": "./src",
},
extensions: config.extensions,
});
// 単一ファイルをコンパイル
function compileFile(inputPath, outputPath) {
console.log(`📝 コンパイル中: ${path.relative(process.cwd(), inputPath)}`);
const code = fs.readFileSync(inputPath, "utf-8");
const lang = inputPath.endsWith(".tsx") ? "tsx" : inputPath.endsWith(".ts") ? "ts" : "js";
// 1. コードを解析(オプション、分析用)
// const ast = parseSync(code, { lang });
// 2. コードを変換
const transformed = transformSync(code, {
lang,
target: config.target,
jsx: "automatic",
jsxImportSource: "react",
sourcemap: true,
});
// 3. コードを圧縮(本番環境)
const minified = minifySync(transformed.code, {
compress: true,
mangle: true,
sourcemap: true,
});
// 出力ディレクトリを確保
const outFilePath = outputPath.replace(/\.tsx?$/, ".js");
const outDir = path.dirname(outFilePath);
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir, { recursive: true });
}
// ファイルを書き込む
fs.writeFileSync(outFilePath, minified.code);
if (minified.map) {
fs.writeFileSync(`${outFilePath}.map`, minified.map);
}
const originalSize = Buffer.byteLength(code, "utf-8");
const minifiedSize = Buffer.byteLength(minified.code, "utf-8");
const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
console.log(` ✅ ${path.basename(outFilePath)} (${reduction}% 縮小)`);
}
// ディレクトリを走査
function walkDir(dir, callback) {
if (!fs.existsSync(dir)) return;
const files = fs.readdirSync(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
walkDir(filePath, callback);
} else if (config.extensions.some((ext) => file.endsWith(ext))) {
callback(filePath);
}
}
}
// メインビルドフロー
function build() {
console.log("\n🚀 OXCビルドを開始...\n");
console.log("━".repeat(50));
const startTime = Date.now();
// 出力ディレクトリをクリア
if (fs.existsSync(config.outDir)) {
fs.rmSync(config.outDir, { recursive: true });
}
fs.mkdirSync(config.outDir, { recursive: true });
// すべてのファイルをコンパイル
walkDir(config.srcDir, (inputPath) => {
const relativePath = path.relative(config.srcDir, inputPath);
const outputPath = path.join(config.outDir, relativePath);
compileFile(inputPath, outputPath);
});
const endTime = Date.now();
const duration = endTime - startTime;
console.log("━".repeat(50));
console.log(`\n✨ ビルド完了: ${duration}ms\n`);
}
// ビルドを実行
build();
パフォーマンス向上のデモ
従来のツールチェーンとOXCツールチェーンのパフォーマンス差を比較しましょう。
テストシナリオ
- プロジェクト規模:100個のTypeScriptファイル
- 総コード量:約20,000行
- 環境:MacBook Pro M1
従来のツールチェーン vs OXCツールチェーン
| タスク | 従来ツール | 時間 | OXC ツール | 時間 | 向上 |
|---|---|---|---|---|---|
| コードチェック | ESLint | 25s | Oxlint | 0.4s | 62x |
| コードフォーマット | Prettier | 2.8s | Oxfmt | 0.15s | 18x |
| TypeScript コンパイル | tsc | 8s | OXC Transformer | 0.6s | 13x |
| コード圧縮 | Terser | 3.5s | OXC Minifier | 0.6s | 5.8x |
| 合計時間 | - | 39.3s | - | 1.75s | 22x |
CI/CD時間比較
| パイプラインステップ | 従来ツールチェーン | OXCツールチェーン |
|---|---|---|
| 依存関係のインストール | 45s | 45s |
| 型チェック | 8s | 8s (tsc) |
| コードチェック | 25s | 0.4s |
| ビルド | 12s | 1.5s |
| テスト | 20s | 20s |
| 合計 | 110s | 75s |
CI時間が32%削減!
開発体験の改善
| シーン | 改善前 | 改善後 |
|---|---|---|
| pre-commitフック | 20-30s | 1-2s |
| 保存時チェック | 遅延を感じる | 即座に完了 |
| 全プロジェクトフォーマット | 待機が必要 | ほぼ瞬時 |
| 大規模プロジェクトのビルド | 数分 | 数秒 |
学習ロードマップの提案
ニーズに応じて、異なる学習パスを選択できます:
入門ロードマップ:日常開発の効率向上
Week 1: Oxlint
├── プロジェクトのESLintを置き換え
├── VS Codeプラグインを設定
└── 即時チェックの快感を体験
Week 2: Oxfmt
├── プロジェクトのPrettierを置き換え
├── 保存時フォーマットを設定
└── lint-stagedと組み合わせて使用
中級ロードマップ:コード処理を深く理解
Week 3-4: Parser + Transformer
├── ASTの基礎を学ぶ
├── Parserでコード分析ツールを構築
├── TransformerでTypeScriptを処理
└── カスタムコード変換を試す
上級ロードマップ:ビルドツール開発
Week 5-6: Minifier + Resolver
├── コード圧縮の原理を理解
├── モジュール解決メカニズムを学ぶ
├── シンプルなバンドラーを構築
└── フロントエンドツールチェーンを深く理解
リソースまとめ
公式リソース
- 📖 OXC日本語ドキュメント:https://oxc.ja.libdoc.top
- 🌟 GitHubリポジトリ:https://github.com/oxc-project/oxc
- 💬 Discordコミュニティ:ディスカッションに参加し、ヘルプを得る
本シリーズの記事
- 初めてのOXC:フロントエンドツールチェーンの新しい選択
- Oxlint実践チュートリアル
- Oxfmt実践チュートリアル
- Parser入門チュートリアル
- Transformer入門チュートリアル
- Minifier実践チュートリアル
- Resolver入門チュートリアル
- 本記事:総括編実践
関連ツール
| ツール | 説明 |
|---|---|
| Vite | OXCをサポートする次世代ビルドツール |
| Rolldown | RustベースのRollup代替 |
| Rspack | RustベースのWebpack代替 |
| Biome | 別のRustフロントエンドツールチェーン |
まとめ
この8つの記事を通じて、OXCツールチェーンを全面的に学びました:
核心的な収穫
| 知識ポイント | 説明 |
|---|---|
| なぜOXCを選ぶか | Rustがもたらす究極のパフォーマンス |
| Oxlint | 50倍速いコードチェック |
| Oxfmt | 20倍速いコードフォーマット |
| Parser | ASTを理解し、コードツールを構築 |
| Transformer | TypeScriptコンパイルとJSX変換 |
| Minifier | 本番環境のコード圧縮 |
| Resolver | モジュールパス解決 |
| 統合アプリケーション | 完全な開発環境を構築 |
一言でまとめる
OXCはRustの速度でフロントエンドツールチェーンを再構築しています。
今後の展望
OXCはまだ急速に発展しています:
- より多くのESLintルールサポート
- より完全な構文ダウングレード
- プラグインシステム
- より多くのバンドルツールとの統合
フロントエンドツールの未来は、すでに到来しています。
💡 最後の一言:
このシリーズを通じてOXCを気に入っていただけたなら、ぜひ**OXC日本語ドキュメント**でさらに深く学び、GitHubでプロジェクトにStarを付けてください!
Happy coding! 🚀