tide - smalltalkでspa

37
Tide - SmalltalkSPA シングルページWebアプリをSmalltalkで作る 69Smalltalk勉強会 合同会社ソフトウメヤ 梅澤真史

Upload: masashi-umezawa

Post on 18-Jun-2015

403 views

Category:

Software


1 download

DESCRIPTION

SmalltalkのシングルページWebアプリフレームワーク、Tideのハンズオン用資料です

TRANSCRIPT

Page 1: Tide - SmalltalkでSPA

Tide - SmalltalkでSPAシングルページWebアプリをSmalltalkで作る

第69回Smalltalk勉強会合同会社ソフトウメヤ 梅澤真史

Page 2: Tide - SmalltalkでSPA

Smalltalkで Web?

● 第一世代(90年前半)○ VisualWave (GUIがそのまま Webブラウザに)

○ Classic Blend (Java Appletと Server Smalltalkと通信)

● 第二世代(2012年くらいまで)○ Seaside (継続ベース。異端のフレームワーク)

○ AIDA/Web (RESTfulなオブジェクトの集合体)

概して進みすぎていて、理解されない!

● 詳しくは

○ 第9回Smalltalk勉強会の資料「SmalltalkでWeb!」

Page 3: Tide - SmalltalkでSPA

第三世代の波

● 今やシングルページWebアプリの時代

■ AJAXとDOMの操作ですべてをまかなう● ページの遷移がない

○ Gmailとか、Google Mapsとか

● 「継続とか、いらなかったんや...」● というかSPAに向いたWebアプリもたくさんある

● SPAに特化したSmalltalkのフレームワークの登場!○ Tide

■ https://github.com/tide-framework/tide○ Flow

■ https://github.com/flow-stack/flow

Page 4: Tide - SmalltalkでSPA

Tide - The missing web framework

● 軽量

○ サーバ側: Pharo■ 27クラス

○ クライアント側: Amber■ 14クラス

● Webの普通の仕組みを使う

○ XHRでAJAX○ Cookieでセッション管理

● 簡潔

○ オブジェクトのメッセージ送信を書くとAJAXしてくれる

Page 5: Tide - SmalltalkでSPA

インストール (1)

● githubから

○ https://github.com/tide-framework/tide● インストール時にbowerが必要となるので入れておく

○ Node.js のnpmですぐに入る

● Pharo取得

● Pharo起動

curl get.pharo.org/30+vm | bash

./pharo-ui Pharo.image

Page 6: Tide - SmalltalkでSPA

インストール (2)

● ConfogurationOfTideで Pharo側をロード

Metacello new configuration: 'Tide'; version: #development; repository: 'http://www.smalltalkhub.com/mc/Pharo/MetaRepoForPharo30/main'; load.

● bowerでAmber側をロード

(ConfogurationOfTideで取得された Amberのディレクトリに移動して)

bower install

Page 7: Tide - SmalltalkでSPA

動作の確認

● Pharoのワークスペースで

● URLをWebブラウザにペーストでAmberが立ち上がる

● Amberのワークスペースから

● Seasideでおなじみのカウンターアプリが立ち上がる

● 動作確認後、Pharoのイメージを保存しておく

TDDispatcher tideIndexPageUrl ”print it”

TDCounterWidget new render

Page 8: Tide - SmalltalkでSPA

クライアント側コード

● Heliosのブラウザを上げてTDCounterWidgetを見てみる

Page 9: Tide - SmalltalkでSPA

TDCounterWidget● クラス定義

● レンダリング

なにやら Seaside っぽい

Widget subclass: #TDCounterWidgetinstanceVariableNames: 'counter header'package: 'Tide-Amber-Examples'

renderOn: htmlheader := html h1 with: self counter count asString.html button

with: '++';onClick: [ self increase ].

html button with: '--';onClick: [ self decrease ]

Page 10: Tide - SmalltalkでSPA

プロキシの存在

● TDCounterWidget >> counter (‘accessing’)

● TDCounterWidget >> increase (‘actions’)

● プロキシ経由でサーバにメッセージ送信

● 非同期を待ってthen:でアップデートをかけている!

counter^ counter ifNil: [ counter := TDClientProxy on: '/counter' ]

increaseself counter increase.self counter then: [ self update ]

Page 11: Tide - SmalltalkでSPA

何が送られているのか?

● Webブラウザの開発者用ツールで覗いてみる

Page 12: Tide - SmalltalkでSPA

こんな感じの JSON

● オブジェクトID(__id__)● アクションとコールバック用ID(actions)● 状態(state)

{"__id__":"cpacwb3c83uxa9icxs39o9g9r","actions":{"increase":"/counter?_callback=798013338","update":"/counter?_callback=784201227","decrease":"/counter?_callback=634370664"},"state":{"tidePresenterString":"a TDPresenter","count":7}}

Page 13: Tide - SmalltalkでSPA

セッション情報はCookieに

● 普通でいい感じ

Page 14: Tide - SmalltalkでSPA

サーバ側では

● PharoのブラウザでTDCounterを確認

Page 15: Tide - SmalltalkでSPA

TDCounter

● クラス定義

● 初期化

● TDPresenterを継承している

● 状態保持用にcountを持つだけ

TDPresenter subclass: #TDCounterinstanceVariableNames: 'count'classVariableNames: ''category: 'Tide-Examples'

initializesuper initialize.count := 0

Page 16: Tide - SmalltalkでSPA

<state>と<action>

● TDCounter >> count (‘accessing’)

● TDCounter >> increase (‘actions’)

● モデル更新の処理を平凡に書く

● <state>, <action> のpragma指定でJSONに変換され、ク

