Successfully reported this slideshow.

最高のツイッタークライアントを求めて

3

Share

Loading in …3
×
1 of 37
1 of 37

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

最高のツイッタークライアントを求めて

  1. 1. 最高のツイッター
 クライアントを求めて 石井遼司 @airtoxin 2015年2月3日 ピコもん株式会社 社内勉強会
  2. 2. @airtoxin • 石井遼司 •   • 大学ではプログラムを書いて遺伝子の探索をしていた • ボードゲームとかよくする • 曲もほんのちょっと作ったり
  3. 3. 最高のツイッター
 クライアントを求めて
  4. 4. 経緯 • 夜フクロウが最高だったけどもうずっとサポートされていない • webは意外と使いやすいけど、結局アプリじゃないのが面倒 • 公式クライアントはヌルヌル動いていい感じと見せかけて、
 よく引っかかるしめっちゃ落ちる • echofon (見た目が • mikutter (名前が • tweetbot (値段が
  5. 5. じゃあ作れば良いのでは?
  6. 6. ツイッタークライアント
  7. 7. を作った
  8. 8. ツイッタークライアント(仮) 今できること • アイコン、相対時間付きでTLが流れる • ツイートの投稿 • ツイートのお気に入り登録 • エラーがあったらなんか出てくる • マルチメディアツイートの表示 • 画像クリックでプレビュー
  9. 9. ツイッタークライアント(仮) 今できないこと • TL以外のタブ機能(Reply、DM、List…) • リプライ、リツイートボタン • ✨👮👊 • 画像投稿 • ユーザーホームの観覧 • Lorem Ipsum
  10. 10. 技術的なところ
  11. 11. アプリケーション
 ビルド
  12. 12. nw.js
  13. 13. nw.js • node.js + HTML + CSS + JSで
 デスクトップアプリが作れる • 旧 node-webkit • node.jsのフォーク、io.jsに移行した際に名称を 変更 • Windows / Mac / Linuxいずれもサポート
  14. 14. nw.js • node.jsのapiもブラウザコンテキストのライブ ラリもどっちも使える • 例えばnodeのfsモジュールでディレクトリ構成 を取得し、グラフィカルに表示するなども • つい最近、ウィンドウの透過をサポート
  15. 15. nw.jsでビルド • package.jsonに main としてエントリーポイン トのHTMLパスを書く • package.jsonがあるディレクトリを指定してビ ルドするとアプリ化される • 手動ならnuwk!が手軽
  16. 16. こんなnw.jsは嫌だ
  17. 17. こんなnw.jsは嫌だ • browserコンテキストとnodeコンテキストの混在で混乱が起きる • ショートカットにESCとかEnterが登録できない • Atom-Shellと覇権争い • windowオブジェクトの管理が大変 • アプリを作っているとviewのイベントに応じてトリガー引いて 処理を…という形になり、結局RESTfullなSPAっぽくなる
  18. 18. JSフレームワーク (ライブラリ)
  19. 19. React.js
  20. 20. React.js • ブラウザーサイドのjsライブラリ(フレームワーク) • Facebook謹製 • 最近なんか流行ってるっぽい • ViewModelなのでデータバインドが楽ちん • 仮想DOMの差分レンダリングで超高速レンダリング • コンポーネント指向で再利用可能なパーツ
  21. 21. 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  */  }   }  );
  22. 22. StateとProps • Stateはコンポーネントの状態を表す変数
 (読み書き可)
 Model的 • Propsはコンポーネントの外部から受け取った変数
 (読み取りのみ可)
 Interface的 • stateはsetState()で書き込みを行う • stateが変更されるとrenderが自動的に走る
  23. 23. よく使うメソッド等 • propTypes
 コンポーネントが公開しているPropsのインターフェースを記述
 開発者に向けたバリデーション • getInitialState()
 Stateの初期値を記述 • componentDidMount()
 コンポーネントがDOMに追加された後に呼ばれる
 DOMに関する初期化処理
 ajaxでデータを取ってきてsetState()など • render()
 単一の仮想DOMを返す
 {}で囲むと評価された値が挿入される
 同じコンポーネントが複数ある場合はkeyを指定しなければならない
  24. 24. シンプルで分かりやすい
  25. 25. こんなReact.jsは嫌だ
  26. 26. こんなReact.jsは嫌だ • jsxのトランスパイル • jsにテンプレートが内包されている • className ? • CSS当てにくい
  27. 27. nw.js + React.js
  28. 28. ビルド自動化 • 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();   }  );
  29. 29. ディレクトリ構成
  30. 30. browserifyとrequire • 一連のjsコードをbrowserifyしてapp.jsとして出力 • ルートのindex.htmlでscriptタグで読み込む事で
 全てnodeコンテキストで書ける様になる • browserifyがrequireを書き換える事に注意
 browserifyしても使えないfsなどのモジュールは requireの代わりにwindow.requireを使う必要がある
  31. 31. アプリケーションの公開 • ビルドされたアプリはソースコードが丸見え • oauthのコンシューマーキーなどを隠す必要がある • nwsnapshotを使ってsnapshot.binを出力 • package.jsonで snapshot : snapshot.bin • htmlの読み込み後にsnapshotが評価される
  32. 32. 絶対皆で最高の
 クライアントを作ろうな!
  33. 33. https://github.com/airtoxin/ twitter-client

×