SlideShare a Scribd company logo
1 of 66
Download to read offline
PharoJSで作る
Webアプリケーション
第142回Smalltalk勉強会
2024 Masashi Umezawa
PharoJSとは?
● PharoでJavaScriptのアプリケーションを開発できる環境
○ Smalltalk → JS へのトランスパイラ
○ PlaygroundからJSオブジェクトへメッセージ送信
○ テストフレームワークも装備
● JavaScriptをほぼ意識せずに、JavaScriptランタイム
(WebブラウザやNode.jsなど)で動作するアプリを開発できる
PharoJSのインストール
Metacello new
baseline: 'PharoJS';
repository:'github://PharoJS/PharoJS:pharo11';
load
● Playgroundで"do it"
サンプルの起動
● インストール後にPharoJSメニューが出現
○ ヘルプを参照したり、サンプルのアプリを起動したりできる
HelloWorldAppの起動
● PjHelloWorldApp -> playground をメニューから選択
○ WebブラウザとPharoのPlaygroundが立ち上がる
Playgroundでの操作
● PlaygroundはJSランタイムと接続されている
○ JSオブジェクトにメッセージ送信が可能
Playgroundからメッセージ送信
● Playgroundで
console log: 'HelloWorld' と "do it"
○ 実行結果がJSのコンソールに表示される
DOMの要素にアクセス
● document, window などにアクセス可能
○ テキストインプットに何か入力
■ #nameTextInput のidが
振られているので...
○ Playgroundで
(document getElementById: 'nameTextInput') value. を"print it"すると
DOMアクセスによるアプリ操作
● テキストインプットを編集した後、ボタンのクリックを
させてみる
(document getElementById: 'sayHelloButton') click.
"こちらでも可"
(document getElementById: 'sayHelloButton') dispatchEvent:
(window Event new: 'click').
(document getElementById: 'nameTextInput') value: 'HI'.
● テキストインプットを直接書き換える
bridgeを使う
● Playgroundからbridgeを使うことで、PharoJSのアプリ
オブジェクトにメッセージを送信できる
bridge app inspect.
bridge appClass inspect.
→ PjHelloWorldAppのインスタンスやク
ラスのインスペクタが開く
その他のメニュー
● export
○ Playgroundを開かず、単にトランスパイルしたJSを書き出す
■ デバッグが不要な時
■ JSがコンパクトになる
● browse
○ Pharo側でアプリのクラスをブラウズ
● files, OS files
○ 生成されたファイルを一覧
PjHelloWorldApp の構成要素
● index.html
○ 基本的にはidを付与した要素が並んでいるだけ
○ 生成されたindex.js を読み込むようになっている
<div style="position:relative;width:100%;max-width:471px;">
<img src="pharoJsLogo.png" alt="PharoJS Logo" style="width:100%;" />
</div>
<input type="text" id="nameTextInput"> <button id="sayHelloButton">Say
Hello</button>
<p><strong><span id="greetingMessageContainer"></span></strong></p>
<script language="javascript" type="text/javascript" src="index.js">
</script>
PjHelloWorldApp クラスを見る - start メソッド
● アプリのエントリポイント
○ getElementById: でDOM要素を取得
○ addEventListener:block: でイベントハンドラを登録
| nameInput sayHelloButton greetingMessageContainer |
super start.
user := PjUser new.
nameInput := document getElementById: #nameTextInput.
sayHelloButton := document getElementById: #sayHelloButton.
nameInput addEventListener: #change block: [ user name: nameInput value ].
greetingMessageContainer := document getElementById:
#greetingMessageContainer.
sayHelloButton addEventListener: #click block: [ greetingMessageContainer
innerHTML: 'Hello ' , user name ]
PjHelloWorldAppクラスを見る - appClasses クラスメソッド
● 生成対象となるクラス群を示す
○ 自身に加え、PJHelloWorldAppが使用しているPjUserクラスも追加
● トランスパイル時に内部的に呼び出されるメソッドのため
<pharoJsSkip> プラグマがついている
■ メソッドが生成対象にならない
appClasses
<pharoJsSkip>
^ super appClasses, { PjUser }
PjHelloWorldAppクラスを見る - PjUserの使用
● インスタンス変数userを定義
● PjUser自身はnameのgetter, setterを持つだけの単純なModelクラス
● startメソッド内でnewして普通に使用している
PjFileBasedWebApp subclass: #PjHelloWorldApp
instanceVariableNames: 'user'
classVariableNames: ''
package: 'PharoJs-Examples-HelloWorld'
user := PjUser new.
greetingMessageContainer innerHTML: 'Hello ' , user name
Smalltalk から JavaScript への変換ルール
● 大体は想像通り
● SmalltalkのメソッドはJavaScript側では pj_ の接頭辞がつく
○ 既存のJavaScriptの関数名と衝突しないようにするため
○ MNUもシミュレートされる
● Smalltalk側で js_ の接頭辞をつけておくと js_ が取れた形でJavaScript
の関数になる
○ MNUにならない
キーワードメッセージの変換ルール
● セレクタの : 部分が _ になる
○ add: item
→ pj_add_(item)
○ copyFrom: from to: to
→ pj_copyFrom_to_(from, to)
newメッセージの変換ルール
● ClassA new → pj_new() となる
○ 内部でpj_basicNew()を呼び出し、
最終的にコンストラクタを呼び出している
● コンストラクタに引数を渡したい場合
○ Class new: param
○ Class new: paramA with: paramB
Globalオブジェクト
● window, document などは最初から参照できる
● グローバルオブジェクト群は PjUniversalGlobals, PjDomGlobals
などのプール辞書に格納されている
○ 直接参照できない場合、メッセージ送信で取得
■ window Event
■ window localStorage
など
インラインJavaScript
● メソッド定義時に javascript: プラグマを指定することでJavaScriptをその
まま書ける
● 例: log: anObject メソッドの実体を console.dir(anObject) にする
log: anObject
<javascript: 'console.dir(anObject)'>
● これで利用時は self log: someObj と書ける
playground / export 再び
● Appクラスに playground メッセージを送ると
○ index.js にbridgeの機能が入る
■ 内部的にWebSocketを利用
■ デバッグ機能なのでデプロイ時には不要
● Appクラスに exportApp メッセージを送ると
○ index.js にbridge は入らない
■ Smalltalkの基本クラス群は入ったまま
■ デプロイ時にはこちらを使う
■ terserなどでminifyする
簡単なWebアプリを作ってみる
● 既存のJavaScriptやCSSのライブラリも利用
● JavaScript
○ Mithril.js
■ SPA用の軽量なWebコンポーネント系のライブラリ
● CSS
○ Bulma
■ レスポンシブ対応の軽量なCSSフレームワーク
サンプルコード入手先
● プレゼンで利用するコードは以下で入手可能
○ https://github.com/mumez/SmalltalkStudy-PharoJS
● 段階ごとにタグ付けしたので、適宜ダウンロード
○ https://github.com/mumez/SmalltalkStudy-PharoJS/tags
ライブラリの指定方法
● index.html にCDNのリンクを書く
○ index.htmlは自動生成されない
○ 既存のものをコピーするなどして自作
…
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css"
>
…
<script src="https://unpkg.com/mithril/mithril.js"></script>
<script language="javascript" type="text/javascript"
src="index.js"></script>
</body>
アプリのクラスを定義
● SPA用のベースクラス、PjFileBasedWebAppが用意されている
○ インスタンス変数は counter にする
PjFileBasedWebApp subclass: #SsMithrilApp
instanceVariableNames: 'counter'
classVariableNames: ''
package: 'StStudy-Pjs-Mithril'
index.jsの生成先を設定
● デフォルトは
pharo-local/iceberg/PharoJS/PharoJS/HTML/(package名)/(class名)
● 階層が深すぎるのでイメージ直下/(class名)とする
defaultAppFolderParent
<pharoJsSkip>
^ '.' asFileReference
SsMithrilApp class
● SsMithrilApp exportApp でindex.jsが生成されることを確認
● 前述のように index.html は別途用意して自分で置く
defaults
index.html
…
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<title>Counter</title>
</head>
<body>
<div id="app" class="hero">
<div class="container">
<p class="title">Counter</p>
<button id="resetButton" class="button is-danger">Reset</button>
<button id="incrementButton" class="button is-primary">Increment</button>
</div>
</div>
<script src="https://unpkg.com/mithril/mithril.js"></script>
<script language="javascript" type="text/javascript" src="index.js"></script>
</body>
Playground で表示確認
● SsMithrilApp playgroundでブラウザに表示されることを確認
○ Bulmaのcssが効いている
○ ボタンを押しても何も起きない
○ Playgroundからメッセージだけは送れる
htmlのアプリ表示部分
<div id="app" class="hero">
<div class="container">
<p class="title">Counter</p>
<button id="resetButton" class="button
is-danger">Reset</button>
<button id="incrementButton" class="button
is-primary">Increment</button>
</div>
</div>
DOM要素アクセス用メソッドの定義
● 各ボタンに簡易にアクセスできるようにメソッドを定義
○ elementAt: はスーパークラスで定義されている
resetButton
^ self elementAt: 'resetButton'
SsMithrilApp
incrementButton
^ self elementAt: 'incrementButton'
accessing
初期化メソッドの定義
● initialize内で、counterを初期化
○ サンプルのPjCounterをそのまま利用
● setupでイベントハンドラを登録
initialize
super initialize.
counter := PjCounter new.
self setup
SsMithrilApp initialization
イベントハンドラの定義
● addEventListener:block:で、ボタンのclickイベントに対して
イベントハンドラを登録
● モデルの状態を変更し、render で表示
setup
self resetButton addEventListener: #click block: [
counter reset.
self render ].
self incrementButton addEventListener: #click block: [
counter increment.
self render ].
self render
SsMithrilApp initialization
renderメソッド実装の前に...
● 基本DOM要素に対してinnerHTML: で書き換えれば良いが...
● Mithril.js のAPIを使ってエレガントに済ませたい!
○ https://mithril.js.org/#live-example
var root = document.body
m.render(root, m("h1", "My first app"))
m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])
<main>
<h1 class="title">My first app</h1>
<button>A button</button>
</main>
m(selector, attributes, children) の利用
● m関数の入れ子で仮想DOMのツリーが作られる
● HTMLだと...
var vnodes = m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])
m.render(document.getElementById("app"), vnodes)
render(element, vnodes) によるHTML生成
● render関数でDOMにHTMLが適用される
● これで id="app"の子要素が、mainタグによる要素に置きかわる
インラインJavaScriptメソッド作成 - m:attrs:children:
● mやrenderを楽に使うためPharoJS側にメソッドを用意しておく
_m: selector attrs: attrs children: children
<javascript: 'return m(selector, attrs, children)'>
m: selector attrs: attrs children: children
^ self _m: selector attrs: attrs asDictionary children: children
SsMithrilApp Mithril API
インラインJavaScriptメソッド作成 - render:vnodes:
● 便利な renderAt:vnodes: も定義した
render: element vnodes: vnodes
<javascript: 'm.render(element, vnodes)'>
renderAt: elementId vnodes: vnodes
^ self render: (self elementAt: elementId) vnodes: vnodes
SsMithrilApp Mithril API
html側にcounter表示箇所を追加
<div id="app" class="hero">
<div class="container">
<p class="title">Counter</p>
<p id="counter" class="subtitle">0</p>
<button id="resetButton" class="button
is-danger">Reset</button>
<button id="incrementButton" class="button
is-primary">Increment</button>
</div>
</div>
renderメソッド
● idが'counter'の要素をレンダリング
SsMithrilApp rendering
render
self renderAt: 'counter' vnodes: (self
m: 'div'
attrs: {
('class' -> 'is-size-1').
('style' -> 'color:gray') }
children: counter count)
renderメソッド
● counterの値により色を変えてみる例
SsMithrilApp rendering
render
| style |
style := counter count  3 = 0
ifTrue: [ 'color:red' ]
ifFalse: [ 'color:gray' ].
self renderAt: 'counter' vnodes: (self
m: 'div'
attrs: {
('class' -> 'is-size-1').
('style' -> style) }
children: counter count)
SsMithrilAppの完成
● Playgroundで確認後、exportするとindex.htmlを読み込むだけで
単体で動くアプリができあがる
● 改良点
○ Traitsの使用
○ Componentの使用
TraitにAPIメソッドをまとめる - SsTMithril作成
● Mithril.js 関係のメソッド群をTraitにまとめておくと便利
Trait named: #SsTMithril
instanceVariableNames: ''
package: 'StStudy-Pjs-Mithril'
○ Mithril API のメソッドカテゴリごとSsTMithrilに移動
TraitにAPIメソッドをまとめる - SsTMithril利用
● SsMithrilAppでSsTMithrilをuse:
○ SsMithrilApp がすっきり
○ TraitsがJavaScriptで使えてハッピー
PjFileBasedWebApp subclass: #SsMithrilApp
uses: SsTMithril
instanceVariableNames: 'counter'
classVariableNames: ''
package: 'StStudy-Pjs-Mithril'
Componentの利用
● mount(root, component)を使うことで、状態変化に応じて
自動的に再描画させることができる
● 続きはWebで!
○ Mithril-Componentブランチ
■ 追加分
Node.js用のWebアプリを作ってみる
● サーバサイドで実行されるアプリの開発も可能
● ベースクラスが用意されている
○ Node.js単体用 (PjNodeApp)
○ Express.js 用 (PjExpressApp)
● 事前に Node.js, npm のインストールが必要
○ nvm などで入れる
○ Pharoからnodeとnpmを呼び出せる必要がある
■ PATHが通っているかチェック
● LibC system: 'node --version' で0が返ればOK
Node.js用のWebアプリ作成上の注意点
● index.jsの生成ディレクトリ
○ パス中にスペースが含まれないようにする
■ PharoJSがうまくハンドリングしてくれていない
● Windowsでのexport
○ 前段のnpmパッケージインストール処理がそのままでは動作しない
■ 手動でnpm installする
■ パッチ当て
● あるいは環境変数ComSpecを一時的にPowerShellに設定
● Windowsでのplayground
○ 動作しない
PjApplication class >> inAppFolderRunCommandLine: aBlock のパッチ
inAppFolderRunCommandLine: aBlock
<pharoJsSkip>
| commandLine |
commandLine := String streamContents: [ :str |
str
<< 'cd ';
<< self appFullJsFolderPath pathString;
<< $;.
aBlock value: str ].
OSPlatform current isWindows ifTrue:[
^ WBWindowsWebBrowser
shellExecute: 'Open' file: 'pwsh' parameters:'-Command "',commandLine,'"'
directory: '' show: 5.
].
LibC system: commandLine
簡単な Express.js アプリを作ってみる
● 既存のJavaScriptやCSSのライブラリも利用
● JavaScript
○ EJS (サーバ側)
■ 軽量なテンプレートエンジン
○ htmx (クライアント側)
■ HTMLの属性指定でAjaxやDOM置き換えを可能にするライブラリ
○ hyperscript (クライアント側)
■ HTMLの属性指定で簡易なスクリプトを書けるライブラリ
● CSS
○ Bulma
アプリのクラスを定義
● 今回もCounterにする
○ PjExpressAppを継承
○ APIサーバにする方法もあるが、今回はHTMLをブラウザに返して
レンダリングする形式
PjExpressApp subclass: #SsExpressCounterApp
instanceVariableNames: 'counter'
classVariableNames: ''
package: 'StStudy-Pjs-Express'
クラスメソッド群の定義
● index.js 生成ディレクトリの指定
defaultAppFolderParent
<pharoJsSkip>
^ '.' asFileReference
SsExpressCounterApp class defaults
● 追加パッケージの指定
npmPackageNames
<pharoJsSkip>
^ super npmPackageNames, #( ejs )
accessing
SsExpressCounterApp class
exportで生成
● メニューからexport、あるいは SsExpressCounterApp exportApp
○ package.jsonが生成されnpmパッケージのインストールが行われる
○ index.js が生成される
TIPS: nodemonの導入
● export時にアプリのリロードを自動的に行わせるため nodemon を
入れておくと良い
$ npm install - D nodemon
● package.jsonのscriptsセクションを編集
"scripts": {
"start": "nodemon index.js",
"debug": "nodemon --inspect index.js"
}
$ npm run start
● 以下でアプリを開始すると、exportの度にリロードが行われる
Webブラウザからアクセス
● startするとポートの確認ができる
○ http://localhost:4321
○ まだ Cannot GET / になるだけ
initializeメソッドを定義
● PjCounterでcounterを初期化してログを出してみる
initialize
super initialize.
counter := PjCounter new.
console log: counter count
○ SsExpressCounterApp exportApp で更新
■ 0が表示される
initialization
SsExpressCounterApp
ルーティングの定義
● initRoutes メソッドを定義してinitializeから呼ぶように変更
initRoutes
server get: '/' handler: [ :req :res | res send: 'hello' ]
initialize
super initialize.
counter := PjCounter new.
self initRoutes
● exportApp で更新するとブラウザにhelloと出るようになる
EJSの準備
● views ディレクトリを作成し、pages, partials のサブディレクトリを作成
○ pages下にindex.ejs
○ partials下にhead.ejs, main.ejs を置く
● pagesが大枠
● partialsがpagesからインクルードされる
pages/index.ejs
● headとmainのパーシャルをインクルード
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body>
<%- include('../partials/main'); %>
</body>
</html>
partials/head.ejs
● cssとクライアント側JSライブラリを指定
<meta charset="UTF-8">
<title>Express Counter</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
partials/main.ejs
● MithrilAppのindex.htmlからapp部分を拝借
○ 後でhtmxを使うため hx-get, hx-target の指定が入っている
<div id="app" class="hero">
<div class="container">
<p class="title">Counter</p>
<p id="counter" class="subtitle is-size-1">0</p>
<button hx-get="/reset" hx-target="#counter" class="button is-danger">
Reset
</button>
<button hx-get="/increment" hx-target="#counter" class="button is-primary">
Increment
</button>
</div>
</div>
EJSの利用
● initRoutes のhandler: 内をejsを使う形に変更
initRoutes
server set: 'view engine' to: 'ejs'.
server get: '/' handler: [ :req :res | self renderIndex: res ]
initialization
SsExpressCounterApp
renderIndex: res
res render: 'pages/index'
rendering
SsExpressCounterApp
○ index.ejs の内容が表示されるようになる
Counter部分のレンダリング
● ボタンを押すと404になる
● htmxの hx-get で/increment, /reset に対してGET は飛ぶようになって
いる
● hx-targetの指定で、GETの結果のHTMLはid="counter"のタグに反映さ
れる
○ ルーティングを追加し、counter部分のHTMLを返すようにする
<button hx-get="/increment" hx-target="#counter" class="button is-primary">
Increment
</button>
partials/counter.ejs
● <%= counter %> でcounterの値を適用してレンダリング
○ ついでにstyleもcounterの値に応じて変わるようにした
<div style="<%= counter % 3 == 0 ?
'color:red' : 'color:gray' %>">
<%= counter %>
</div>
initRoutesの修正
● increment, reset のルーティングを追加
○ GETリクエストがあったらモデルを更新し renderCounter: でレンダリング
initRoutes
server set: 'view engine' to: 'ejs'.
server get: '/' handler: [ :req :res | self renderIndex: res ].
server get: '/increment' handler: [ :req :res |
counter increment.
self renderCounter: res ].
server get: '/reset' handler: [ :req :res |
counter reset.
self renderCounter: res ]
initialization
SsExpressCounterApp
renderCounter:の追加
● render:with: によりEJS側にcounter countの値を渡すように
renderCounter: res
res render: 'partials/counter'
with: {'counter' -> counter count} asDictionary
rendering
SsExpressCounterApp
hyperscriptで連打対策
● ちょっとしたロジックをクライアント側に入れたい時
○ Incrementボタン連打の間隔をhyperscriptで調整
<div id="app" class="hero">
<div class="container">
<p class="title">Counter</p>
<p id="counter" class="subtitle is-size-1">0</p>
<button hx-get="/reset" hx-target="#counter" class="button is-danger">
Reset
</button>
<button hx-get="/increment" hx-target="#counter" class="button is-primary"
_="on click toggle [@disabled='true'] for 0.1s">
Increment
</button>
</div>
</div>
まとめ
● PharoJSを使えばJavaScriptを意識せずにJavaScriptのアプリを開発で
きる
● 慣れ親しんだPharoの開発環境が使える
● Playgroundも完備
● TraitやメソッドカテゴリなどJSにない機能も利用可能
どこまでPharoJSでできるかチャレンジしてみるのも良いかも

