16
14

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.

[Nuxt.js] SPAモードで無理やりmetaタグを入れてSEO対策する裏技

Last updated at Posted at 2019-09-13

NuxtのSPAモードで開発してるとき、
急にページ単位で違うOGP入れたくなったりした事ってありませんか?
私はありません。

が、業務上そういう必要に駆られてしまうことは稀にあります。
そういう場合はサーバーサイドレンダリングをやってくれるUniversalモードを使えばいいんですが、

とはいえSPAモードで開発してたものを後からUniversalモードに切り替えたりすると、
ブラウザ情報を取得して動かしてたものが、サーバーサイドに移ったことで動かなくなったりするので
検証したりロジック修正したりとかなり面倒で手間をかけされられます。

というわけで、Nuxtを書き出すレンダラや配信するサーバに介入して無理やりHTMLにmetaタグをぶち込みます。

※ この記事ではどうやってNuxtが書き出したHTMLを配信する前に捕まえるかについて書いています。 実際にNode.jsでHTMLを編集するにはどうしたらいいかについてはまた別途記事を書く予定です。

参考にした資料: 【Nuxt(SPA)でもOGPしたい/want to render ogp with nuxt spa mode@fruitriin

Nuxt自体をExpressモジュールとして使おう!

↑の公式リファレンスで触れられている通り、Nuxtはそれ自体を別のNode.jsプログラムに組み込んで使うことができる。
特にNuxtのページ自体を書き出す Nuxt.render(req, res) はリクエスト/レスポンス要素を引数に取るため、
ExpressサーバであればNuxt.renderをそのままモジュールとして使うことができる。

const express = require('express');
const { Nuxt, Builder } = require('nuxt');
const config = require('./nuxt.config.js');

// Expressサーバを作成
const app = express();

// Nuxtを起動
const nuxt = new Nuxt(config);
nuxt.ready();

// ExpressにNuxtモジュールを使う
app.use('/*', nuxt.render);

app.listen(3000);

こんな感じ。
で、nuxt.renderはページのレンダリングから配信まで一気にやってしまうため、
何とかしてレンダリング結果を捕まえて、そこでmetaタグを注入してやればいい、ということになる。

方法1. renderRouteを使う

HTML要素をレンダリングだけする(配信はしない)メソッド
Nuxt.renderRoute(path, context) というのがあるので、
meta要素の注入が必要な部分だけrenderではなくrenderRouteでHTML文字列を書き出して、それに対してmeta埋め込み操作を行った後に配信する。

// ExpressにNuxtモジュールを使う

// 特定のルートならOGP改ざん
app.get('/detail/*', (req, res) => {
  const result = nuxt.renderRoute('/', req);
  /** result.htmlの中にHTML文書が文字列が入っているのでmetaタグを入れてやる **/
  res.send(result.html);
});

// それ以外のルートを通常通り描画
app.use('/*', nuxt.render);

こんな感じ。

ただ問題は、飛んできたリクエストがHTMLかどうかを判断するルート分けをしておかなければならないこと。
例えば上記の例だと、/detail/以下のパスに対して全てHTMLを配信する形になるため、
/detail/hoge.jsだったり/detail/fuga.pngだったりするHTML以外のリクエストにもそのままHTMLを返しに行ってしまう。
厳密にルーティング書いてやれば行けなくもないがめんどくさいので、もっと簡単にできる方法を探したところ、あった。

方法2. hookで割り込み処理をかける

requireで呼び出したNuxtインスタンスに対して、特定のライフサイクルイベントが発火した時に処理を捕まえて、処理を追加することができるhookという仕組みが存在する。

使い方はこんな感じ。

// nuxtの配信準備ができたらコンソールログを吐く
nuxt.hook('ready', (nuxt) => {
  console.log('ready for nuxt');
  return;
});

要はイベントリスナに登録するみたいなものと考えてもらえばOK。
そのフックできるイベントの中にrender:routeという、
ルートがサーバレンダリングされる度に発火し、レンダリング結果を引数に取るイベントがあるので、これを使って割り込み処理を実装してやる。

nuxt.hook('render:route', (url, result, context) => {
  // ルーティングの結果がhtmlでないなら早期return
  if (!render.html) return result;
  // 特定のルートならOGP改ざん
  if (/^\/detail\/.*/.test(url)) {
    /** result.htmlの中にHTML文書が文字列が入っているのでmetaタグを入れてやる **/
  }
  return result;
})

// ExpressにNuxtモジュールを使う
app.use('/*', nuxt.render);

こうしてやれば割とざっくりしたパス指定でも
NuxtのレンダラがHTMLを配信するか、それ以外のリソースなのかを判断してくれるので楽。

まとめ

最初からUniversalモードでSSR開発しよう!!!

16
14
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
16
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?