Upload
airtoxin-ishii
View
521
Download
3
Embed Size (px)
Citation preview
経緯• 夜フクロウが最高だったけどもうずっとサポートされていない
• webは意外と使いやすいけど、結局アプリじゃないのが面倒
• 公式クライアントはヌルヌル動いていい感じと見せかけて、よく引っかかるしめっちゃ落ちる
• echofon (見た目が
• mikutter (名前が
• tweetbot (値段が
ツイッタークライアント(仮) 今できること
• アイコン、相対時間付きでTLが流れる
• ツイートの投稿
• ツイートのお気に入り登録
• エラーがあったらなんか出てくる
• マルチメディアツイートの表示
• 画像クリックでプレビュー
ツイッタークライアント(仮) 今できないこと
• TL以外のタブ機能(Reply、DM、List…)
• リプライ、リツイートボタン
• ✨👮👊
• 画像投稿
• ユーザーホームの観覧
• Lorem Ipsum
nw.js• node.js + HTML + CSS + JSでデスクトップアプリが作れる
• 旧 node-webkit
• node.jsのフォーク、io.jsに移行した際に名称を変更
• Windows / Mac / Linuxいずれもサポート
nw.js
• node.jsのapiもブラウザコンテキストのライブラリもどっちも使える
• 例えばnodeのfsモジュールでディレクトリ構成を取得し、グラフィカルに表示するなども
• つい最近、ウィンドウの透過をサポート
nw.jsでビルド
• package.jsonに”main”としてエントリーポイントのHTMLパスを書く
• package.jsonがあるディレクトリを指定してビルドするとアプリ化される
• 手動ならnuwk!が手軽
こんなnw.jsは嫌だ• browserコンテキストとnodeコンテキストの混在で混乱が起きる
• ショートカットにESCとかEnterが登録できない
• Atom-Shellと覇権争い
• windowオブジェクトの管理が大変
• アプリを作っているとviewのイベントに応じてトリガー引いて処理を…という形になり、結局RESTfullなSPAっぽくなる
React.js• ブラウザーサイドのjsライブラリ(フレームワーク)
• Facebook謹製
• 最近なんか流行ってるっぽい
• ViewModelなのでデータバインドが楽ちん
• 仮想DOMの差分レンダリングで超高速レンダリング
• コンポーネント指向で再利用可能なパーツ
var Tweet = React.createClass( { propTypes: { tweetPayload: React.PropTypes.object // tweet object https://dev.twitter.com/overview/api/tweets }, getInitialState: function () { return { relativeTime: ‘1s' }; }, componentDidMount: function () { var self = this; setInterval( function () { self.setState( { relativeTime: self.getRelativeTime( self.props.tweetPayload.created_at ) } ); }, 3000 ); }, render: function () { var payload = this.props.tweetPayload; var medias = []; if ( this.props.tweetPayload.extended_entities && this.props.tweetPayload.extended_entities.media && this.props.tweetPayload.extended_entities.media.length > 0 ) { medias = this.props.tweetPayload.extended_entities.media.map( function ( media ) { return <Media mediaPayload={ media } key={ media.id_str } /> } ); } return ( <div className="tweet row"> <div className="col-‐sm-‐2 text-‐center"> <img className="profile-‐icon" src={ payload.user.profile_image_url_https.replace( '_normal', '' ) } /> </div> <div className="col-‐sm-‐9"> <p> <span className="user-‐name">{ payload.user.name }</span> <span className="user-‐id">@{ payload.user.screen_name }</span> </p> <div className="text"><p>{ payload.text }</p></div> <div className="row">{ medias }</div> </div> <div className="col-‐sm-‐1"> <div className="post-‐time btn disabled">{ this.state.relativeTime }</div> <div className="action-‐icons btn-‐group-‐vertical"> <button className="action-‐icon btn btn-‐default" type="button"><i className="fa fa-‐reply"></i></button> <button className="action-‐icon btn btn-‐default" type="button"><i className="fa fa-‐retweet"></i></button> <Favorite id={ payload.id_str } favorited={ payload.favorited } /> </div> </div> </div> ); }, getRelativeTime: function ( targetDate ) { /* do something */ } } );
StateとProps• Stateはコンポーネントの状態を表す変数 (読み書き可) Model的
• Propsはコンポーネントの外部から受け取った変数 (読み取りのみ可) Interface的
• stateはsetState()で書き込みを行う
• stateが変更されるとrenderが自動的に走る
よく使うメソッド等• propTypes コンポーネントが公開しているPropsのインターフェースを記述開発者に向けたバリデーション
• getInitialState()Stateの初期値を記述
• componentDidMount() コンポーネントがDOMに追加された後に呼ばれるDOMに関する初期化処理ajaxでデータを取ってきてsetState()など
• render()単一の仮想DOMを返す {}で囲むと評価された値が挿入される同じコンポーネントが複数ある場合はkeyを指定しなければならない
ビルド自動化• Grunt / gulpなどのタスクランナーで自動化
• jsxの変換や必要モジュールのロードなどを行ったものをcompileディレクトリに出力
• compileディレクトリを対象にnw.jsのアプリをbuild
!
!
var gulp = require( 'gulp' ); var NwBuilder = require( 'node-‐webkit-‐builder' ); !gulp.task( 'nw', function () { var nw = new NwBuilder( { files: './compile/**/*', platforms: [ 'osx64' ], version: ( process.env.NODE_ENV === 'production' ) ? 'latest' : 'v0.10.5' } ); return nw.build(); } );
browserifyとrequire
• 一連のjsコードをbrowserifyしてapp.jsとして出力
• ルートのindex.htmlでscriptタグで読み込む事で全てnodeコンテキストで書ける様になる
• browserifyがrequireを書き換える事に注意browserifyしても使えないfsなどのモジュールはrequireの代わりにwindow.requireを使う必要がある
アプリケーションの公開
• ビルドされたアプリはソースコードが丸見え
• oauthのコンシューマーキーなどを隠す必要がある
• nwsnapshotを使ってsnapshot.binを出力
• package.jsonで”snapshot”: “snapshot.bin”
• htmlの読み込み後にsnapshotが評価される