More Related Content

Similar to 第142回Smalltalk勉強会 - PharoJSで作るWebアプリケーション

Jqm20120210
Jqm20120210Jqm20120210
Jqm20120210
cmtomoda
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
Jumpei Ogawa
 
今流行りのウェブアプリ開発環境Yeoman
今流行りのウェブアプリ開発環境Yeoman今流行りのウェブアプリ開発環境Yeoman
今流行りのウェブアプリ開発環境Yeoman
tomo_masakura
 

Similar to 第142回Smalltalk勉強会 - PharoJSで作るWebアプリケーション (20)

Try_to_writecode_practicaltest #atest_hack
Try_to_writecode_practicaltest #atest_hackTry_to_writecode_practicaltest #atest_hack
Try_to_writecode_practicaltest #atest_hack
 
Twitter sphere of #twitter4j #twtr_hack
Twitter sphere of #twitter4j #twtr_hackTwitter sphere of #twitter4j #twtr_hack
Twitter sphere of #twitter4j #twtr_hack
 
Sphinx customization for OGP support at SphinxCon JP 2018
Sphinx customization for OGP support at SphinxCon JP 2018Sphinx customization for OGP support at SphinxCon JP 2018
Sphinx customization for OGP support at SphinxCon JP 2018
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
 
実践 NestJS
実践 NestJS実践 NestJS
実践 NestJS
 
omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜
 
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化するEWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
EWD 3トレーニングコース#30 ewd-xpressアプリケーションをモジュラー化する
 
ぶっとびケータイ+Firefox OS Apps
ぶっとびケータイ+Firefox OS Appsぶっとびケータイ+Firefox OS Apps
ぶっとびケータイ+Firefox OS Apps
 
EC-CUBEプラグイン講義
EC-CUBEプラグイン講義EC-CUBEプラグイン講義
EC-CUBEプラグイン講義
 
Djangoによるスマホアプリバックエンドの実装
Djangoによるスマホアプリバックエンドの実装Djangoによるスマホアプリバックエンドの実装
Djangoによるスマホアプリバックエンドの実装
 
Unit testing JavaScript with JUnit/JavaFX
Unit testing JavaScript with JUnit/JavaFXUnit testing JavaScript with JUnit/JavaFX
Unit testing JavaScript with JUnit/JavaFX
 
環境構築から始めるDjangoチュートリアル
環境構築から始めるDjangoチュートリアル環境構築から始めるDjangoチュートリアル
環境構築から始めるDjangoチュートリアル
 
Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)
 
Jqm20120210
Jqm20120210Jqm20120210
Jqm20120210
 
Gws 20130315 gradle_handson
Gws 20130315 gradle_handsonGws 20130315 gradle_handson
Gws 20130315 gradle_handson
 
