りぺんぎんの書きなぐり技術書

基本、ITの技術について書きます

Firebaseで簡易ブログを作った

前回記事を書いてから大分経ちました。 サボっていたわけではなく、色々なことをやって楽しんでいました。

具体的には ちょまど氏が推している「Xamarin」さわってみたり azure のセッション見ていて面白そうと思った 「azure mobile app」 さわったり 新卒一年目金融系保守エンジニアの今後のキャリアと自分の幸せについて考えたり 色々毎日悩む日々が続いています。

今回は「azure mobile app」の関連?(くくり的にはpaasだから)である 「Firebase」で簡易ブログを作って見たので記録しておきます。

何を作ったの?

アクセスのたびにコンテンツが変化する写真メインのブログ(Instagramのクソザコナメクジブログ版)

URL: https://blog-c86e5.firebaseapp.com/

※画像が結構重いので注意

なぜ作ったの?ブログなんてWordPressでよくない?それFirebase使っている意味あるの?

正直に言います。Firebaseで作った意味あんまないです。

メリット:アクセスがしょぼい内は無料、鯖の細かい設定いらないっていうぐらい。機能の拡張性はまぁまぁ

期間は?

色々試行錯誤して(javascriptとか思い出したりして) 約 2日

どうやって作ったの? 以下に書いていきますー macOSでの操作で書いています。

使用した技術

・Firebase Hosting (HTML,js配置)

・Firebase RealTime Database (コンテンツをランダム表示処理するためのデータ管理,画像データの管理) リアルタイムの必要性皆無

・Firebase Storage (画像ファイルの配置)

プロジェクト作成(Firebaseは基本コマンドラインで操作する)

プロジェクト作成の細かい方法については省略します。わかりやすい記事書いている人がいっぱいいるんで

Firebase Web Consoleにログインして新規プロジェクト作成→Firebase Hosting→ウィザードに従う

でプロジェクトが作成できます。

困ったこと

公式ドキュメントには「firebase init」 実行時に publicフォルダとfirebase.jsonファイルが作成されるよ!

って書いてあるけど publicフォルダはできないし、firebase.jsonファイルは空だった(謎)

↓解決策

firebase.jsonをエディタで開き以下のように書き込む

{
  "hosting": {
    "public": "app",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}

publicフォルダではなく、app フォルダを作成する

設定ファイルに app を公開フォルダに設定すると書いているため

作成したappフォルダに index.html とか置いてターミナルで 「firebase deploy」実行したらデプロイされる。

ブログの仕組み

f:id:repenguin:20170918210723p:plain

大雑把ですがだいたいこんなもんです

コードを見ていくよ

index.html だよ!ユーザはこのページしか見ないよ

コンテンツを表示する枠とjavascriptの処理部分があるよ

<!DOCTYPE html>
<html lang="ja">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M"
    crossorigin="anonymous">
  <!-- firebase の必須ライブラリ -->
  <script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js"></script>
  <!-- firebase  storageのライブラリ -->
  <script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-storage.js"></script>
  <!-- firebase database のライブラリ -->
  <script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-database.js"></script>


  <script>
 // body がロードされると初期化処理を走らせる
    function initialize() {
      // コンフィグファイル
      var config = {
        apiKey: 'AIzaSyCFHfTVDbfRzt8EX7MXqC1MNE_deum02AI',
        storageBucket: 'gs://blog-c86e5.appspot.com',
        databaseURL: 'https://blog-c86e5.firebaseio.com/',
      };
      // 初期化
      firebase.initializeApp(config);
      // コンテンツとってきてね
      getContent();
    }
    
    // 非同期でコンテンツを取得するメソッド
    async function getContent() {
      // 記事数をとってきてね
      var max = await getData('maxId/contentId');
      // 最小の記事番号
      var min = 1;
      // 乱数で記事を決めてね 
      var randomContentId = Math.floor( Math.random() * (max + 1 - min) ) + min ;
      
      // HTMLのファイル名を取得するよ
      var htmlUrl = await getData('contents/content' + randomContentId);
      // index.htmlにロード
      $('#main_data').load(htmlUrl, function() {
          // htmlが読み込めたら画像をストレージから読み出すよ
          getImage(htmlUrl);
      }); 
    }
    
    // 非同期で画像を取得するメソッド
    async function getImage(htmlUrl) {
      var urlSpilit = htmlUrl.split('.')[0];
      // 画像のURLを取得
      var imageUrl = await getData('images/' + urlSpilit);
      var storage = firebase.storage();
      // 参照を作成
      var storageRef = storage.ref('images/' + imageUrl);
   // 画像のURLを取得して埋め込むよ
      storageRef.getDownloadURL().then(function (url) {
        var tag = '<img src="'+ url +'" class="img-fluid" alt="image" style="margin-bottom:50px">';
        $('#main_img').html(tag);
      }).catch(function (error) {
        console.error(error);
      });
       
    }
    
    // リアルタイムデータベースからデータを取得するメソッド
    function getData(path) {
      // async await 便利だね!!
      const p = new Promise((resolve, reject) => {
        var database = firebase.database();
        var dataRef = database.ref(path);
        // 一回だけロードするよ リアルタイムデータベースはリアルタイムでの更新を想定しているから今回みたいにそういう機能がいらない場合は一回だけ読み込むのが正解
        dataRef.once('value').then(function(snapshot){
          if(snapshot.exists()){
            resolve(snapshot.val()); 
          }
        });
      });
      return p;
    }

  </script>
  <style>
    body {
      background-color: PeachPuff;
    }
  </style>
</head>

<body onload="initialize()">
  <nav class="navbar navbar-expand-lg navbar-light bg-light" style="margin-bottom:20px;">
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01"
      aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
    <div class="collapse navbar-collapse" id="navbarTogglerDemo01">
      <a class="navbar-brand" href="index.html">RePenguin Blog</a>
    </div>
  </nav>
  <div class="container-fluid" id="main_data">

  </div>

  <!-- Optional JavaScript -->
  <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
    crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4"
    crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1"
    crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</body>

</html>

データベースの中身

f:id:repenguin:20170918215252p:plain

ストレージの中身

f:id:repenguin:20170918215354p:plain

ストレージとリアルタイムデータベースにはセキュリティルールをしっかり設定しとこう

database 書き込みはいらないから無効にしてる

{
  "rules": {
    ".read": true,
    ".write": false,
  }
}

storage 書き込みはいらないから無効にしてる

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
    }
  }
}

詳しい解説は正直いらないか… firebaseは簡単にアプリを作ることができるから良いと思います!! ただデータベースがNoSqlっていうのがなんとも言えないところ 一過性のイベントアプリとかには適してそう

今回はWebページを作りましたが firebaseの本質はスマホアプリだから今度はスマホアプリにチャレンジして見たいです!