30
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Firebase】Cloud Functions + Express + EJSで動的コンテンツを配信する

Last updated at Posted at 2017-10-07

Firebaseの公式リファレンスを見ると以下のように書いてありました。

Cloud Functions による動的コンテンツの配信

Firebase Hostingでは、Cloud Functionsを使用してサーバー側の処理を実行できます。つまり、Firebase Hostingサイトのコンテンツの動的生成をサポートすることができます。

どうやらFirebase Hostingは、動的なサイトも運用できるという、何とも素晴らしいサービスのようなので、実際に動的コンテンツの配信を行ってみました。

Node.jsの「Express」を使います。テンプレートエンジンには「EJS」を使います。(ここは別に「Pug」でも「handlebars」でも問題ないです)

Firebase Hostingの環境構築の説明は割愛します。
詳しくはこちらをどうぞ

プロジェクトの階層

階層はこんな感じです。

├── firebase.json
├── functions
│   ├── firebase-debug.log
│   ├── index.js
│   ├── node_modules
│   │   ├── @types
│   │   ├── ・・・・・・・
│     │     ├── ・・・・・・・
│   ├── package-lock.json
│   ├── package.json
│   └── views
│       └── template.ejs
└── public
    └── index.html

#npmで「Express」と「EJS」をインストール

expressのインストール

$ npm install express --save

ejsのインストール

$ npm install ejs --save

それぞれnpmでインストールする必要があります。

firebase.json ファイル

firebase.json を開き、内容を次のコードに置き換えます。

firebase.json
{
  "hosting": {
    "public": "public",
    "rewrites": [
       {
         "source": "/**",
         "function": "sample"
       }
    ]
  }
}

関数にHostingリクエストを送信する

リライトルールを使用すると、特定のパターンに一致するリクエストを単一の宛先に送ることができます。
/** のすべてのリクエストを送信して sample というHTTPS関数を実行します。

今回はトップページは静的なページを表示し、 /** にアクセスがあると(/page1と/page2)、 ** に応じた動的コンテンツを返します。

public

ルート直下 / は「public」ディレクトリ内の index.html ファイルがロードされます。
ファイルの中身は以下です。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="content-type">
    <title>トップページ</title>
    <style>
    h1 { font-size:18px; background-color:#eaeaea; }
    </style>
</head>
<body>
    <header>
        <h1 id="h1">トップページ</h1>
    </header>
    <div>
        <p>これはトップページです。</p>
        <ul>
          <li><a href="/page1">ページ1へ</a></li>
          <li><a href="/page2">ページ2へ</a></li>
        </ul>
    </div>
</body>
</html>

HTTPS関数を作成する index.js

/functions/index.js を開き、内容を次のコードに置き換えます。前述した sample というHTTPS 関数をここで作成。

index.js
const functions = require('firebase-functions');
const express = require('express');
const url = require('url');
const app = express();

const routes = {
    "/page1":{
        "title":"ページ1",
        "content":"これはページ1です。"
    },
    "/page2":{
        "title":"ページ2",
        "content":"これはページ2です。"
    }
};

app.set("view engine","ejs");
app.engine('ejs', require('ejs').__express);

app.get("*",function(req,res){

  const url_parts = url.parse(req.path);
  
  if(routes[url_parts.pathname] == null){
    res.status(404).send("page not found");
  }else{
    res.status(200).render("template",
      {
          title: routes[url_parts.pathname].title,
          content: routes[url_parts.pathname].content
      }
    );
  }
});

exports.sample = functions.https.onRequest(app);

ビューエンジンにejsをセットする

以下の部分です。

app.set("view engine","ejs");
app.engine('ejs', require('ejs').__express);

routesにデータをまとめておく

各ページのデータを routes 変数にまとめています。
アクセス先のpathをキーとして用意し、そのpathで表示されるページ情報を連想配列で値にセットします。

この routes 変数から、パスごとに必要な情報をロードして処理します。

const routes = {
    "/page1":{
        "title":"ページ1",
        "content":"これはページ1です。"
    },
    "/page2":{
        "title":"ページ2",
        "content":"これはページ2です。"
    }
};

「url」オブジェクトをロードする

「url」オブジェクトをロードします。URLの文字列をパースする為に使います。

const url = require('url');

アクセスしてきたURLをパースする

パースして url_parts 変数に変換します。

const url_parts = url.parse(req.path);

判定

アクセスがあったpathを判定して、 routes[url_parts.pathname] に一致しなければ404を送り、一致すれば、 routes 変数を元にしたデータをJSONで送り、テンプレートをレンダリングします。

if(routes[url_parts.pathname] == null){
    res.status(404).send("page not found");
}else{
    res.status(200).render("template",
      {
          title: routes[url_parts.pathname].title,
          content: routes[url_parts.pathname].content
      }
    );
}

テンプレートファイルを用意

「functions」ディレクトリ内に「views」ディレクトリを作成し、その中に template.ejs ファイルを作成します。ファイルの中身は以下です。

template.ejs
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="content-type">
    <title><%=title %></title>
    <style>
    h1 { font-size:18px; background-color:#eaeaea; }
    </style>
</head>
<body>
    <header>
        <h1 id="h1"><%=title %></h1>
    </header>
    <div>
        <p><%-content %></p>
        <ul>
          <li><a href="/">トップページへ</a></li>
        </ul>
    </div>
</body>
</html>

デプロイ後の結果

/ は静的なトップページが表示され、/page1 /page2にアクセスすると動的ページとしてそれぞれのURLに応じたコンテンツが表示されます。

スクリーンショット_2017-10-07_21_16_48.jpg

スクリーンショット_2017-10-07_21_17_08.jpg

まとめ

Firebase HostingでCloud Functionsを使えば本格的に動的なサイトも運用できるんです。
しかも無料で(制限あり)

Firebaseは制限多いと思ってましたけど、これならAWS Lambdaより気軽に柔軟なアプリケーションが作れる気がします。Firebase Realtime Databaseと組み合わせて。

30
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?