Movable TypeのWebアプリケーションフレームワークの基本
Movable TypeのWebアプリケーションフレームワークの基本Movable TypeのWebアプリケーションフレームワークの基本
Movable TypeのWebアプリケーションフレームワークの基本
 
Start python with fastapi
Start python with fastapiStart python with fastapi
Start python with fastapi
 
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
 
今流行りのウェブアプリ開発環境Yeoman
今流行りのウェブアプリ開発環境Yeoman今流行りのウェブアプリ開発環境Yeoman
今流行りのウェブアプリ開発環境Yeoman
 
Try Jetpack
Try JetpackTry Jetpack
Try Jetpack
 

More from Masashi Umezawa

More from Masashi Umezawa (20)

FileManで楽々ファイル操作
FileManで楽々ファイル操作FileManで楽々ファイル操作
FileManで楽々ファイル操作
 
TruffleSqueakの紹介
TruffleSqueakの紹介TruffleSqueakの紹介
TruffleSqueakの紹介
 
SmalltalkBoltでUFFI入門
SmalltalkBoltでUFFI入門SmalltalkBoltでUFFI入門
SmalltalkBoltでUFFI入門
 
TaskItの紹介
TaskItの紹介TaskItの紹介
TaskItの紹介
 
Smalltalk勉強会 - 過去、現在、そして未来へ のその後
Smalltalk勉強会 - 過去、現在、そして未来へ のその後Smalltalk勉強会 - 過去、現在、そして未来へ のその後
Smalltalk勉強会 - 過去、現在、そして未来へ のその後
 