ライアントに送られる

count<state>^ count

increase<action>count := count + 1

Page 17: Tide - SmalltalkでSPA

演習: Todoを作ってみる

● Pharo側にTDTodoPresenter, TDTodoList, TDTodoItemが用意されている

作れということ!

Page 18: Tide - SmalltalkでSPA

Todoのサーバ側 (1)

● TDTodoPresenter○ TDPresenter を継承

○ <state>toDoListとしてTDTodoListを保持

○ ‘todo’というURLで自己を登録している

● TDTodoList○ Objectを継承。単なるモデル

○ <state>itemsとしてTDTodoItemを保持

○ <action>addItemLabeled: aString○ <action>removeItem: anItem を定義

Page 19: Tide - SmalltalkでSPA

Todoのサーバ側 (2)

● TDTodoItem○ Objectを継承。単なるモデル

○ <state>label, <state>completed を持つ

サーバ側は以上。何の変哲もないつくり。素直。

● 以上をふまえ、クライアント側(Amber)を作ってみる!

Page 20: Tide - SmalltalkでSPA

Todo用のhtmlを用意

● いちいち Heliosからdo itするのが面倒なので、

Todo起動用のhtmlを作っておく

● index.htmlと同じ場所に置く(tide-framework-tide-xxx下)● index.htmlをコピーしてJSの最後の部分を書き換える

● URL指定で Todoが立ち上がるようになる

(TDTodoWidgetはこれから作ります!)

function (smalltalk) { smalltalk.initialize({defaultAmdNamespace: 'tide'}); smalltalk.TDTodoWidget._new()._render();}

Page 21: Tide - SmalltalkでSPA

TDTodoWidget の基本メソッド群

● クラス定義●

● アクセッサ

Widget subclass: #TDTodoWidgetinstanceVariableNames: 'todo listPart'package: 'Tide-Amber-Examples'

todo^ todo ifNil: [ todo := TDClientProxy on: '/todo' ]

list^self todo todoList

Page 22: Tide - SmalltalkでSPA

TDTodoWidget レンダリング (1)

● はじめにconnectしておくのが特徴

● DOMにくっつけるところは通常のAmberと同じ

(ただしthen:を使ってconnectの結果を待っている)

renderself todo connect.self todo then: [ self appendToJQuery: 'body' asJQuery ]

Page 23: Tide - SmalltalkでSPA

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追加の処理を書く

Page 24: Tide - SmalltalkでSPA

TDTodoWidget イベントハンドラ

● プロキシ経由で<action> addItemLabelled: を送信

● then:後にアップデート

addItemLabelled: aStringself list addItemLabelled: aString.self list then: [ self update ]

askTodo^BrowserInterface new prompt: 'Todo?'

● Todo項目の入力用UIを作るのが面倒なので、BrowserInterface>>prompt:で対応

Page 25: Tide - SmalltalkでSPA
Page 26: Tide - SmalltalkでSPA

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;}

Page 27: Tide - SmalltalkでSPA

updateの中身

updatelistPart contents: [:html |

self renderListOn: html]

● renderOn: で捕まえておいたlistPartのTagBrushを使い、特定DOM部分(<div class=’listPart’>)のみを再描画

Page 28: Tide - SmalltalkでSPA

レンダリング続き (1)

● プロキシ経由でitemsを得て、個々をrenderItem:on:でレンダリング

renderListOn: htmlhtml ul: [ self list items do: [:each | html li:[self renderItem: each on: html]]]

Page 29: Tide - SmalltalkでSPA

レンダリング続き (2)

● <action> completed:や<state>labelを利用

● チェックボックスを即座に更新するためasJQueryでDOMを

とらえて’checked’属性を変えている

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

Page 30: Tide - SmalltalkでSPA
Page 31: Tide - SmalltalkでSPA

演習2: Todo項目を削除できるように

● 今のところ、 Todo項目の削除機能がない

● チェックした項目を削除するには?

● Pharo側に<action> removeItem: anItem があるので

これを使うことを考えてみる

Page 32: Tide - SmalltalkでSPA

新たな<action>の追加

● 選択したTodo項目を一度に消すため、Pharo側に

<action>removeCheckedItemsを作ってみる

removeCheckedItems<action>self items do: [:each |

each completed ifTrue: [self removeItem: each]].

Page 33: Tide - SmalltalkでSPA

レンダリングコードの修正

● Amberに戻り、renderOn:を修正、削除ボタンをつける

● クリック時のコールバックでremoveCheckedItemsを指定

renderOn: html...html button

with: '-';onClick: [self removeCheckedItems].

Page 34: Tide - SmalltalkでSPA

削除用のコールバックを実装

● プロキシ経由でremoveCheckedItemsをメッセージ送信

● 結果を待って更新

完成!!

removeCheckedItemsself list removeCheckedItems.self list then: [ self update ]

Page 35: Tide - SmalltalkでSPA
Page 36: Tide - SmalltalkでSPA

● Pharo側で”do it”● セッションの状態、アクティブなプレゼンターなどを観察でき

おまけ: セッションの様子を見る

TDDispatcher default sessionManager explore.

Page 37: Tide - SmalltalkでSPA

まとめ

● TideはSmalltalkでSPAを作るための軽量フレームワーク

● メッセージ送信と若干のpragmaで書け、AJAXの詳細は意識

する必要がない

● 定番のWeb技術を素直に使っているため拡張も楽

○ CSSで見栄えの調整

○ AmberのCanvasが嫌な場合は、Handlebarsなど、

クライアントサイドJSONテンプレートも使える(はず)

● Tideで作られたCMS、Marinaも見てみよう!https://github.com/tide-framework/marina