6
6

More than 1 year has passed since last update.

RubyでSPAを構築してみました

Last updated at Posted at 2022-05-05

はじめに

RubyのWebAssemblyビルドを使ってSPA(single page application)を構築するためのパッケージ"Bormaŝino"を開発し、TodoMVC移植してみました
本記事ではパッケージの紹介及び移植されたコードを解説します。

デモ

パッケージ"Bormaŝino"について

コンセプト

伝統的な「フォームを表示し」「POSTされる内容でデータストアを更新し」「データストアに保持されている内容を元に画面を表示する」だけのアプリケーションを通信時間が0に近い状態で走らせれば、いわゆるSPA的な操作感が得られるのでは?

という考えに基づき、Sinatra1を用いて構築された伝統的なWebアプリケーションをブラウザ内で動作させる環境を提供するパッケージが"Bormaŝino"です。
この構成により以下の項目を実現しました。

  • アプリケーションの実装は伝統的なWebアプリケーションのそれと似通っており、学習負荷が低い
  • 既存のrubygems等の資産を流用できる

現状出来ること

  • いわゆるSPA的な画面遷移
  • LocalStorageの読み書き
  • ユーザ入力の取扱い

構成

次の2つのパッケージから構成されています。

また、アプリケーションのテンプレートを用意してあります。
https://github.com/keyasuda/bormashino-app-template

依存関係

主に以下のプロダクトに依存しています。

TodoMVC移植版のコードについて

ファイル構成

.
├── js
│   ├── app.js          ページ読み込み後にruby.wasmを読み込み起動するブートストラップコード
│   └── index.html      アプリケーションの外枠
├── spec
│   └── todo_spec.rb    Todoクラスのユニットテスト
└── src
    ├── app.rb          アプリケーションの中心部。Sinatra::Baseを継承したクラス
    ├── bootstrap.rb    ruby.wasm起動後のブートストラップコード
    ├── todo.rb         Todoクラス。LocalStorageへの読み書きを(Bormashino::LocalStorage経由で)行う
    └── views
        ├── index.erb   Todo一覧を内包する画面
        └── todo.erb    Todo一件を表示するERB断片

アプリケーションの実質的な実装はこれらのファイルに記述されています。

リンクの扱い/ルーティング

<li>
  <a href="/" <% if request.path_info == '/' %>class="selected"<% end %>>All</a>
</li>
<li>
  <a href="/active" <% if request.path_info == '/active' %>class="selected"<% end %>>Active</a>
</li>
<li>
  <a href="/completed" <% if request.path_info == '/completed' %>class="selected"<% end %>>Completed</a>
</li>

ドメイン名を含まないリンクは画面更新時に自動でonclickイベントハンドラが設定され、クリック時にアプリケーションへのGETリクエストが行われます。

<p>Created by <a href="https://github.com/keyasuda">@keyasuda</a></p>
<p>An <a href="https://github.com/keyasuda/bormashino">Bormaŝino</a> port of <a href="http://todomvc.com">TodoMVC</a></p>

他ドメイン名へのリンクにはイベントハンドラは設定されず、通常のリンクとして機能します。

フォームの扱い

<form action="/todos/all" method="PUT">

formは拡張されており、methodに標準のget,postの他put,patch及びdeleteを指定可能です。
リンクと同様に自動でイベントハンドラが設定され、submitでアプリケーションへリクエストが行われます。

フォーム中の子要素に対する操作

<input
  class="toggle"
  data-bormashino-submit-on="change"
  type="checkbox"
  name="completed"
  <% if todo.completed %>checked<% end %>>

フォーム中にdata-bormashino-submit-onという属性を持った要素がある場合、その要素で指定されているイベント(この例ではonclick)が対象の要素で発生した場合に親となるフォームがsubmitされる仕組みを組み込んであります。これを利用してチェックボックスのクリックでTodoのactive/completed状態を更新しています。

ローカルストレージの利用

window.localStorageのラッパーとしてBormashino::LocalStorageを用意してあります。Todoの内容はTodoMVCの仕様通りにtodos-bormashinoキー以下にJSONとして格納されます。

JavaScriptとの統合

window.bormashino = RubyApplication

window.bormashinoにアプリケーション操作用のオブジェクトがセットされています。
https://github.com/keyasuda/bormashino-todomvc/blob/main/src/views/todo.erb#L11

<label ondblclick='bormashino.router.pushState(<%= "#{request.path_info}?edit=#{todo.id}".to_json %>)'><%= todo.title %></label>

本TodoMVCデモ実装ではTodoのダブルクリックで編集モードに入れるためにondblclickハンドラが設定されています。

おわりに

パッケージ"Bormaŝino"を用いてRubyでTodoMVCと同様のSPAが構築できました。今後、以下のような追加機能開発を予定しています。

  • Fetch APIのラッパー実装
  • JavaScriptとの統合機能強化
    • 画面更新時に発生するイベントの追加

Railsのように気の利いたコードジェネレータはありませんが、テンプレートを用意してありますのでどうぞお試し下さい。

2022-05-15追記: 続きを書きました

  1. に限らずRack protocol準拠のWebアプリケーションフレームワークであれば動く可能性はありますが未検証です

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6