Turbopack のプラグイン開発入門

Next.js の高速化を実現する Turbopack は、従来の Webpack を大幅に上回るパフォーマンスを提供しています。しかし、開発者の多くが疑問に思うのは「Turbopack でプラグイン開発はできるのか?」ということでしょう。
本記事では、2025 年 6 月現在の Turbopack におけるカスタマイズ機能の現状と制限、そして将来のプラグインシステムへの展望について詳しく解説いたします。現在利用可能な実践的な手法から、将来の開発に向けた準備まで、包括的にご紹介します。
Turbopack の現在のカスタマイズ機能
現在のカスタマイズ可能範囲
Turbopack は 2025 年 6 月時点で、Next.js 15.3 での開発モードが安定版となっています。プロダクションビルドはまだアルファ版の段階ですが、開発環境では十分実用的なカスタマイズが可能です。
サポート状況一覧
機能 | 開発モード | プロダクションビルド | 状況 |
---|---|---|---|
webpack ローダー | 部分サポート | 開発中 | コアローダーのみ |
next.config.js 設定 | 完全サポート | 完全サポート | 安定 |
ファイル拡張子設定 | 完全サポート | 完全サポート | 安定 |
エイリアス設定 | 完全サポート | 完全サポート | 安定 |
カスタムプラグイン | 未サポート | 未サポート | 開発予定 |
現在の制限事項
Turbopack には以下の重要な制限があります:
javascript// ❌ サポートされていない機能
module.exports = {
webpack(config) {
// webpack設定は無視される
config.module.rules.push({
test: /\.custom$/,
use: 'custom-loader',
});
return config;
},
};
bash# よく発生するエラー
Warning: webpack() configuration found in next.config.js.
Turbopack replaces Webpack, so webpack configuration is not supported.
Use the turbopack configuration instead.
webpack ローダーとの連携
サポート済みローダーの活用
現在 Turbopack でテスト済みのローダーは限定的ですが、重要なローダーは動作します。
動作確認済みローダー一覧
javascript// 2025年6月現在、以下のローダーが動作確認済み
const supportedLoaders = [
'babel-loader',
'@svgr/webpack',
'svg-inline-loader',
'yaml-loader',
'string-replace-loader',
'raw-loader',
'sass-loader',
'graphql-tag/loader',
];
実際の設定例
SVG ファイルを React コンポーネントとして使用する例
javascript// next.config.js
module.exports = {
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
};
YAML ファイルの処理例
javascript// next.config.js
module.exports = {
turbopack: {
rules: {
'*.yaml': {
loaders: [
{
loader: 'yaml-loader',
options: {
asJSON: true,
},
},
],
as: '*.js',
},
},
},
};
カスタムローダーの設定方法
基本的な設定パターン
javascript// next.config.js
module.exports = {
turbopack: {
rules: {
// パターン1: シンプルなローダー指定
'*.md': {
loaders: ['raw-loader'],
as: '*.js',
},
// パターン2: 設定オプション付き
'*.graphql': {
loaders: [
{
loader: 'graphql-tag/loader',
options: {
schema: 'schema.graphql',
},
},
],
as: '*.js',
},
// パターン3: 複数ローダーの連携
'*.scss': {
loaders: [
'sass-loader',
{
loader: 'string-replace-loader',
options: {
search: '{{BASE_URL}}',
replace: process.env.BASE_URL || '',
},
},
],
as: '*.css',
},
},
},
};
TypeScript での型安全な設定
typescript// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
turbopack: {
rules: {
'*.proto': {
loaders: [
{
loader: 'protobuf-loader',
options: {
json: true,
includeDirs: ['./proto'],
},
},
],
as: '*.js',
},
},
},
};
export default nextConfig;
制限事項と対処法
現在の主要な制限
1. JavaScript のみ返すローダーの制限
bash# よく遭遇するエラー
Error: Only loaders that return JavaScript code are supported.
Loaders that transform files like stylesheets or images are not currently supported.
対処法:
javascript// ❌ 動作しない例
'*.png': {
loaders: ['url-loader'], // 画像ローダーは未サポート
as: '*.js',
}
// ✅ 動作する例
'*.svg': {
loaders: ['@svgr/webpack'], // JSコードを返すため動作
as: '*.js',
}
2. require() プラグインの制限
bash# エラー例
Error: Options passed to webpack loaders must be plain JavaScript primitives, objects, and arrays.
It's not possible to pass require() plugin modules as option values.
対処法:
javascript// ❌ 動作しない例
{
loader: 'some-loader',
options: {
plugin: require('some-plugin'), // require()は使用不可
},
}
// ✅ 動作する例
{
loader: 'some-loader',
options: {
plugin: 'some-plugin', // 文字列で指定
config: './config.json', // ファイルパスで指定
},
}
3. 複雑な webpack API の制限
bash# よく発生するエラー
Error: Only a core subset of the webpack loader API is implemented.
Currently, there is enough coverage for some popular loaders.
対処法として、代替アプローチを検討:
javascript// Turbopack用の最適化された設定
module.exports = {
turbopack: {
// シンプルな変換ルールに限定
rules: {
'*.env': {
loaders: ['raw-loader'],
as: '*.js',
},
},
// より複雑な処理は別の方法で実装
resolveAlias: {
'@env': './config/environment.js',
},
},
};
設定ベースのカスタマイズ
next.config.js での設定
基本設定オプション
javascript// next.config.js - 完全設定例
module.exports = {
turbopack: {
// ルートディレクトリの設定
root: path.join(__dirname, '..'),
// ファイル変換ルール
rules: {
'*.custom': {
loaders: ['custom-loader'],
as: '*.js',
},
},
// モジュール解決の設定
resolveAlias: {
'@': './src',
'@components': './src/components',
'@utils': './src/utils',
},
// 解決可能な拡張子
resolveExtensions: [
'.tsx',
'.ts',
'.jsx',
'.js',
'.mjs',
'.json',
'.wasm',
],
// モジュールID生成方式
moduleIds: 'named', // 'named' | 'deterministic'
// Tree shakingの設定
treeShaking: true,
// メモリ制限(バイト単位)
memoryLimit: 1024 * 1024 * 1024, // 1GB
},
};
環境別設定の実装
javascript// next.config.js - 環境別設定
const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
turbopack: {
// 開発環境でのみ詳細なデバッグ情報
moduleIds: isDev ? 'named' : 'deterministic',
// 開発環境でのメモリ制限を緩く設定
memoryLimit: isDev
? 2 * 1024 * 1024 * 1024 // 2GB
: 1024 * 1024 * 1024, // 1GB
resolveAlias: {
// 環境別のAPI設定
'@api': isDev
? './src/api/development'
: './src/api/production',
},
rules: {
// 開発環境でのみソースマップ付きローダー
...(isDev && {
'*.ts': {
loaders: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-typescript'],
sourceMaps: true,
},
},
],
as: '*.js',
},
}),
},
},
};
エイリアス設定とモジュール解決
パスエイリアスの活用
javascript// next.config.js
module.exports = {
turbopack: {
resolveAlias: {
// 基本的なエイリアス
'@': './src',
'@components': './src/components',
'@hooks': './src/hooks',
'@utils': './src/utils',
'@styles': './src/styles',
'@public': './public',
// ライブラリの置き換え
lodash: 'lodash-es', // ES modules版を使用
moment: 'dayjs', // より軽量な代替
// 条件付きエイリアス(環境別)
config: {
browser: './src/config/browser.js',
node: './src/config/server.js',
},
},
},
};
tsconfig.json との連携
json// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"]
}
}
}
javascript// next.config.js - tsconfig.jsonと同期
const path = require('path');
module.exports = {
turbopack: {
// TypeScriptのpathsと同期
resolveAlias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(
__dirname,
'src/components'
),
'@hooks': path.resolve(__dirname, 'src/hooks'),
'@utils': path.resolve(__dirname, 'src/utils'),
},
},
};
拡張子とファイル変換
カスタム拡張子の処理
javascript// next.config.js
module.exports = {
turbopack: {
// 解決可能な拡張子を拡張
resolveExtensions: [
'.tsx',
'.ts',
'.jsx',
'.js',
'.mjs',
'.cjs',
'.json',
'.wasm',
'.css',
'.scss',
// カスタム拡張子
'.vue',
'.svelte',
'.mdx',
],
rules: {
// MDXファイルの処理
'*.mdx': {
loaders: [
{
loader: '@mdx-js/loader',
options: {
remarkPlugins: [],
rehypePlugins: [],
},
},
],
as: '*.jsx',
},
// GraphQLスキーマファイル
'*.graphql': {
loaders: ['graphql-tag/loader'],
as: '*.js',
},
// プロトコルバッファー
'*.proto': {
loaders: [
{
loader: 'protobuf-loader',
options: {
json: true,
},
},
],
as: '*.js',
},
},
},
};
ファイルタイプ別の最適化
javascript// next.config.js - ファイルタイプ別設定
module.exports = {
turbopack: {
rules: {
// テキストファイルの最適化
'*.txt': {
loaders: [
{
loader: 'raw-loader',
options: {
esModule: true,
},
},
],
as: '*.js',
},
// 設定ファイルの動的読み込み
'*.config.js': {
loaders: [
{
loader: 'string-replace-loader',
options: {
search: '{{ENV}}',
replace: process.env.NODE_ENV,
},
},
],
as: '*.js',
},
// SVGアイコンの最適化
'*.icon.svg': {
loaders: [
{
loader: '@svgr/webpack',
options: {
icon: true,
svgo: true,
svgoConfig: {
plugins: [
{
name: 'removeViewBox',
active: false,
},
],
},
},
},
],
as: '*.js',
},
},
},
};
将来のプラグイン API への準備
開発予定のプラグインシステム
現在の開発状況
Turbopack チームは、完全なプラグインエコシステムの構築を進めています。2025 年後半から 2026 年にかけて、以下の機能が予定されています:
rust// 将来予定されているRustベースプラグインAPI(概念図)
use turbopack_plugin::{Plugin, Context, Result};
#[turbopack_plugin]
pub struct CustomTransformPlugin {
options: CustomOptions,
}
impl Plugin for CustomTransformPlugin {
fn name(&self) -> &str {
"custom-transform"
}
async fn transform(
&self,
ctx: &Context,
source: &str
) -> Result<String> {
// カスタム変換ロジック
Ok(transform_source(source, &self.options))
}
}
JavaScript/TypeScript API の提供予定
typescript// 将来予定されているJavaScript API(概念図)
import { definePlugin } from '@turbopack/plugin-api';
export default definePlugin({
name: 'custom-transform',
transform: {
include: /\.(custom)$/,
exclude: /node_modules/,
async handler(code: string, id: string) {
// 変換ロジック
return {
code: transformedCode,
map: sourceMap,
};
},
},
resolveId: {
async handler(id: string, importer?: string) {
// モジュール解決ロジック
return resolvedId;
},
},
buildStart: {
async handler() {
// ビルド開始時の処理
},
},
});
現在の Rust ベースアーキテクチャ
Turbopack の内部構造
Turbopack は Rust で構築された高性能なビルドシステムです。その基盤となるアーキテクチャを理解しておくことは、将来のプラグイン開発に重要です。
rust// Turbopackの核となるアーキテクチャ(簡略化)
pub struct TurboEngine {
graph: IncrementalGraph,
cache: FunctionLevelCache,
runtime: AsyncRuntime,
}
impl TurboEngine {
pub async fn compile(&self, entry: &Path) -> Result<Bundle> {
// インクリメンタルコンパイル
let nodes = self.graph.get_affected_nodes(entry)?;
for node in nodes {
if !self.cache.is_valid(&node) {
let result = self.compile_node(&node).await?;
self.cache.store(&node, result);
}
}
self.generate_bundle().await
}
}
パフォーマンス特性の理解
javascript// 現在のTurbopackの設計思想
const turbopackPrinciples = {
incremental: {
description: '関数レベルでのキャッシュ',
benefit: '変更箇所のみ再処理',
},
parallel: {
description: 'マルチコア並列処理',
benefit: 'CPUリソースの最大活用',
},
lazy: {
description: '必要な時のみコンパイル',
benefit: '初期起動時間の短縮',
},
unified: {
description: '単一の依存関係グラフ',
benefit: 'サーバー・クライアント間の一貫性',
},
};
コミュニティへの貢献方法
GitHub でのコントリビューション
bash# Turbopackリポジトリのクローン
git clone https://github.com/vercel/turbo.git
cd turbo
# 開発環境のセットアップ
cargo install --path crates/turbopack-cli
# テストの実行
cargo test -p turbopack
# ベンチマークの実行
cargo bench -p turbopack-bench
プラグイン API 設計への参加
現在、Turbopack チームはコミュニティからのフィードバックを積極的に募集しています:
typescript// 望ましいプラグインAPI設計についてのフィードバック例
interface PluginFeedback {
// どのような機能が必要か
requiredFeatures: string[];
// 既存webpack pluginからの移行要件
migrationNeeds: {
plugin: string;
features: string[];
complexity: 'simple' | 'moderate' | 'complex';
}[];
// パフォーマンス要件
performanceRequirements: {
buildTime: string;
memoryUsage: string;
cacheEfficiency: string;
};
}
ディスカッションと RFC 参加
markdown<!-- GitHub Discussionsでの提案例 -->
## Plugin API RFC: Custom File Transformations
### 背景
現在の webpack ローダーシステムから移行する際の課題
### 提案
```typescript
interface TransformPlugin {
name: string;
test: RegExp;
transform(
code: string,
id: string
): Promise<TransformResult>;
}
```
利用例
- TypeScript 以外の言語サポート
- カスタムファイル形式の処理
- コード生成ツールとの連携
arduino
# 実践的なカスタマイズ例
## 実際のプロジェクトでの活用事例
### ケース1: マルチテナント SaaS での設定管理
```javascript
// next.config.js - テナント別設定
const tenantConfig = require('./config/tenants.json');
module.exports = {
turbopack: {
resolveAlias: {
// テナント別の設定ファイル
'@tenant-config': `./config/tenants/${process.env.TENANT_ID || 'default'}.js`,
// テナント別のテーマ
'@theme': `./src/themes/${process.env.TENANT_ID || 'default'}`,
},
rules: {
// テナント別カスタムコンポーネント
'*.tenant.tsx': {
loaders: [
{
loader: 'string-replace-loader',
options: {
multiple: [
{
search: '{{TENANT_NAME}}',
replace: process.env.TENANT_NAME || 'Default',
},
{
search: '{{TENANT_COLOR}}',
replace: tenantConfig[process.env.TENANT_ID]?.primaryColor || '#000000',
},
],
},
},
],
as: '*.tsx',
},
},
},
};
実際の使用例:
typescript// src/components/Header.tenant.tsx
import React from 'react';
const Header: React.FC = () => {
return (
<header style={{ backgroundColor: '{{TENANT_COLOR}}' }}>
<h1>{{ TENANT_NAME }} Dashboard</h1>
</header>
);
};
export default Header;
ケース 2: 国際化(i18n)対応での動的翻訳
javascript// next.config.js - 多言語対応
const supportedLocales = ['ja', 'en', 'ko', 'zh'];
module.exports = {
turbopack: {
rules: {
// 翻訳ファイルの動的生成
'*.i18n.json': {
loaders: [
{
loader: 'string-replace-loader',
options: {
search: '{{LOCALE}}',
replace: process.env.NEXT_LOCALE || 'ja',
},
},
],
as: '*.json',
},
// 多言語テンプレート
'*.intl.tsx': {
loaders: [
{
loader: '@formatjs/ts-transformer',
options: {
overrideIdFn: '[sha512:contenthash:base64:6]',
},
},
],
as: '*.tsx',
},
},
resolveAlias: {
// ロケール別メッセージファイル
'@messages': `./src/locales/${
process.env.NEXT_LOCALE || 'ja'
}/messages.json`,
},
},
};
ケース 3: GraphQL スキーマの型安全性確保
javascript// next.config.js - GraphQL統合
module.exports = {
turbopack: {
rules: {
// GraphQLスキーマファイル
'*.graphql': {
loaders: ['graphql-tag/loader'],
as: '*.js',
},
// GraphQL型定義生成
'*.gql.ts': {
loaders: [
{
loader: 'string-replace-loader',
options: {
search:
/\/\* GENERATED_TYPES_START \*\/([\s\S]*?)\/\* GENERATED_TYPES_END \*\//,
replace: function () {
// 実際のプロジェクトでは外部スクリプトで型生成
return '/* GENERATED_TYPES_START */\n// Generated types here\n/* GENERATED_TYPES_END */';
},
},
},
],
as: '*.ts',
},
},
resolveAlias: {
'@schema': './src/graphql/schema.graphql',
'@queries': './src/graphql/queries',
},
},
};
デバッグとトラブルシューティング
パフォーマンス測定
bash# Turbopackトレースファイルの生成
NEXT_TURBOPACK_TRACING=1 yarn dev --turbo
# 生成されるファイル
# .next/trace-turbopack - パフォーマンス情報
よくあるエラーと対処法
1. ローダーが見つからないエラー
bashError: Cannot resolve loader 'custom-loader'
対処法:
bash# ローダーをインストール
yarn add -D custom-loader
# または、フルパスで指定
javascriptmodule.exports = {
turbopack: {
rules: {
'*.custom': {
loaders: [require.resolve('custom-loader')],
as: '*.js',
},
},
},
};
2. メモリ不足エラー
bashError: Process ran out of memory
Error: Cannot allocate memory for compilation
対処法:
javascriptmodule.exports = {
turbopack: {
// メモリ制限を増加
memoryLimit: 4 * 1024 * 1024 * 1024, // 4GB
},
};
3. 循環依存エラー
bashError: Circular dependency detected
Module A -> Module B -> Module A
対処法:
javascript// 問題のある循環依存の例
// file-a.ts
import { funcB } from './file-b';
export function funcA() {
return funcB();
}
// file-b.ts
import { funcA } from './file-a';
export function funcB() {
return funcA();
}
javascript// 解決策: 共通モジュールの分離
// shared.ts
export function sharedLogic() {
return 'shared implementation';
}
// file-a.ts
import { sharedLogic } from './shared';
export function funcA() {
return sharedLogic();
}
// file-b.ts
import { sharedLogic } from './shared';
export function funcB() {
return sharedLogic();
}
設定の検証方法
javascript// next.config.js - 設定検証
const { z } = require('zod');
const turbopackConfigSchema = z.object({
rules: z
.record(
z.object({
loaders: z.array(
z.union([
z.string(),
z.object({
loader: z.string(),
options: z.record(z.any()).optional(),
}),
])
),
as: z.string(),
})
)
.optional(),
resolveAlias: z.record(z.string()).optional(),
resolveExtensions: z.array(z.string()).optional(),
});
const config = {
turbopack: {
// 設定内容
},
};
// 設定の検証
try {
turbopackConfigSchema.parse(config.turbopack);
console.log('✅ Turbopack設定は有効です');
} catch (error) {
console.error('❌ Turbopack設定エラー:', error.message);
}
module.exports = config;
まとめ
2025 年 6 月現在、Turbopack のプラグイン開発は過渡期にあります。完全なプラグイン API はまだ開発中ですが、webpack ローダーとの限定的な連携や、設定ベースでのカスタマイズによって、実用的な拡張が可能です。
重要なポイント
- 現在利用可能な機能を活用し、段階的にカスタマイズを進める
- Web 標準に基づいた設計を心がけ、将来の移行に備える
- コミュニティへの参加を通じて、プラグイン API の設計に貢献する
- パフォーマンスを重視し、Turbopack の利点を最大限に活用する
今後の展望
Turbopack は Web 開発の未来を形作る重要なツールです。現在の制限を理解しつつ、将来のプラグインエコシステムに向けて準備を進めることで、次世代の高速 Web 開発を実現できるでしょう。
プラグイン API の正式リリースまでは、本記事で紹介した手法を活用し、Turbopack の恩恵を受けながら開発を進めることをお勧めいたします。新しい情報が公開され次第、本記事も更新していく予定です。
関連リンク
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来
- review
人類はなぜ地球を支配できた?『サピエンス全史 上巻』ユヴァル・ノア・ハラリが解き明かす驚愕の真実
- review
え?世界はこんなに良くなってた!『FACTFULNESS』ハンス・ロスリングが暴く 10 の思い込みの正体
- review
瞬時に答えが出る脳に変身!『ゼロ秒思考』赤羽雄二が贈る思考力爆上げトレーニング
- review
関西弁のゾウに人生変えられた!『夢をかなえるゾウ 1』水野敬也が教えてくれた成功の本質