google
Firebase
MaterialDesignLite

LTを盛り上げるツール(匿名掲示板)をFirebaseでサクッと作る

はじめに

LTを盛り上げるためのリアルタイム掲示板(匿名)を
Firebaseでサクッと作ってみました。
LTとは別のモニターに写して、コメントがリアルタイムに表示されるってやつですね。

見る側は各自のスマホのブラウザでアクセスして
「へぇ」ボタンなども実装してあるので、更に盛り上がります。
(あくまで、社内ツールとして使ってくださいね)

Firebaseで作ってみた感想としては

リアルタイムのWebアプリが速攻で作れるだけでなく、
デフォルトでオフライン投稿も可能な仕様なのでびっくりという感じでしょうか。
(オンラインになったら裏で自動でサーバへ投稿)

今回は、ホスティングもGoogleさんにおまかせプランで作ります。

手順の流れは簡単!

  • Firebaseに登録、プロジェクト作成
  • 自分のMacに環境構築
  • コマンドでデプロイ

以上!

①Firebaseに登録、プロジェクト作成

  • G Suite を契約している人は、「Firebase Console」でプロジェクト作るのみです。
  • そうでない方はGoogleさんにクレジットカード情報も含めて諸々登録しましょう(詳細は割愛)

②自分のMacに環境構築

  • nodeのインストール
    https://nodejs.org(今回はv6)
  • firebase-toolesのインストール
$ sudo su -
# npm install -g firebase-tools
# exit
$ firebase login
$ firebase init
 流れとしては、ログインして、ホスト先を指定すればOKです。
 (基本DefaultでOK)

↓ 必要なファイルが作成されます

$ ls -lR
total 16
-rwxr-xr-x@  1 ishino  staff  134  8 30 10:21 firebase.json
drwxr-xr-x@ 15 ishino  staff  510  8 31 16:21 public

./public:
total 1160
-rwxr-xr-x@ 1 ishino  staff    1808  8 26 23:12 404.html
-rwxr-xr-x@ 1 ishino  staff    5760  9  1 14:51 index.html
  • ./public/index.htmlをお好みに編集するだけでOK(下記はサンプル)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>BBS</title>

    <!-- update the version number as needed -->
    <script defer src="/__/firebase/4.3.0/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="/__/firebase/4.3.0/firebase-auth.js"></script>
    <script defer src="/__/firebase/4.3.0/firebase-database.js"></script>
    <script defer src="/__/firebase/4.3.0/firebase-messaging.js"></script>
    <script defer src="/__/firebase/4.3.0/firebase-storage.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script defer src="/__/firebase/init.js"></script>
    <link rel="stylesheet" href="./material.min.css">
    <script src="./material.min.js"></script>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.deep_purple-pink.min.css">
    <link rel="stylesheet" href="styles.css">
    <style>
    #view-source {
      position: fixed;
      display: block;
      right: 0;
      bottom: 0;
      margin-right: 40px;
      margin-bottom: 40px;
      z-index: 900;
    }
    .mdl-demo .mdl-card .mdl-card__supporting-text {
        text-align: right;
    }
    .mdl-demo.mdl-demo .mdl-card__supporting-text h4 {
        text-align: left;
    }
    h6 {
        font-size: 0.5em;
        text-align: right;
        margin-top: 0px;
        margin-bottom: 0px;
    }
    @media (min-width: 1024px) {
      h3 {
          color: #616161;
          margin-top: 0px;
          margin-bottom: 0px;
          font-size: 84px;
          line-height: 80px;
      }
      li.mdl-list__item {
          padding-top: 10px;
          padding-bottom: 10px;
      }
    }
    @media (max-width: 1023px) {
      h3 {
          color: #616161;
          margin-top: 0px;
          margin-bottom: 0px;
          font-size: 15px;
      }
      li.mdl-list__item {
          padding-top: 0px;
          padding-bottom: 0px;
      }
    }
    </style>
  </head>
  <body class="mdl-demo mdl-color--grey-100 mdl-color-text--grey-700 mdl-base" background="bg.jpg">

  <audio id="sound-hee" preload="auto">
    <source src="./hee.mp3" type="audio/mp3">
  </audio>

    <div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
      <main class="mdl-layout__content">
        <div class="mdl-layout__tab-panel is-active" id="overview" style="padding-top: 8px;">
          <section class="section--center mdl-grid mdl-grid--no-spacing mdl-shadow--2dp" style="opacity: 0.95;">
            <div class="mdl-card mdl-cell mdl-cell--12-col">
              <div class="mdl-card__supporting-text" style="margin-bottom: 0px;margin-top: 0px;margin-left: 0px;">
                <div class="mdl-grid" style="padding-top: 0px; padding-bottom: 0px;">
                  <div class="mdl-cell mdl-cell--5-col" style="padding-top: 12px;">
                    <a onClick="document.getElementById('sound-hee').play()"><img src="./hee.png" width="40" alt="へぇ!!!!!"></a>
                  </div>
                  <div class="mdl-cell mdl-cell--7-col">
                    <div class="mdl-textfield mdl-js-textfield">
                      <input class="mdl-textfield__input" type="text" id="message">
                      <label class="mdl-textfield__label" for="sample1">Text or Image's URL...</label>
                    </div>
                      <button class="mdl-button mdl-js-button mdl-button--raised" id="send">投稿</button>
                  </div>
                </div>
              </div>
              <hr style="margin-top: 0px; margin-bottom: 0px;">
              <ul class="demo-list-icon mdl-list" id="messages" style="margin-top: 0px; margin-bottom: 0px;"></ul>
            </div>
          </section>
        </div>
      </main>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
    <script src="https://cdn.firebase.com/js/client/2.3.2/firebase.js"></script>
    <script>
      var firebaseRef = new Firebase("https://chat-xxxxx.firebaseio.com/");
      var messagesRef = firebaseRef.child('messages');

      messagesRef.on('child_added', function(snapshot) {
        var msg = snapshot.val();
        $('ul').prepend( '<li class="mdl-list__item"><span class="mdl-list__item-primary-content"><i class="material-icons mdl-list__item-icon">person</i><h3>' + msg.body + '</h3></span><h6>' + msg.time + '</h6></li>');
      });

      $('#send').click(function() {
        var now = new Date();
        var y = now.getFullYear();
        var m = now.getMonth() + 1;
        var d = now.getDate();
        var w = now.getDay();
        var h = now.getHours();
        var mi = now.getMinutes();
        var s = now.getSeconds();
        if ( $('#message').val() != "" )  {
          if ( $('#message').val().match(/http/)) {
            messagesRef.push({
              body: '<img src="' + $('#message').val() + '">',
              time: h + ":" + mi
            });
          } else {
            messagesRef.push({
              body: $('#message').val(),
              time: h + ":" + mi
            });
          }
          $('#message').val('');
        }
      });
    </script>
  </body>
</html>

③デプロイ

$ firebase deploy

=== Deploying to 'chat-xxxxx'...

i  deploying hosting
i  hosting: preparing public directory for upload...
✔  hosting: xx files uploaded successfully
i  starting release process (may take several minutes)...

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/chat-xxxxx/overview
Hosting URL: https://chat-xxxxx.firebaseapp.com

公開設定

  • Firebase Consoleにログイン メニュー > Database > ルール
全てのアクセスOKの設定
{
  "rules": {
    ".read": true,
    ".write": true
  }
}

注意事項

  • あくまで、社内で使ってくださいね。
  • セキュリティ
    • 全てのアクセスを許可する場合は中身に注意しましょう
    • URLが知られるとアクセスされまくって無料枠の閾値を超えるので注意