※本記事は「RailsからLaravelを眺める」シリーズの第4回です。Rails出身の私がLaravelを触りながら、Railsと比較して違いを整理していく連載になります。
はじめに
React や Vue が主流となった現代Web開発ですが、実務の現場を見渡せば「すべてをSPAで作る必要はない」ことは明らかです。多くのシステムでは、サーバーサイドMVCの延長線上でUIを少しリッチにできれば十分です。
そのためにRailsには Hotwire(Turbo/Stimulus) が、Laravelには Livewire(+Alpine.js) が生まれました。どちらも「JSを書かずにUIをリッチ化する」という点では共通していますが、思想と実装は大きく異なります。今回はRailsエンジニアとしての経験を踏まえ、両者の違いをコード例を交えて解説していきます。
背景:HotwireとLivewireの誕生
Railsでは長らくRails UJSとjQueryで非同期処理や部分更新を実現してきました。しかしSPAフレームワークの流行により、RailsアプリでもリッチUIが求められるようになります。React on Railsのような取り込みもありましたが、それはRails Wayからは大きく外れていました。そこで「Railsらしさを残したままモダン化する」ために登場したのがHotwireです。
LaravelはVue.jsを公式に推していた時期がありますが、小〜中規模案件では「Vueを導入するのは重い」「Bladeで完結したい」という声が強くありました。そのニーズに応える形で登場したのがLivewireです。Bladeコンポーネントを強化し、PHPサイドに状態を保持して差分HTMLを返す仕組みは、多くのLaravel開発者に歓迎されました。
思想の違い:HTML指向と状態指向
Hotwireの哲学は「HTML over the wire」。サーバーがHTMLを描画し、それをそのままブラウザに送り、差し替えることでUXを改善します。つまり「ドキュメント」を中心に据える考え方です。
Livewireの哲学は「Component state sync」。コンポーネントごとにサーバーが状態を管理し、イベントが発生するたびに差分HTMLを返します。つまり「状態」を中心に据え、その変化がビューに反映される構造です。
Railsはドキュメント志向、Laravelは状態志向。この根本の差が両者を分けています。
開発体験の違い
RailsでHotwireを使うと、既存のERBやパーシャルをそのまま活かしながらリッチなUIを実現できます。Stimulusを使う場面も「blurイベントで入力検証をする」程度で、HTMLファーストの潔さを損ないません。
LaravelのLivewireは、php artisan make:livewire
でコンポーネントを生成し、Bladeに差し込むだけで動き出します。wire:model
で双方向バインディングが簡単にでき、状態とビューを同期できます。足りない部分はAlpine.jsで補完し、全体としては「PHPから出ない開発体験」が得られます。
コード例で理解するHotwireとLivewire
検索フォーム
RailsのHotwireではTurbo Frameを使って検索結果部分だけを差し替えます。
<%= form_with url: users_path, method: :get, data: { turbo_frame: "results" } do %>
<input type="search" name="q" value="<%= params[:q] %>">
<% end %>
<turbo-frame id="results">
<%= render partial: "users", locals: { users: @users } %>
</turbo-frame>
LaravelのLivewireでは、入力と状態を同期させて再描画します。
class UserSearch extends Component {
public string $q = '';
public function render() {
$users = User::where('name','like',"%{$this->q}%")->get();
return view('livewire.user-search',['users'=>$users]);
}
}
<div>
<input type="search" wire:model.live="q">
@foreach ($users as $user)
<div>{{ $user->name }}</div>
@endforeach
</div>
フォームの即時バリデーション
RailsではStimulusを利用してblurイベントでfetchを飛ばし、Turboでエラーメッセージを差し替えます。
<%= f.email_field :email, data: { action: "blur->instant-validate#check" } %>
<div data-instant-validate-target="error"></div>
LaravelのLivewireでは、validateOnly
を利用して即座にエラーを返します。
class RegisterForm extends Component {
#[Rule('required|email|unique:users,email')]
public string $email = '';
public function updated($prop){ $this->validateOnly($prop); }
}
<input type="email" wire:model.live="email">
@error('email') <div class="text-red-600">{{ $message }}</div> @enderror
無限スクロール
RailsのHotwireはTurbo Frameでページングを行い、その部分だけ差し替えます。
<turbo-frame id="posts" src="/posts?page=2"></turbo-frame>
LaravelのLivewireはページ数を状態で持ち、ロードボタンで増やす方式です。
class PostList extends Component {
public $page = 1;
public function loadMore(){ $this->page++; }
public function render(){
return view('livewire.post-list',[
'posts'=>Post::paginate($this->page*10)
]);
}
}
<div>
@foreach($posts as $post)
<div>{{ $post->title }}</div>
@endforeach
<button wire:click="loadMore">もっと見る</button>
</div>
行内編集(インライン編集)
RailsではTurbo Frameを使って該当部分だけを差し替えます。
<turbo-frame id="user_<%= user.id %>">
<%= render "user", user: user %>
</turbo-frame>
LaravelのLivewireでは、状態をトグルして表示を切り替えます。
class UserRow extends Component {
public User $user;
public bool $editing = false;
public function toggle(){ $this->editing = !$this->editing; }
}
<div>
@if($editing)
<input wire:model="user.name">
<button wire:click="toggle">保存</button>
@else
<span wire:click="toggle">{{ $user->name }}</span>
@endif
</div>
適用領域と現実解
管理画面や業務アプリといった領域では、HotwireもLivewireも強力な選択肢です。Railsなら公式スタックとしてHotwireを導入すれば自然に馴染み、LaravelならLivewireとFilamentを組み合わせれば爆速で管理画面を構築できます。
一方、ユーザー体験が複雑に絡み合う本格SPAでは限界があります。クライアントサイドでの状態管理が大規模になる場合はReactやVueを採用する方が妥当です。
コミュニティ文化の違い
Railsは公式主導で安定的に進化する文化を持ち、Hotwireもその正統進化の一部です。gem文化は枯れていて長寿命です。Laravelはエコシステムの更新が速く、非公式のパッケージでも事実上の標準になることが珍しくありません。LivewireやFilamentはその代表格です。Railsは「安定」、Laravelは「スピード感」と言えるでしょう。
実務での採用判断
Hotwireは公式スタックであり、長期運用に強く、大規模Railsアプリに安心して導入できます。Livewireは開発スピードに優れ、Bladeとの親和性も高いため、管理画面や中小規模の業務アプリに適しています。ただし、どちらもSPAの完全な代替にはならず、必要な場面ではReactやVueと棲み分けるのが現実的です。
まとめ
HotwireとLivewireは、RailsとLaravelという異なる文化の中で同じ課題に挑み、異なるアプローチを生み出しました。Hotwireは「Rails Wayを守りつつHTMLを速く届ける」方向に進化し、Livewireは「Bladeを強化しPHPに居続ける」方向に進化しています。
両者ともSPAを完全に置き換える存在ではありませんが、サーバーサイドMVCを基盤としたままUXを改善できる点で非常に強力な武器です。RailsならHotwire、LaravelならLivewire+Alpine、そしてFilamentを組み合わせることで、開発体験と生産性は大きく変わるでしょう。
次にあなたが選ぶのは、“ドキュメント指向のHotwire”か、“状態指向のLivewire”か。
この比較が、UI戦略を考えるきっかけになれば幸いです。
コメント