Más contenido relacionado La actualidad más candente (20) Similar a Tide - SmalltalkでSPA (20) Más de Masashi Umezawa (20) Tide - SmalltalkでSPA2. Smalltalkで Web?
● 第一世代(90年前半)
○ VisualWave (GUIがそのまま Webブラウザに)
○ Classic Blend (Java Appletと Server Smalltalkと通信)
● 第二世代(2012年くらいまで)
○ Seaside (継続ベース。異端のフレームワーク)
○ AIDA/Web (RESTfulなオブジェクトの集合体)
概して進みすぎていて、理解されない!
● 詳しくは
○ 第9回Smalltalk勉強会の資料「SmalltalkでWeb!」
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. Tide - The missing web framework
● 軽量
○ サーバ側: Pharo
■ 27クラス
○ クライアント側: Amber
■ 14クラス
● Webの普通の仕組みを使う
○ XHRでAJAX
○ Cookieでセッション管理
● 簡潔
○ オブジェクトのメッセージ送信を書くとAJAXしてくれる
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. インストール (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. 動作の確認
● Pharoのワークスペースで
TDDispatcher tideIndexPageUrl ”print it”
● URLをWebブラウザにペーストでAmberが立ち上がる
● Amberのワークスペースから
TDCounterWidget new render
● Seasideでおなじみのカウンターアプリが立ち上がる
● 動作確認後、Pharoのイメージを保存しておく
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. プロキシの存在
● TDCounterWidget >> counter (‘accessing’)
counter
^ counter ifNil: [ counter := TDClientProxy on: '/counter' ]
● TDCounterWidget >> increase (‘actions’)
increase
self counter increase.
self counter then: [ self update ]
● プロキシ経由でサーバにメッセージ送信
● 非同期を待ってthen:でアップデートをかけている!
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)
15. TDCounter
● クラス定義
TDPresenter subclass: #TDCounter
instanceVariableNames: 'count'
classVariableNames: ''
category: 'Tide-Examples'
● 初期化
initialize
super initialize.
count := 0
● TDPresenterを継承している
● 状態保持用にcountを持つだけ
16. <state>と<action>
● TDCounter >> count (‘accessing’)
● TDCounter >> increase (‘actions’)
● モデル更新の処理を平凡に書く
● <state>, <action> のpragma指定でJSONに変換され、ク
ライアントに送られる
count
<state>
^ count
increase
<action>
count := count + 1
17. 演習: Todoを作ってみる
● Pharo側にTDTodoPresenter, TDTodoList, TDTodoItem
が用意されている
作れということ!
18. Todoのサーバ側 (1)
● TDTodoPresenter
○ TDPresenter を継承
○ <state>toDoListとしてTDTodoListを保持
○ ‘todo’というURLで自己を登録している
● TDTodoList
○ Objectを継承。単なるモデル
○ <state>itemsとしてTDTodoItemを保持
○ <action>addItemLabeled: aString
○ <action>removeItem: anItem を定義
19. Todoのサーバ側 (2)
● TDTodoItem
○ Objectを継承。単なるモデル
○ <state>label, <state>completed を持つ
サーバ側は以上。何の変哲もないつくり。素直。
● 以上をふまえ、クライアント側(Amber)を作ってみる!
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. TDTodoWidget の基本メソッド群
● クラス定義
●
Widget subclass: #TDTodoWidget
instanceVariableNames: 'todo listPart'
package: 'Tide-Amber-Examples'
● アクセッサ
todo
^ todo ifNil: [ todo := TDClientProxy on: '/todo' ]
list
^self todo todoList
22. TDTodoWidget レンダリング (1)
render
self todo connect.
self todo then: [ self appendToJQuery: 'body' asJQuery ]
● はじめにconnectしておくのが特徴
● DOMにくっつけるところは通常のAmberと同じ
(ただしthen:を使ってconnectの結果を待っている)
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. TDTodoWidget イベントハンドラ
addItemLabelled: aString
self list addItemLabelled: aString.
self list then: [ self update ]
● プロキシ経由で<action> addItemLabelled: を送信
● then:後にアップデート
askTodo
^BrowserInterface new prompt: 'Todo?'
● Todo項目の入力用UIを作るのが面倒なので、
BrowserInterface>>prompt:で対応
26. 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;
}
27. updateの中身
update
listPart contents: [:html |
self renderListOn: html
]
● renderOn: で捕まえておいたlistPartのTagBrushを使い、
特定DOM部分(<div class=’listPart’>)のみを再描画
28. レンダリング続き (1)
renderListOn: html
html ul: [
self list items do: [:each | html li:[self renderItem: each on: html]]
]
● プロキシ経由でitemsを得て、個々をrenderItem:on:で
レンダリング
29. レンダリング続き (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’属性を変えている
31. 演習2: Todo項目を削除できるように
● 今のところ、 Todo項目の削除機能がない
● チェックした項目を削除するには?
● Pharo側に<action> removeItem: anItem があるので
これを使うことを考えてみる
37. まとめ
● TideはSmalltalkでSPAを作るための軽量フレームワーク
● メッセージ送信と若干のpragmaで書け、AJAXの詳細は意識
する必要がない
● 定番のWeb技術を素直に使っているため拡張も楽
○ CSSで見栄えの調整
○ AmberのCanvasが嫌な場合は、Handlebarsなど、
クライアントサイドJSONテンプレートも使える(はず)
● Tideで作られたCMS、Marinaも見てみよう!
https://github.com/tide-framework/marina