対象読者
- JavaScriptとWeb開発の基礎に理解がある方
- Reactに興味/関心があり、これから学び始める方
前提環境
筆者の検証環境は以下の通りです。
- macOS High Sierra 10.13.3
- Node.js v10.4.1/npm 6.1.0
- React 16.5.1
- firebase-tools 4.2.1
- create-next-app 0.5.9
- Next.js 6.1.2
- Babel 7.0.0
前回作成したプロジェクトを眺めてみる
前回はFirebase Hostingに対応した、Next.jsのプロジェクトを、firebase-ssrという名前で作成しました。
今回はまず、できあがったfirebase-ssrディレクトリの中を見てみましょう。srcディレクトリの中が、少し込み入った構造になっています(図1)。
src/app/
ディレクトリの中がブラウザ向けのアプリケーションで、src/functions/
ディレクトリの中がCloud Functions向けのアプリケーションになっています。それぞれの中を見てみましょう。
まずはsrc/app/
の中です。Next.jsの仕様で、src/app/pages/
内に配置したJavaScriptファイルにURLが割り当てられて1画面を構成するので、今回はエントリーポイントとなるindex.jsを見てみます(リスト1)。
import * as React from 'react' import App from '../components/App' export default () => ( <App> <p>Index Page</p> </App> )
特に何の変哲もない、普通のReactアプリケーションのように見えます。Appコンポーネント側にヘッダーやリンクが配置されていますが、本記事では触れないことにします。
さて、次はサーバー側です。src/functions/index.js
を見てみましょう(リスト2)。
const functions = require('firebase-functions') const next = require('next') var dev = process.env.NODE_ENV !== 'production' var app = next({ dev, conf: { distDir: 'next' } }) // (1) var handle = app.getRequestHandler() exports.next = functions.https.onRequest((req, res) => { return app.prepare().then(() => handle(req, res)) })
少々込み入ってはいるものの、基本的な流れとしてはnext
関数が呼び出された場合に、すべての処理をNext.jsに委譲する形になっています。(1)のdistDir: 'next'
は、src/app/
のブラウザアプリケーションをビルドしたものがfunctions/next
に出力されるので、それをサーバー側で読み込むための指定です。
デプロイしたアプリケーションでサーバーサイドレンダリングが動いていることを確認する
それでは、実際にデプロイしてみましょう。すでにdevDependenciesにfirebase-toolsがインストールされていますし、それを扱うためのnpm scriptsも整備されています。また、前回すでにFirebaseのプロジェクトをセットアップしてありますので、次のコマンドを実行するだけで、デプロイができます。
$ npm run deploy
すると、ブラウザ向けのビルドが行われてFirebase Hostingにデプロイされる処理と、サーバー向けのビルドが行われてFirebase Cloud Functionsにデプロイされる処理が、それぞれ実行されます(図2)。
前回のFirebase Hostingと同様に、最後に表示されたURLにアクセスしてみます。筆者の環境で実施したものは次のURLにあります。
開いてみると、図3のようになりました。
これだけだと何の変哲もないReactアプリケーションですね。
サーバーサイドレンダリングが行われていることを確認するために、Google ChromeのDev Toolsを開いてみます(図4)。
Dev Toolsを開いたら、図5のようにNetworkタブを開いた状態で、ブラウザを再読み込みします。
図5の「HTMLのリクエスト」の部分をクリックすると、リクエストとレスポンスの詳細が見られます。Responseタブが実際のレスポンスの内容です(図6)。
すると、HTMLデータの中にReactアプリケーションのコンテンツが埋め込まれていることがわかります。サーバーサイドレンダリングが成功しています。