do7be.exports

エッセンシャルガチ草トメィトゥ

WEBサービス運用費を1/12に削減した

2,3年ほど前に作った LGTM-HUB というしょぼいサービスをふと振り返ったら毎月$12ほどかかっていることに気づきました。さすがに月数百PVほどのサービスにここまでかけるのもどうかなと思い、インフラ構成を変えて運用費を削減しようかなと思いました。ついでにデザインも新しくしました。

f:id:do7be:20180819161131p:plain

どれくらい安くなったのか

毎月約$12かかっていたサービス運用費が毎月約$1になりました。

移行の内容

当初の構成

当初のインフラ構成はこんな感じでした

  • EC2(t2.micro)
    • サーバ費用削減のためフロントのnginxでサブドメインのNodeサーバにproxyする構成だったが、当時は1サービスにしかproxyしてなかったので意味なかった
    • 履歴のデータはオンメモリで持ってた
  • Route53

アプリケーションはこんな感じ

  • express
  • jQuery
  • React.js
  • socket.io
  • ZeroClipboard
  • gulp

AWS→Heroku

とりあえずEC2は金かかるなと思い、Herokuに移行することにしました。ついでにhttps化と古いライブラリの廃止と全体的なリファクタリングを行いました。

その結果、月$7まで削減することができました。

  • Heroku(カスタムドメインhttpsで利用したかったのでHobby)
  • Route53
  • Redis(Heroku add-on)

アプリケーション構成は以下のようになりました。

  • express
  • typescript
  • React.js
  • Redux
  • clipboard.js(ZeroClipboardはFLASH使ってた)
  • webpack
  • 開発環境をDocker化

プルリクはこんな感じ。ほぼ2年ほど構成を変えていなかったので直す箇所が大量にあってしんどかった。

AWS Lambda化

月$7でもちょっと高く感じたので、さらに費用削減するべくAWSのLambdaに移行することにしました。SPAをLambdaで動かす事例はちょいちょい見かけていたので。

とはいえ、Expressで書かれたアプリケーションを移行するのめんどいなと思っていたら AWS Serverless Expressという便利そうなものを発見。

aws-serverless-expressでlambda化

若干面倒だった箇所として、JSなどの静的ファイルとかはアップロードしたLambdaのzipファイルを基に配信するため、Expressで専用のパスを作ってあげて1回受けるようにしました。このへん

アプリケーション構成としてはHerokuのときとほとんど変わりませんでしたが、インフラ的には大きく変わりました。

  • Lambda
  • ApiGateway
  • Route53
  • DynamoDB

RedisのままだとElastiCacheとかでアホみたいに金かかる感じだったのでDynamoDBを利用することに。開発環境ではDynamoDBのDockerイメージを用いました。

費用内訳

  • Route53: 約$1
  • その他: $0〜$0.5

感想

インフラだけでなくアプリケーションコードも大幅リニューアルできたのですが、フロントのクオリティアップやバックエンドのリファクタリングなど、まだまだやりたいことがたくさんあってやりきった感はまだないです。

毎月そんなにPVはなくとも使ってくださるユーザーのために運営し続けたくはなるのですが、長期間となると運営費がバカにならないので安く抑えられるならできるだけ工夫して安くしたほうがいいかなと思いました。

スクロール領域からスクロールバーを消す(可変高さ対応)

qiita.com

スクロールバー消したくてこれを読んでいたら固定幅(高さ)しかできなさそうだったのでいろいろ模索してみた。

ホバーするとliのサイズが変わる。

jsfiddle.net

解説

ulの親要素にoverflow: hidden;を設けてあげてulにネガティブマージンをつけてあげると実現できる。

コード

<p>横スクロールできるけどスクロールバーを非表示にしてる</p>
<div>
  <ul>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>
    <li>hoge</li>  
  </ul>
</div>
div {
  overflow: hidden;
}

ul {
  display: flex;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 0 20px;
  margin: 0 0 -20px;
  width: 400px;
  background-color: #ddd;
}

li {
  margin: 0 4px;
  height: 100px;
  background-color: #ccc;
  transition: 0.2s height;
}

li:nth-child(2) {
  background-color: #f00;
}

li:nth-child(2):hover {
  height: 200px;
}

li:nth-child(4) {
  background-color: #0ff;
}

li:nth-child(4):hover {
  height: 50px;
}

余談

こっちはなぜか同僚が作った自動で高さが変わるようにしたデモ。

jsfiddle.net

横スクロール出来るリストを作るときのCSSについて

多くの商品などの画像を並べるとき、↓のようなリストで実現することがある。僕は嫌いなのだがスマホタブレット対応を考えると横スクロールに対応する必要がある。こんなリストをCSSで組もうとするといくつか方法が考えられると思うのでまとめておいた。

f:id:do7be:20171003210953p:plain

各実装方法

inline-blockによる実装

これは最も簡単で、最近のブラウザでなくてもレンダリング出来ることが強み。しかもデモにあるようにリストの両端にマージンを付与することが出来る。このマージンは単にデザインに必要という場合だけでなく、カルーセルだった場合にボタンを置く領域にもなる。個人的にはこれをおすすめしたい。

