最近つくった積読ハウマッチをNuxtのSPAで作成しているけど、
シェアされたときにいい感じに画像とかを表示してほしいのでやってみた。
N番煎じ感がつよいけれど、自分の整理用〜
若干複雑...
図的にはこんな感じ
まずは、Cloud Function for Firebaseから。
リスエストのパスに応じてDBの値を取得して、OPG用のHTMLを生成。
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
// ********************************************************
// * Generate OPG HEAD
// ********************************************************
/**
* OGP用のヘッダだけのHTMLを返す関数
* @param {String} TITLE タイトル
* @param {String} DESCRIPTION ディスクリプション
* @param {String} OGP_URL OGP画像のURL
* @param {String} PAGE_URL 該当ページのURL
* @param {String} REDIRECT_URL リダイレクト先のURL
*/
const createHtml = (TITLE, DESCRIPTION, OGP_URL, PAGE_URL, REDIRECT_URL) => {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>${TITLE}</title>
<meta property="og:title" content="${TITLE}">
<meta property="og:image" content="${OGP_URL}">
<meta property="og:description" content="${DESCRIPTION}">
<meta property="og:url" content="${PAGE_URL}">
<meta property="og:type" content="article">
<meta property="og:site_name" content="${SITE_NAME}">
<meta name="twitter:site" content="${BASE_URL}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${TITLE}">
<meta name="twitter:image" content="${OGP_URL}">
<meta name="twitter:description" content="${DESCRIPTION}">
</head>
<body>
<script type="text/javascript">window.location="${REDIRECT_URL}";</script>
</body>
</html>
`;
};
/**
* '/user/<userId>'に対応するHTMLを返すFunction
*/
const BASE_URL = '<サイトのBASE_URL>'
exports.users = functions.https.onRequest(async (req, res) => {
try {
// PATHからパスパラメータを取得
const [, , userId] = req.path.split("/");
if (!userId) throw new Error(`userId is empty`);
// パスパラメータを使って、DBからデータを取得
const docRef = db.collection("users").doc(userId);
const snap = await docRef.get();
if (!snap.exists) throw new Error(`Not Found: userId=${userId}`);
// DBのデータからHTML作成に必要なデータを用意
const user = snap.data();
const title = `${user.name}さんのページ`;
const desc = `${user.name}さんのページの詳細です`;
const ogpURL = "<該当ユーザのOGP画像のURL>";
const pageURL = `${BASE_URL}/user/${userId}`;
const redirectURL = `/_user/${userId}`;
// ヘッダだけのHTMLを生成
const html = createHtml(title, desc, ogpURL, pageURL, redirectURL);
// キャッシュを設定
res.set("Cache-Control", "public, max-age=600, s-maxage=600");
// 生成したHTMLを返却
res.status(200).end(html);
} catch (err) {
// エラーが発生したら'/'にリダイレクト
console.warn(err);
res.redirect("/");
}
});
firebase.jsonの設定。該当のパスにアクセスされたら、
リライトでFunctionを呼び出すように設定を追加。
{
"functions": {
"source": "functions"
},
"hosting": {
"rewrites": [
// '/user/<userId>'へのアクセスがあったらFunctionsのusersを呼び出す
{
"source": "/user/*",
"function": "users"
},
{
"source": "**",
"destination": "/404.html"
}
],
},
}
nuxt.config.jsのrouterの設定。HTML内でリダイレクトされる先を、
さらにrouter側でリダイレクト。もとに戻す感じに。
const config: NuxtConfiguration = {
/*
** Router configuration
*/
router: {
extendRoutes(routes: NuxtRouteConfig[], resolve) {
routes.push({
path: "/_user/:uid",
redirect: "/user/:uid",
chunkNames: {}
});
}
},
}
ちなみに、該当のパスにHostingのHTMLがあるとダメ...
Hostingの優先度がこんな感じ...
リライトよりも静的コンテンツのほうが優先度が高いので、
リライトでFunctionを呼び出されるよりも先にHTMLが返されてしまう...
nuxt generate
するとHTMLが配置されてしまうので、
動的パラメタじゃないとダメかも...
以上!!
積んでいる本の総額がわかる読書管理サービス
『積読ハウマッチ』をリリースしました♪
積読が多い方も、少ない方も、ない方も、
ぜひお試しください(´ω`)
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント