Se ha denunciado esta presentación.
Se está descargando tu SlideShare. ×

Tide - SmalltalkでSPA

Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Próximo SlideShare
NanoStrand
NanoStrand
Cargando en…3
×

Eche un vistazo a continuación

1 de 37 Anuncio

Más Contenido Relacionado

Presentaciones para usted (20)

Similares a Tide - SmalltalkでSPA (20)

Anuncio

Más de Masashi Umezawa (20)

Más reciente (20)

Anuncio

Tide - SmalltalkでSPA

  1. 1. Tide - SmalltalkでSPA シングルページWebアプリをSmalltalkで作る 第69回Smalltalk勉強会 合同会社ソフトウメヤ 梅澤真史
  2. 2. Smalltalkで Web? ● 第一世代(90年前半) ○ VisualWave (GUIがそのまま Webブラウザに) ○ Classic Blend (Java Appletと Server Smalltalkと通信) ● 第二世代(2012年くらいまで) ○ Seaside (継続ベース。異端のフレームワーク) ○ AIDA/Web (RESTfulなオブジェクトの集合体) 概して進みすぎていて、理解されない! ● 詳しくは ○ 第9回Smalltalk勉強会の資料「SmalltalkでWeb!」
  3. 3. 第三世代の波 ● 今やシングルページWebアプリの時代 ■ AJAXとDOMの操作ですべてをまかなう ● ページの遷移がない ○ Gmailとか、Google Mapsとか ● 「継続とか、いらなかったんや...」 ● というかSPAに向いたWebアプリもたくさんある ● SPAに特化したSmalltalkのフレームワークの登場! ○ Tide ■ https://github.com/tide-framework/tide ○ Flow ■ https://github.com/flow-stack/flow
  4. 4. Tide - The missing web framework ● 軽量 ○ サーバ側: Pharo ■ 27クラス ○ クライアント側: Amber ■ 14クラス ● Webの普通の仕組みを使う ○ XHRでAJAX ○ Cookieでセッション管理 ● 簡潔 ○ オブジェクトのメッセージ送信を書くとAJAXしてくれる
  5. 5. インストール (1) ● githubから ○ https://github.com/tide-framework/tide ● インストール時にbowerが必要となるので入れておく ○ Node.js のnpmですぐに入る ● Pharo取得 curl get.pharo.org/30+vm | bash ● Pharo起動 ./pharo-ui Pharo.image
  6. 6. インストール (2) ● ConfogurationOfTideで Pharo側をロード Metacello new configuration: 'Tide'; version: #development; repository: 'http://www.smalltalkhub. com/mc/Pharo/MetaRepoForPharo30/main'; load. ● bowerでAmber側をロード bower install (ConfogurationOfTideで取得された Amberのディレクトリに移動して)
  7. 7. 動作の確認 ● Pharoのワークスペースで TDDispatcher tideIndexPageUrl ”print it” ● URLをWebブラウザにペーストでAmberが立ち上がる ● Amberのワークスペースから TDCounterWidget new render ● Seasideでおなじみのカウンターアプリが立ち上がる ● 動作確認後、Pharoのイメージを保存しておく
  8. 8. クライアント側コード ● Heliosのブラウザを上げてTDCounterWidgetを見てみる
  9. 9. TDCounterWidget ● クラス定義 Widget subclass: #TDCounterWidget instanceVariableNames: 'counter header' package: 'Tide-Amber-Examples' ● レンダリング renderOn: html header := html h1 with: self counter count asString. html button with: '++'; onClick: [ self increase ]. html button with: '--'; onClick: [ self decrease ] なにやら Seaside っぽい
  10. 10. プロキシの存在 ● TDCounterWidget >> counter (‘accessing’) counter ^ counter ifNil: [ counter := TDClientProxy on: '/counter' ] ● TDCounterWidget >> increase (‘actions’) increase self counter increase. self counter then: [ self update ] ● プロキシ経由でサーバにメッセージ送信 ● 非同期を待ってthen:でアップデートをかけている!
  11. 11. 何が送られているのか? ● Webブラウザの開発者用ツールで覗いてみる
  12. 12. こんな感じの JSON {"__id__":"cpacwb3c83uxa9icxs39o9g9r", "actions":{"increase":"/counter?_callback=798013338"," update":"/counter?_callback=784201227","decrease":" /counter?_callback=634370664"}, "state":{"tidePresenterString":"a TDPresenter","count": 7}} ● オブジェクトID(__id__) ● アクションとコールバック用ID(actions) ● 状態(state)
  13. 13. セッション情報はCookieに ● 普通でいい感じ
  14. 14. サーバ側では ● PharoのブラウザでTDCounterを確認
  15. 15. TDCounter ● クラス定義 TDPresenter subclass: #TDCounter instanceVariableNames: 'count' classVariableNames: '' category: 'Tide-Examples' ● 初期化 initialize super initialize. count := 0 ● TDPresenterを継承している ● 状態保持用にcountを持つだけ
  16. 16. <state>と<action> ● TDCounter >> count (‘accessing’) ● TDCounter >> increase (‘actions’) ● モデル更新の処理を平凡に書く ● <state>, <action> のpragma指定でJSONに変換され、ク ライアントに送られる count <state> ^ count increase <action> count := count + 1
  17. 17. 演習: Todoを作ってみる ● Pharo側にTDTodoPresenter, TDTodoList, TDTodoItem が用意されている 作れということ!
  18. 18. Todoのサーバ側 (1) ● TDTodoPresenter ○ TDPresenter を継承 ○ <state>toDoListとしてTDTodoListを保持 ○ ‘todo’というURLで自己を登録している ● TDTodoList ○ Objectを継承。単なるモデル ○ <state>itemsとしてTDTodoItemを保持 ○ <action>addItemLabeled: aString ○ <action>removeItem: anItem を定義
  19. 19. Todoのサーバ側 (2) ● TDTodoItem ○ Objectを継承。単なるモデル ○ <state>label, <state>completed を持つ サーバ側は以上。何の変哲もないつくり。素直。 ● 以上をふまえ、クライアント側(Amber)を作ってみる!
  20. 20. Todo用のhtmlを用意 ● いちいち Heliosからdo itするのが面倒なので、 Todo起動用のhtmlを作っておく ● index.htmlと同じ場所に置く(tide-framework-tide-xxx下) ● index.htmlをコピーしてJSの最後の部分を書き換える function (smalltalk) { smalltalk.initialize({defaultAmdNamespace: 'tide'}); smalltalk.TDTodoWidget._new()._render(); ● URL指定で Todoが立ち上がるようになる (TDTodoWidgetはこれから作ります!) }
  21. 21. TDTodoWidget の基本メソッド群 ● クラス定義 ● Widget subclass: #TDTodoWidget instanceVariableNames: 'todo listPart' package: 'Tide-Amber-Examples' ● アクセッサ todo ^ todo ifNil: [ todo := TDClientProxy on: '/todo' ] list ^self todo todoList
  22. 22. TDTodoWidget レンダリング (1) render self todo connect. self todo then: [ self appendToJQuery: 'body' asJQuery ] ● はじめにconnectしておくのが特徴 ● DOMにくっつけるところは通常のAmberと同じ (ただしthen:を使ってconnectの結果を待っている)
  23. 23. TDTodoWidget レンダリング (2) renderOn: html html h1: 'Tide-Todo'. listPart := html div class: 'listPart'; with: [ self renderListOn: html ]. html button with: '+'; onClick: [self addItemLabelled: self askTodo]. ● 後のアップデートのため、listPartインスタンス変数にTagBrushを 入れておく ● onClick: イベントハンドラでTodo追加の処理を書く
  24. 24. TDTodoWidget イベントハンドラ addItemLabelled: aString self list addItemLabelled: aString. self list then: [ self update ] ● プロキシ経由で<action> addItemLabelled: を送信 ● then:後にアップデート askTodo ^BrowserInterface new prompt: 'Todo?' ● Todo項目の入力用UIを作るのが面倒なので、 BrowserInterface>>prompt:で対応
  25. 25. CSSで見栄えよく ● todo.cssを書いて、todo.htmlから参照させる ● 中身はご自由に h1 { color: #333333; background-color:#cccccc; } body { background-color:#66ccff; } ul { list-style-type: none; margin-left:10px; font-size:120%; } .label {padding:10px;} .listPart{ background-color:#b2e5ff; }
  26. 26. updateの中身 update listPart contents: [:html | self renderListOn: html ] ● renderOn: で捕まえておいたlistPartのTagBrushを使い、 特定DOM部分(<div class=’listPart’>)のみを再描画
  27. 27. レンダリング続き (1) renderListOn: html html ul: [ self list items do: [:each | html li:[self renderItem: each on: html]] ] ● プロキシ経由でitemsを得て、個々をrenderItem:on:で レンダリング
  28. 28. レンダリング続き (2) renderItem: each on: html | chkbox | chkbox := html input class: 'completed'; type: 'checkbox'. chkbox onClick: [ each completed: each completed not. chkbox asJQuery attr: 'checked' to: each completed ]. each completed ifTrue: [chkbox at: 'checked' put: 'checked']. html span class: 'label'; with: each label ● <action> completed:や<state>labelを利用 ● チェックボックスを即座に更新するためasJQueryでDOMを とらえて’checked’属性を変えている
  29. 29. 演習2: Todo項目を削除できるように ● 今のところ、 Todo項目の削除機能がない ● チェックした項目を削除するには? ● Pharo側に<action> removeItem: anItem があるので これを使うことを考えてみる
  30. 30. 新たな<action>の追加 ● 選択したTodo項目を一度に消すため、Pharo側に <action>removeCheckedItemsを作ってみる removeCheckedItems <action> self items do: [:each | each completed ifTrue: [self removeItem: each] ].
  31. 31. レンダリングコードの修正 ● Amberに戻り、renderOn:を修正、削除ボタンをつける renderOn: html ... html button with: '-'; onClick: [self removeCheckedItems]. ● クリック時のコールバックでremoveCheckedItemsを 指定
  32. 32. 削除用のコールバックを実装 removeCheckedItems self list removeCheckedItems. self list then: [ self update ] ● プロキシ経由でremoveCheckedItemsをメッセージ送信 ● 結果を待って更新 完成!!
  33. 33. おまけ: セッションの様子を見る TDDispatcher default sessionManager explore. ● Pharo側で”do it” ● セッションの状態、アクティブなプレゼンターなどを観察でき る
  34. 34. まとめ ● TideはSmalltalkでSPAを作るための軽量フレームワーク ● メッセージ送信と若干のpragmaで書け、AJAXの詳細は意識 する必要がない ● 定番のWeb技術を素直に使っているため拡張も楽 ○ CSSで見栄えの調整 ○ AmberのCanvasが嫌な場合は、Handlebarsなど、 クライアントサイドJSONテンプレートも使える(はず) ● Tideで作られたCMS、Marinaも見てみよう! https://github.com/tide-framework/marina

×