LoginSignup
24
25

More than 3 years have passed since last update.

Vue.jsとWordPressを共存させる(OGPにも対応)

Last updated at Posted at 2020-04-26

地元のグルメ情報を紹介するWebアプリをVue.jsで作り、WordPressで運営しているサイトのサブディレクトリー上に公開しました。また。WebアプリのURLがSNSでシェアされた時に写真が展開されるよう、OGPに対応させています。

この記事ではWordPressを使っているサイトにVue.jsのアプリを同居させ、プリレンダリングを使ってOGPに対応させる方法について紹介します。WordPressは https://example.com で運営され、そこにVueアプリを https://example.com/app-name/ で公開するものとします。

前提とする環境

Vue CLIを使ってアプリを開発しています。

$ npm install -g @vue/cli 
$ vue --version
@vue/cli 4.2.3

ルート以外でVueアプリを公開する

開発したアプリはルートディレクトリ https://example.com/ で公開されるように作られています。これを、サブディレクトリ https://example.com/app-name/ で公開されるように変更します。

WordPressをサーバーのディレクトリー/にインストールしている場合、その下に新しく/app-nameディレクトリーを作り、Vueアプリの成果物をアップロードします。

最初はWordPressの動作をよく理解していなかったので、

  • /app-name/ でアクセスできるページが必要?
  • それなら「固定ページ」で app-name を作ればいいのでは?

と誤解していたのですが、そんなことは不要でした。

vue.config.js を変更する

vue.config.js に publicPath [公式]、outputDir [公式] を追記します。

vue.config.js
module.exports = {
  publicPath: '/app-name/',
  outputDir: 'dist/app-name/',
  ...
}

まず、開発用サーバーで正しく動作するかを確認します。

$ npm run serve
...
 DONE  Compiled successfully in XXXXms

  App running at:
  - Local:   http://localhost:8080/app-name/ 
  - Network: http://XXX.XXX.XXX.XXX:8080/app-name/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

Webブラウザーで http://localhost:8080/app-name/ にアクセスして、正しく動作することを確認します。

public ディレクトリーに.htaccessを作成してビルド

WordPressはWebブラウザーが/app-nameにアクセスした時に/app-name/index.phpを読み込むように設定されています。その設定はサーバーの/.htaccessに書いてあります。
Vue.jsでは/app-nameにアクセスした時に(index.phpではなく)/app-name/index.htmlを読み込むことを期待します。そこで、/app-name/.htaccessを準備して/app-nameにアクセスしたときの動作を変更します。ここで作成する.htaccessファイルは開発マシンのpublicディレクトリーに作ります。

public/.htaccess
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /app-name/
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . index.html [L]
</IfModule>

参考:WordPressのサブディレクトリでVueアプリを動かす

次にビルドを実行して、dist/app-name/ に成果物が出力されることを確認します。なお、vue uiでbuildタスクを動かす場合、vue.config.js の outputDir が無視されます。UIからoutputを設定してください。

参考:outputDir config not working #2639

$npm run build
...
 DONE  Build complete. The dist/gourmet directory is ready to be deployed.
 INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html

WordPressの.htaccessを書き換える

生成された dist/app-name をサーバーの/app-nameとしてアップロードします。ここで https://example.com/app-name にアクセスしても、まだVueアプリは動作しません。サーバー側の/.htaccessを修正して、/app-nameへのアクセスだけは/app-name/.htaccessに書いたルールで動作させる必要があります。

修正を間違えるとWordPressが正しく動作しなくなるため、.htaccessファイルのコピーを別名で作ってから作業してください。

/.htaccess
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(^/app-name/) # この行を追加
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

参考:WordPressのサブディレクトリでVueアプリを動かす

https://example.com/app-name にアクセスしてVueアプリが正しく動作することを確認してください。

VueアプリをOGPに対応させる

OGPではシェアしたときに表示したい写真のURLなどをHTMLの

タグにあるタグに記述します。そのページのURLがSNSでシェアされた時に、SNSのボットがそのURLにアクセスし、metaタグを解析することでSNSに表示する情報を決めています。

VueアプリのトップページをOGPに対応させる

public/index.html を編集して、OGPに対応させます。このファイルはビルドにより dist/app-name/index.html として出力されるのでそのままサーバーにアップロードして公開します。

public/index.html
<!DOCTYPE html>
<html lang="ja">
  <head prefix="og:http://ogp.me/ns# fb:http://ogp.me/ns/fb# website:http://ogp.me/ns/website#">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="/favicon.ico">
    <title>[アプリ名]</title>
    <meta name="description" content="[アプリの説明]" />
    <meta property="og:type" content="website" />
    <meta property="og:site_name" content="[サイト名]" />
    <meta property="og:title" content="[アプリ名]" />
    <meta property="og:url" content="https://example.com/app-name/" />
    <meta property="og:image" content="https://example.com/app-name/img/app-name.jpg" />
    <meta property="og:description" content="[アプリの説明]" />
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content="@[アプリのTwitterアカウント名]" />
    <meta name="twitter:player" content="@[アプリのTwitterアカウント名]" />
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue_app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

