Rspack完全ガイド - Rust製高速バンドラーでwebpackから移行
Rspack完全ガイド
はじめに
Rspack(アールスパック)は、2023年にByteDance社が開発し、2026年現在、webpack互換の高速バンドラーとして急速に普及しています。
Rspackとは
Rspackは、Rust製のJavaScriptバンドラーで、以下の特徴があります。
- 10倍高速: webpackの10倍以上の速度
- webpack互換: 既存のwebpack設定をほぼそのまま使用可能
- Rust製: 並列処理による高速化
- プラグイン対応: webpack loaderとpluginの大部分をサポート
- 開発体験: HMR(Hot Module Replacement)が高速
- 大規模対応: 数万ファイルでも高速
他のバンドラーとの比較
| 項目 | webpack | Rspack | Vite | Turbopack |
|---|---|---|---|---|
| ビルド速度 | 遅い | 速い | 速い | 最速 |
| 開発サーバー | 遅い | 速い | 最速 | 速い |
| webpack互換 | 100% | 90% | 20% | 0% |
| 学習コスト | 高 | 低(webpack経験者) | 中 | 未知数 |
| エコシステム | 最大 | 成長中 | 大 | 小 |
| 安定性 | 安定 | 安定 | 安定 | 開発中 |
| 本番利用 | ◎ | ◎ | ◎ | △ |
なぜRspackを選ぶのか
理由1: webpackからの移行コストが低い
設定ファイルがほぼ同じ
→ 既存プロジェクトを簡単に移行
理由2: 圧倒的な速度
大規模プロジェクトで特に効果大
→ ビルド時間が1/10に短縮
理由3: webpackエコシステムが使える
既存のloaderとpluginが動く
→ 新しいツールを学ぶ必要なし
理由4: Next.js対応
Next.jsの実験的サポートあり
→ Next.jsでも高速ビルド
セットアップ
新規プロジェクト作成
# CLIでプロジェクト作成
npm create rspack@latest
# 対話形式で選択
? Project name: my-app
? Select template: React
? Use TypeScript? Yes
? Use CSS? Yes
既存プロジェクトへの追加
# Rspackインストール
npm install -D @rspack/core @rspack/cli
# Reactプロジェクトの場合
npm install -D @rspack/plugin-react-refresh
プロジェクト構造
my-app/
├── src/
│ ├── index.tsx
│ ├── App.tsx
│ └── styles.css
├── public/
│ └── index.html
├── rspack.config.js
├── package.json
└── tsconfig.json
基本的な設定ファイル
// rspack.config.js
const path = require('path');
const rspack = require('@rspack/core');
/** @type {import('@rspack/cli').Configuration} */
module.exports = {
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'builtin:swc-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
type: 'javascript/auto',
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new rspack.HtmlRspackPlugin({
template: './public/index.html',
}),
],
devServer: {
port: 3000,
hot: true,
},
};
package.json scripts
{
"scripts": {
"dev": "rspack serve",
"build": "rspack build",
"preview": "rspack serve --mode production"
}
}
webpackからの移行
移行手順
1. Rspackインストール
npm install -D @rspack/core @rspack/cli
2. webpack.config.jsをコピー
cp webpack.config.js rspack.config.js
3. 互換性のない設定を修正(後述)
4. ビルドテスト
npx rspack build
5. 開発サーバー起動
npx rspack serve
6. 動作確認
ブラウザで http://localhost:3000
互換性のある設定
以下のwebpack設定はそのまま動作します。
// ✅ そのまま使える設定
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif)$/,
type: 'asset/resource',
},
],
},
devServer: {
port: 3000,
hot: true,
},
};
互換性のない設定
// ❌ Rspackでは動作しない
// 1. webpack 4のmode
mode: 'development', // Rspackでは --mode フラグで指定
// 2. 一部のwebpack plugin
new webpack.DefinePlugin({ ... }) // → rspack.DefinePlugin
// 3. 特殊なloader設定
{
loader: 'babel-loader',
options: {
// 複雑な設定は動かない可能性
}
}
修正例
// webpack.config.js(変更前)
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com'),
}),
],
};
// rspack.config.js(変更後)
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com'),
}),
],
};
babel-loaderからの移行
Rspackは内蔵のSWCを使用するため、babel-loaderは不要です。
// webpack(変更前)
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
}
// Rspack(変更後)
{
test: /\.jsx?$/,
use: 'builtin:swc-loader',
exclude: /node_modules/,
options: {
jsc: {
parser: {
syntax: 'ecmascript',
jsx: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
},
}
TypeScript対応
基本的なTypeScript設定
// rspack.config.js
module.exports = {
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'builtin:swc-loader',
exclude: /node_modules/,
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
},
},
},
},
],
},
};
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Path Alias設定
// rspack.config.js
const path = require('path');
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils'),
},
},
};
使用例:
// ✅ Path Aliasを使用
import { Button } from '@components/Button';
import { formatDate } from '@utils/date';
// ❌ 相対パス(避ける)
import { Button } from '../../../components/Button';
React統合
React + TypeScriptプロジェクト
// rspack.config.js
const rspack = require('@rspack/core');
const ReactRefreshPlugin = require('@rspack/plugin-react-refresh');
const isDev = process.env.NODE_ENV === 'development';
module.exports = {
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'builtin:swc-loader',
exclude: /node_modules/,
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
},
transform: {
react: {
runtime: 'automatic',
development: isDev,
refresh: isDev,
},
},
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
type: 'javascript/auto',
},
],
},
plugins: [
new rspack.HtmlRspackPlugin({
template: './public/index.html',
}),
isDev && new ReactRefreshPlugin(),
].filter(Boolean),
devServer: {
port: 3000,
hot: true,
open: true,
},
};
CSS Modules対応
// rspack.config.js
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]--[hash:base64:5]',
},
},
},
],
type: 'javascript/auto',
}
使用例:
/* Button.module.css */
.button {
padding: 10px 20px;
background-color: blue;
color: white;
}
// Button.tsx
import styles from './Button.module.css';
export function Button() {
return <button className={styles.button}>Click me</button>;
}
Tailwind CSS統合
# インストール
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// rspack.config.js
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
],
type: 'javascript/auto',
}
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
プラグイン
組み込みプラグイン
Rspackは主要なwebpackプラグインを内蔵しています。
const rspack = require('@rspack/core');
module.exports = {
plugins: [
// HTML生成
new rspack.HtmlRspackPlugin({
template: './public/index.html',
title: 'My App',
}),
// 環境変数定義
new rspack.DefinePlugin({
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
// プログレス表示
new rspack.ProgressPlugin(),
// CSS抽出
new rspack.CssExtractRspackPlugin({
filename: '[name].[contenthash].css',
}),
],
};
webpack pluginの互換性
多くのwebpack pluginがそのまま動作します。
// ✅ 動作するwebpack plugin
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new BundleAnalyzerPlugin(),
new CompressionPlugin(),
],
};
カスタムプラグイン
// plugins/CustomPlugin.js
class CustomPlugin {
apply(compiler) {
compiler.hooks.done.tap('CustomPlugin', (stats) => {
console.log('Build completed!');
console.log(`Time: ${stats.endTime - stats.startTime}ms`);
});
}
}
module.exports = CustomPlugin;
// rspack.config.js
const CustomPlugin = require('./plugins/CustomPlugin');
module.exports = {
plugins: [
new CustomPlugin(),
],
};
パフォーマンス最適化
Code Splitting
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
},
common: {
minChunks: 2,
name: 'common',
priority: 5,
},
},
},
},
};
Dynamic Import
// 動的インポート
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
);
}
Tree Shaking
module.exports = {
optimization: {
usedExports: true, // 未使用exportを削除
sideEffects: false, // 副作用なしとマーク
},
};
// package.json
{
"sideEffects": false
}
キャッシング
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
};
並列処理
Rspackはデフォルトで並列処理を行います。
module.exports = {
experiments: {
// 並列ビルドの最大スレッド数
parallelism: 4,
},
};
本番ビルド
本番用設定
// rspack.config.prod.js
const rspack = require('@rspack/core');
module.exports = {
mode: 'production',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
clean: true,
},
optimization: {
minimize: true,
minimizer: [
new rspack.SwcJsMinimizerRspackPlugin(),
new rspack.LightningCssMinimizerRspackPlugin(),
],
splitChunks: {
chunks: 'all',
},
},
plugins: [
new rspack.CssExtractRspackPlugin({
filename: '[name].[contenthash:8].css',
}),
],
};
環境変数
// rspack.config.js
const rspack = require('@rspack/core');
module.exports = {
plugins: [
new rspack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
],
};
# .env.production
API_URL=https://api.production.com
ビルドコマンド
{
"scripts": {
"build": "cross-env NODE_ENV=production rspack build",
"build:analyze": "cross-env NODE_ENV=production ANALYZE=true rspack build"
}
}
バンドルサイズ分析
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
process.env.ANALYZE && new BundleAnalyzerPlugin(),
].filter(Boolean),
};
npm run build:analyze
ベンチマーク結果
実測例1: 中規模Reactアプリ
プロジェクト: 500ファイル、50,000行
webpack 5:
開発ビルド: 12.3秒
本番ビルド: 45.2秒
HMR: 800ms
Rspack:
開発ビルド: 1.1秒 (11倍高速)
本番ビルド: 4.8秒 (9.4倍高速)
HMR: 120ms (6.7倍高速)
実測例2: 大規模モノレポ
プロジェクト: 5,000ファイル、500,000行
webpack 5:
開発ビルド: 180秒
本番ビルド: 600秒
Rspack:
開発ビルド: 12秒 (15倍高速)
本番ビルド: 52秒 (11.5倍高速)
メモリ使用量
webpack: 2.8GB
Rspack: 1.2GB (57%削減)
Next.js統合(実験的)
Next.js + Rspack
Next.js 15からRspackの実験的サポートがあります。
// next.config.js
module.exports = {
experimental: {
webpackBuildWorker: true,
rspack: true,
},
};
制限事項
現時点での制限:
- 一部のNext.js機能が未対応
- 安定性が開発中
- 本番利用は慎重に
推奨:
- 開発環境でのみ使用
- 定期的にNext.jsリリースノート確認
トラブルシューティング
エラー1: モジュールが見つからない
エラー: Module not found: Error: Can't resolve '@/components/Button'
解決策:
1. resolve.aliasを確認
2. tsconfig.jsonのpathsと一致させる
3. ファイルの存在を確認
エラー2: loaderが動作しない
エラー: You may need an appropriate loader
解決策:
1. type: 'javascript/auto' を追加
2. loaderの順序を確認(右から左に実行)
3. webpack loaderの互換性を確認
エラー3: HMRが動作しない
解決策:
1. devServer.hot: true を設定
2. React Refresh Pluginを追加
3. ブラウザコンソールでエラー確認
パフォーマンスが遅い
改善策:
1. cache: { type: 'filesystem' } を有効化
2. 不要なloaderを削除
3. exclude: /node_modules/ を設定
4. 並列処理を確認
まとめ
Rspackの強み
- 圧倒的速度: webpackの10倍以上
- 互換性: webpack設定をほぼそのまま使用可能
- 安定性: 本番環境で使用可能
- 開発体験: 高速HMR
- 大規模対応: モノレポでも高速
ベストプラクティス
- webpackから段階的に移行
- キャッシュを有効化してさらに高速化
- Code Splittingで最適化
- バンドルサイズ分析で肥大化防止
- 本番ビルド前に十分テスト
いつRspackを使うべきか
- webpackのビルドが遅い
- 大規模プロジェクト(1000+ファイル)
- モノレポ構成
- 開発サーバーの起動を高速化したい
次のステップ
- 公式ドキュメント: https://www.rspack.dev/
- GitHub: https://github.com/web-infra-dev/rspack
- Discord: コミュニティに参加
- サンプル: https://github.com/web-infra-dev/rspack-examples
Rspackで、ビルド時間を劇的に短縮しましょう。