inline-block方式

methodと書いてあるところがミソ

flexによる実装

これも簡単なのでおすすめ。ただ、IE9以下だとレンダリングできず、両端にマージンをつけることが出来ない。許容出来れば良いと思う。

flex方式

tableによる実装

これはあまり使わない。border-spacingで間隔を空けるが両端のマージンについては対応が困難。一応両端のtdで実現はできそう。td自体にはwidthを指定できないのでtdの子要素で指定する必要がある。正直考えることが多いしコードもでかくなるので嫌い。

table方式

grid-layoutによる実装

リスト内の要素数が固定の場合は実装できそう。やったことないけど。

まとめ

inline-blockによる実装かflexによる実装がおすすめ。他にも簡単でレンダリングが崩れない実装があるかもしれないので色々試して欲しい。

Chatworkでの発言をDiscordに流すようにした

けっこう前に適当に書いたコードの話。

某ゲームのChatworkグループに所属しているのだが、Discordしか見ないメンバーもいてDiscordでも見れるようにしてほしいとの要望から作りました。

こんなかんじ

f:id:do7be:20170826193721p:plain

書いたコード

  • GASで実装
  • 15分ごとにChatwork監視(もっと頻度多くてもよさそう)
  • 新規メッセージがあればDiscordのWebhookを叩く
function main() {
  var messages = getMessages();
  if(!messages) {
    return;
  }

  var message = [];
  for (var i = 0; i < messages.length; i++) {
    message.push(messages[i].account.name + ' > ' + messages[i].body);
  }
  message = message.join('\n');

  sendMessageToDiscord(message);
}

function getMessages () {
  var params = {
    headers : {"X-ChatWorkToken" : ChatworkAPI申請して取得したトークン},
    method : "get"
  };
  var room_id = Chatworkの部屋ID;
  var url = "https://api.chatwork.com/v2/rooms/" + room_id + "/messages";
  var rawRespons = UrlFetchApp.fetch(url, params);
 
  if(rawRespons == "") {
    return;
  }
  
  var response = rawRespons.getContentText();
  var json = JSON.parse(response);
  Logger.log(json);
 
  return json;
}

function sendMessageToDiscord (message) {
  var url = 'https://discordapp.com/api/webhooks/チャンネル番号/トークン';
  var payload = JSON.stringify({content: message});
  
  var params = {
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'User-Agent': 'DiscordBot (http://example.com, v0.0.1)',
    },
    method: "post",
    payload: payload,
  };
  
  Logger.log(params);
  
  var rawRespons = UrlFetchApp.fetch(url, params);  
}

function test () {
  sendMessageToDiscord('テストでーすwww');
}

事前にやること

  • ChatworkAPI申請
  • Discord Webhookの作成

f:id:do7be:20170826194208p:plain

余談

  • 適当に書いたコードなのでかなり汚くてすまそ。
  • Discordのドキュメントだいたい英語でちょい時間かかってしまった。
  • 本当はBot作りたかったんだけどなぜかHeaderのAuthorizeがうまく通らなくて諦めてしまった。
  • LoLやってる人は気軽に連絡ください。一緒にやりましょう!

cssnanoをrequireしたらローカルだけSyntaxErrorが発生

追記(16:22)

同僚に聞いてわかった。Content-EncodingがUTF-8になってないせいっぽい。

つまり <meta charset="UTF-8"> を追加すればOK。

なんてこったい。

現象

src/index.jsでrequireしただけでSyntaxErrorが起きた

var cssnano = require('cssnano')

でWebpack buildして実行すると

f:id:do7be:20161217160115p:plain

でもgh-pagesだとエラーが発生しない。

https://do7be.github.io/cssnano-test/

Nodeでもエラー起きないし、ローカルでhtml開いたときだけ起きてるっぽい。

エラー内容

エラーを見ると cubicСontrolPoint という変数を初期化しているところで起きている。JSだと動きそうなもんだけど、実際に実行すると本当にSyntaxErrorになった。

f:id:do7be:20161217160514p:plain

どうやら ¡ という文字がいけないらしい。

Babelのせいなのかcssnanoのせいなのかcssnanoのdependenciesのせいなのか謎なのでIssuesもどこに立てればいいのか謎。

github.com

SugarSSのtransformデモツールをつくった

Stylusっぽく書けるPostCSSパーサーのSugarSSが良い感じなので最近使ってる。

でもDocument全然ないしDEMOページすらないので辛酸なめまくってて厳しい。

そこでSugarSSを入力するとtransformしてくれるDEMOページを作ってみた。

https://do7be.github.io/sugarss-demo/

コードは↓

github.com

まとめ

  • SugarSS良い
  • React良い
  • CSS Modules良い
  • Tabキーハンドラきつい
  • Reactのハイライトめんどい
  • 最近また行ったけどソラマチトリトンくそうまいし安いから今月も行きたい

f:id:do7be:20161208230413p:plain