Revealing ALLSTOCKER
Revealing ALLSTOCKERRevealing ALLSTOCKER
Revealing ALLSTOCKER
 
TarandocでJSONを永続化
TarandocでJSONを永続化TarandocでJSONを永続化
TarandocでJSONを永続化
 
Dockerizing pharo
Dockerizing pharoDockerizing pharo
Dockerizing pharo
 
今からでも遅くないSmalltalk入門
今からでも遅くないSmalltalk入門今からでも遅くないSmalltalk入門
今からでも遅くないSmalltalk入門
 
Tarantubeでメッセージキューを使い倒す
Tarantubeでメッセージキューを使い倒すTarantubeでメッセージキューを使い倒す
Tarantubeでメッセージキューを使い倒す
 
VerStixの紹介
VerStixの紹介VerStixの紹介
VerStixの紹介
 
Oldtalk - あのころの処理系は今
Oldtalk - あのころの処理系は今Oldtalk - あのころの処理系は今
Oldtalk - あのころの処理系は今
 
Pyonkeeを鳴らす
Pyonkeeを鳴らすPyonkeeを鳴らす
Pyonkeeを鳴らす
 
Smalltalk勉強会 - 過去、現在、そして未来へ
Smalltalk勉強会 - 過去、現在、そして未来へSmalltalk勉強会 - 過去、現在、そして未来へ
Smalltalk勉強会 - 過去、現在、そして未来へ
 
Tarantalk
TarantalkTarantalk
Tarantalk
 
Smalltalkと型について
Smalltalkと型についてSmalltalkと型について
Smalltalkと型について
 
Introduction of Pharo 5.0
Introduction of Pharo 5.0Introduction of Pharo 5.0
Introduction of Pharo 5.0
 
Why!? Smalltalk
Why!? SmalltalkWhy!? Smalltalk
Why!? Smalltalk
 
Pillarの紹介
Pillarの紹介Pillarの紹介
Pillarの紹介
 
Scrumの紹介とXPプロジェクトへの適用(Scrum and XP)
Scrumの紹介とXPプロジェクトへの適用(Scrum and XP)Scrumの紹介とXPプロジェクトへの適用(Scrum and XP)
Scrumの紹介とXPプロジェクトへの適用(Scrum and XP)
 

第142回Smalltalk勉強会 - PharoJSで作るWebアプリケーション