2021新春の Nuxt + SSR + Vuetify + Firebase Setup and Deploy 覚書
Node.js は、最新の Firebase functions に合わせ 12を使います。Node.js(nvm)のインストールの方法は、検索していただければ記事があると思います。そちらを参照ください。
> nvm use v12.20.0 > npx create-nuxt-app nuxt-ssr-vuetify

ここからインストールが始まります。無事に完了すると以下の画面になります。Nodeのバージョンが古かったりするとエラーが出たりします。

Localで動作を確認します。上の画面の指示の通り npm run devを実行します。

ブラウザで http://localhost:3000 にアクセスして以下の画面が出れば動作確認は問題ありません。

この状態から Firebaseを設定しますが、事前に
- firebase-toolsのインストール
- firebase login
- firebase project の作成(コマンドラインから作成することもできますが、後ほど Project情報が必要となりますのでブラウザから作成しておくと良いと思います)
を済ませてくださいませ。
> firebase init




これで firebaseの準備は終わりです。いくつかパッケージをインストールします。
> npm i @nuxtjs/dotenv > npm i firebase
次に、ssr側、つまり、functions側(package.json)へも Host側とほぼ同様のパッケージをインストールします。
{ "name": "functions", "description": "Cloud Functions for Firebase", "scripts": { "serve": "firebase emulators:start --only functions", "shell": "firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log" }, "engines": { "node": "12" }, "main": "index.js", "dependencies": { "@nuxtjs/dotenv": "^1.4.1", "@nuxtjs/pwa": "^3.3.3", "@nuxtjs/vuetify": "^1.11.2", "async": "^3.2.0", "axios": "^0.21.1", "core-js": "^3.8.2", "firebase": "^8.2.1", "firebase-admin": "^9.4.2", "firebase-functions": "^3.11.0", "nuxt": "^2.14.12" }, "devDependencies": { "firebase-functions-test": "^0.2.0" }, "private": true }
次に、firebase.jsonの内容を変更します。
{ "functions": { "source": "functions", "predeploy": [ "rm -rf functions/nuxt && cp -r .nuxt/ functions/nuxt/" ] }, "hosting": { "predeploy": [ "rm -rf public/* && mkdir -p public/_nuxt && cp -r .nuxt/dist/client/ public/_nuxt && cp -a static/. public/" ], "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "function": "ssr" } ], "headers": [ { "source": "**/*", "headers": [ {"key": "X-Content-Type-Options", "value": "nosniff"}, {"key": "X-Frame-Options", "value": "DENY"}, {"key": "X-XSS-Protection", "value": "1; mode=block"}, {"key": "Access-Control-Allow-Origin", "value": "*"}, {"key": "Access-Control-Allow-Headers", "value": "Content-Type"}, {"key": "Content-Security-Policy", "value": "script-src 'self' https://www.gstatic.com/ https://cdn.jsdelivr.net/ https://*.firebaseio.com https://apis.google.com https://*.googleapis.com https://www.google-analytics.com; object-src 'self' https://www.youtube.com;"} ] } ] } }
次に、nuxt.config.jsの何箇所か追加(’@/plugins/firebase.js’, ‘@nuxtjs/dotenv’)します。
import colors from 'vuetify/es5/util/colors' export default { // Global page headers (https://go.nuxtjs.dev/config-head) head: { titleTemplate: '%s - nuxt-ssr-vuetify', title: 'nuxt-ssr-vuetify', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' }, { hid: 'description', name: 'description', content: '' } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ] }, // Global CSS (https://go.nuxtjs.dev/config-css) css: [ ], // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins) plugins: [ '@/plugins/firebase.js' ], // Auto import components (https://go.nuxtjs.dev/config-components) components: true, // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules) buildModules: [ // https://go.nuxtjs.dev/vuetify '@nuxtjs/vuetify', ], // Modules (https://go.nuxtjs.dev/config-modules) modules: [ '@nuxtjs/dotenv', // https://go.nuxtjs.dev/axios '@nuxtjs/axios', // https://go.nuxtjs.dev/pwa '@nuxtjs/pwa', ], // Axios module configuration (https://go.nuxtjs.dev/config-axios) axios: {}, // Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify) vuetify: { customVariables: ['~/assets/variables.scss'], theme: { dark: true, themes: { dark: { primary: colors.blue.darken2, accent: colors.grey.darken3, secondary: colors.amber.darken3, info: colors.teal.lighten1, warning: colors.amber.base, error: colors.deepOrange.accent4, success: colors.green.accent3 } } } }, // Build Configuration (https://go.nuxtjs.dev/config-build) build: { } }
plugins/firebase.js を作成します。内容は以下の通りです。(FUNCTIONS_URLの部分はなくてもよいです。axios経由で firebase function を呼び出すときの URLです。)
import firebase from 'firebase/app' if (!firebase.apps.length) { const app = firebase.initializeApp({ apiKey: process.env.apiKey, authDomain: process.env.authDomain, databaseURL: process.env.databaseURL, projectId: process.env.projectId, storageBucket: process.env.storageBucket, messagingSenderId: process.env.messagingSenderId, appId: process.env.appId, measurementId: process.env.measurementId }) } // export default firebase const FUNCTIONS_URL = process.env.FUNCTIONS_URL export default ({}, inject) => { inject('FUNCTIONS_URL', FUNCTIONS_URL) }
.env を作成します。それぞれのパラメーターは、Firebaseコンソール > プロジェクトの概要 > プロジェクトを設定 > マイアプリ > ウェブアプリから取得できます。
// Firebase Config apiKey = '' authDomain = '' databaseURL = '' projectId = '' storageBucket = '' messagingSenderId = '' appId = '' measurementId = '' FUNCTIONS_URL = ''
これで build して deployすると Hosting URL: https:// とホスティングされた URLが表示されますので、アクセスしてみてください。
> npm run build && firebase deploy

尚、CSP(Content Security Policy)でエラーが発生すると思います。とりあえず、指示通りにハッシュコードを firebase.jsonへ追加し、再 Deploy、キャッシュクリア及びリロードでエラーは消えると思います。
{"key": "Content-Security-Policy", "value": "script-src 'self' https://www.gstatic.com/ https://cdn.jsdelivr.net/ https://*.firebaseio.com https://apis.google.com https://*.googleapis.com https://www.google-analytics.com; object-src 'self' https://www.youtube.com;"}
ここの ‘self’ の後に半角スペースを空けて、’sha256-zP5h5M4BR3kXO3X+w0FqAWUXHQ4d2NMBFUj3Qk3r+Ik=’ を追加してください。(このハッシュ値はエラーメッセージを参照してください)
コード(.env除く)は、nuxt-ssr-vuetify-firebaseにあります。