公開後、OGPの情報が正しく設定されているかを確認するため、以下のツールにアプリのURLを入力して動作を確かめます。

Vue Routerで作ったページをOGPに対応させる

OGP対応で問題になるのが、Vue Routerを使ったアプリです。

OGPの情報を収集するFacebookやTwitterのボットはJavaScriptに対応していません。なので、Vue Routerで生成したURLにボットがアクセスしてもOGPの情報を収集することがでず、そのURLをSNSでシェアしても、写真などが展開されることはありません。

そこでビルドの際にヘッドレスブラウザーPuppeteerを使ってプリレンダリングを実施し、Vue RouterのURLごとにindex.htmlを成果物として作成します。出来上がったindex.htmlをそのままサーバーにアップロードして公開すれば、ボットがOGPの情報を収集できるようになります。

vue-meta を使ってURLごとにOGPを設定する

Nuxt.jsに含まれるvue-metaを使えば、URLごとに異なるOGP情報を設定できます。

vue-metaを使う時に気をつける必要があるのは、変更するタグには data-vmid 属性を付与することです。

ここでは、description, og:title, og:url, og:image, og:description の5つを変更するため、public/index.html を次のように修正します。

public/index.html
...
    <meta data-vmid="description" name="description" content="[アプリの説明]" />
    <meta data-vmid="og:title" property="og:title" content="[アプリ名]" />
    <meta data-vmid="og:url" property="og:url" content="https://example.com/app-name/" />
    <meta data-vmid="og:image" property="og:image" content="https://example.com/app-name/img/app-name.jpg" />
    <meta data-vmid="og:description" property="og:description" content="[アプリの説明]" />
...

その上で、vue-meta をインストールして、URLに応じてタグを書き換えるために metaInfo() を記述します。

$ npm install --save vue-meta
Spot.vue
...
<script>
...
  data: {
    return: function() {
      id: '...',
      titie: '...',
      desc: '...'
    }
  },
  metaInfo() {
    return {
      title,
      meta: [
        { vmid: 'description', name: 'description', content: desc },
        { vmid: 'og:title', property: 'og:title', content: title },
        { vmid: 'og:description', property: 'og:description', content: desc },
        { vmid: 'og:url', property: 'og:url', content: `https://example.com/app-name/spots/${this.id}/` },
        { vmid: 'og:image', property: 'og:image',
          content: `https://example.com/app-name/img/${this.id}.jpg`
        }
      ]
    }
  }
}
</script>

参考:メタタグが重複したときは? - NuxtJS

prerender-spa-plugin を使ってビルドの際にプリレンダリングを実施する

prerender-spa-pluginを使ってビルド時に開発用サーバーを起動し、PupeteerでVueアプリにアクセスすることでHTMLを生成していきます。

ここではVueアプリのURLとして /app-name/spots/00001/ から /app-name/spots/00100/ が存在するとします。

$ npm install --save prerender-spa-plugin

staticDir は app-name なし、indexPath は app-name ありで index.html まで指定することに気をつけてください。

なお、アクセスする先の /app-name/spots/:id は、アクセスしてから <div id="spot" /> が表示されるまでに少し時間がかかるので、Puppeteer にそのタグが出るまで待たせるようにしています。皆さんのアプリには不要なので削除してご利用ください。

vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer

module.exports = {
  publicPath: '/app-name/',
  outputDir: 'dist/app-name/',
  configureWebpack: () => {
    if (process.env.NODE_ENV === 'production') {
      const routes = []
      for (let i = 1; i <= 100; i++) {
        let id = String(i).padStart(5, '0')
        routes.push(`/app-name/spots/${id}/`)
      }
      return {
        plugins: [
          new PrerenderSPAPlugin({
            staticDir: path.join(__dirname, 'dist'),
            indexPath: path.join(__dirname, 'dist/app-name/index.html'),
            routes,
            renderer: new Renderer({
              renderAfterElementExists: '#spot'
            }),
          })
        ]
      }
    }
  }
}

あとはビルドを実行して、dist/app-name/spots の下に 00001/index.html, ..., 00100/index.html がそれぞれ出力されて、タグに期待通りの情報が記述されていることを確認してください。

参考:プリレンダリングを用いてVue.jsのSPAをビルドする導入から設定まで

問題がなければdist/app-nameをサーバーにアップロードし、Facebook デバッガーなどで https://example.com/app-name/spots/00001/ などが期待通りに動作するか確認してください。

24
25
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
24
25