BiwaSchemeでWebアプリを作る の2
とりあえずMithrilでイベントをScheme側に渡し、値を更新してビューをアップデートするところまで実装できた。 https://github.com/okuoku/biwasyuni-editortest/tree/175a298e14ee2e530cbb3ff197573ba8f4c92f23
リポジトリにはyuniとbiwasyuniをsubmoduleとして入れてあるので、クローンしてsubmoduleをinit、updateし、
cd biwasyuni && yarn yarn yarn start
でポート8080にexpressが上がるようにしている。
ONCLICKのログはScheme側から出力されている。
(define (counter-object m) ;; m はmithril.jsのHyperScriptオブジェクト (define counter 0) (define (onclick e) ;; onclickイベントハンドラ (PCK 'ONCLICK counter e) (set! counter (+ counter 1))) (let ((handler (js-closure onclick))) (js-obj "view" (js-closure (lambda () ;; m("div", {onclick: function(...)}, counter); (js-call m "div.alert.alert-primary[role=alert]" (js-obj "onclick" handler) (number->string counter)))))))
ビルドシステム
- JavaScript側: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/scripts/parcel-run.js
- Scheme側: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/scripts/preroll.scm
ParcelのCLIを使うのは諦め、Parcelのライブラリを使ってビルドする方式を取った。Parcelのビルドシステムはexpress互換のmiddlewareとして使用できるため、Parcelがビルドするファイル以外にSchemeソースコードをserveする都合。
Scheme側は簡易的なyuniのブートストラップを実装している。BiwaScheme自体はR6RSライブラリをサポートしていないためライブラリシステムとしてyuniを使うが、yuniのリポジトリをどうやってビルドするかが課題になる。これを機に、yuniはビルド不要で使えるように、つまり、チェックアウトしたままの状態で使えるように変更していくことにした。
現状、yuniは使用するためにbootstrap schemeのいづれか(Chez、Racket、Sagittarius、Gauche または Chibi-scheme)を使用してブートストラップを行う必要が有るが、これを不要にした方が取り回しが良いと考えられる。今回のケースだと、本来bootstrap schemeでないBiwaSchemeだけの状態でもyuniを使うことができる。
アプリケーションの記述とロード
- JavaScript側エントリポイント: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/index.js
- Scheme側エントリポイント: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/app.sps
- アプリケーション本体: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/yunilib/appmain.sls
- node.jsのFilesystem API風のfetch APIラッパ: https://github.com/okuoku/biwasyuni-editortest/blob/175a298e14ee2e530cbb3ff197573ba8f4c92f23/loader_biwasyuni.js
アプリケーションはyuniのR6RS-lite形式で記述する。アプリケーションのロードは普通にHTML5のfetch APIを使用している。今のところビルドシステムにファイルの結合やminifyの類は実装していないので、ファイルは1つ1つダウンロードされる。
動的なライブラリのロードは未対応で、今のところライブラリファイルは事前にloadしておく必要がある。これはBiwaSchemeがexpand中にPauseできないという制約があるため( https://github.com/okuoku/yuni/issues/109 )。ビルドシステムは事前にどのファイルをloadすべきかを把握できるので、アプリケーションを実装する上ではそんなに障害にはならない。。はず。
今のところMithrilのAPIを直接使用しているが、当然SXMLか何かでwrapしたAPIを出すべきで、どうすれば良いのかは考え中。
展望
重要なポイントは、yuniで書いたアプリケーションを動的なホスティングなしでWebアプリにできる点な気がしている。つまり、ビルド済のyuniのランタイムと今回作成したWeb版biwasyuniを適当にGitHub pagesかどこかに入れておけば、(原理的には、)GitHubのリポジトリ上に配置したyuniアプリを直接起動できることになる。
...別に今クラウドに払っている金額を考えれば(営業のために)動的にアプリをビルドして配信するようなサーバを作ることもコスト的には大したことはないが、組織内での使用などインターネット上にあっても仕方ないケースもある。
当然、見ず知らずのWebアプリを自分のドメインで動かすというのは本質的にXSS脆弱性なので、何らかの対策を入れる必要は有る。例えば、Scheme側からのJavaScript evalを禁止するとか、DOMは信頼したライブラリにしか見せないといった対策は必要だろう。