owned mediaウェブ制作に役立つコンテンツを発信中!

ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #2:フロントエンドでのサイト制作

最終更新日: Update!!
前回記事「ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築」に引き続き、ヘッドレスCMSとSSGを使ったJamstackの構成でのサイト制作についてまとめていきたいと思います。第二回の本記事では、Nuxt.jsでベースとなるサイト制作を行っていきます。この段階でベースとなる設定やページ、コンポーネント、また基本的な処理などを用意していきます。ヘッドレスCMSの構築については過去記事をご覧ください。 (過去記事) ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築  
Nuxt.jsを使ったフロントエンド側でのサイト制作
まずは新規のNuxt.jsのプロジェクトを作成していきます。いつもの通り下記のコマンドでモジュールをインストールしていきます。初回インストール時の設定などは必要に応じて選択していきます。
$ npx create-nuxt-app PROJECT_NAME
  インストールが終わると、開発用サーバーを立ち上げて正しく表示されるかをチェックしておきます。
$ cd PROJECT_NAME
$ yarn dev
  ローカルホスト(http://localhost:3000)にアクセスして初回のデモ画面が表示されていればOKです。引き続き開発を進めていきましょう。上手くいかないなどの場合には過去記事にも詳しくまとめていますのでご参考に。 (参考記事) ・Nuxt.jsでTypeScriptを導入する環境構築まとめ ・Vue.jsのフレームワークであるNuxt.jsの導入と新規プロジェクト作成フローまとめ  
必要モジュールのインストール
無事にインストールが終わると、サイトの本格的な制作へと移りますが、その前に必要なモジュールをあらかじめ揃えておきます。初回インストール時に済んでいるものもあれば、まだインストールされていないものもあるかと思いますので、個別に必要なものをインストールしていきます。参考までにいくつかのモジュールを下記にまとめています。  
@nuxtjs/axios HTTPでの非同期通信を行う、API経由で投稿データを取得する際に使用
@nuxtjs/sitemap 個別記事ページを含めたサイトマップを生成できる
@nuxtjs/google-analytics グーグルアナリティクスを導入する
cross-env 環境変数で開発環境や本番環境を切り分けることができる
@nuxtjs/eslint-module, eslint, eslint-plugin-nuxt, eslint-config-prettier, eslint-plugin-prettier ESlint関連のモジュール
@nuxtjs/stylelint-module, stylelint stylelint関連のモジュール
sass, sass-loader, fibers Sassの導入
pug, pug-plain-loader Pugの導入
  各モジュールのインストール後の詳しい使用例などは下記の過去記事などで紹介していますので、合わせてご参考に。 (参考記事) ・Nuxt.jsでcross-envを使って本番環境と開発環境のURLを切り分けてみる ・Nuxt.jsのプロジェクトでSassやstylus、Pugを使えるようにする ・Nuxt.jsのプロジェクトでGoogleアナリティクスを導入する方法まとめ   また、TypeScriptで作成する場合には別途対応するためのモジュールが必要となります。この辺りはまた後日別記事にてまとめていきたいと思います。  
環境変数用ファイルの準備
続いて、先に環境変数を切り替えられるように設定ファイルを準備していきます。環境変数用のファイルを用意することで、コマンドごとに開発環境用、本番環境用などで出力ファイルの内容を変えることができます。特に動作検証などでステージング環境などのテスト用環境を用意する場合には必須となりますので、あらかじめ準備しておくといいですね。ここでは下記のように開発環境ごとにスクリプトファイルを用意して、開発環境用の値をインポートできるようにしています。
┣ node_modules
┣ .....
┣ env.development.js
┣ env.staging.js
┣ env.production.js
┗ nuxt.config.js
  基本的にはURLやサイトタイトルなどが必要となる感じですが、それ以外にも開発環境や本番環境で切り替えたいものがあれば、このように追加していく形になります。
// env.development.js
module.exports = {
  BASE_URL: 'http://localhost:3000/',
  BASE_NAME: '(開発環境)サイトタイトル',
}

// env.production.js
module.exports = {
  BASE_URL: 'https://example.com/',
  BASE_NAME: 'サイトタイトル'
}
  モジュールについても詳しくは過去記事にまとめていますのでご参考にどうぞ。 (参考記事) ・Nuxt.jsでcross-envを使って本番環境と開発環境のURLを切り分けてみる  
nuxt.config.jsファイルの設定
次にNuxt.jsのプロジェクト設定ファイルであるnuxt.config.jsを編集していきます。こちらも基本的にはプロジェクトの内容に合わせて行っていきますが、今回はSSGということで、いくつか必須となる設定があります。下記はあくまで設定ファイルの一部を抜粋したものになりますが、詳細を確認していきましょう。まずは必要なモジュールなどをrequireで読み込んでいき、エクスポートで設定内容を出力していきます。 【nuxt.config.js】※一部抜粋
const environment: any = process.env.NODE_ENV
const envSettings: any = require(`./env.${environment}.js`)
const dartSass: any = require('sass')
const fibers: any = require('fibers')
export default {
  ssr: 'true',
  target: 'static',
  env: envSettings,
  .....
  generate: {
    fallback: '404.html',
    subFolders: true,
    .....
  }
  head: {
    htmlAttrs: {
      lang: 'ja',
      prefix: 'og: http://ogp.me/ns#',
    },
    title: 'サイトタイトル',
    .....
  }
  .....
  buildModules: [
    '@nuxtjs/stylelint-module',
    '@nuxtjs/google-analytics'
    .....
  ],
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/sitemap',
    .....
  ],
  build: {
    extend(config, ctx) {},
    postcss: {
      preset: {
        autoprefixer: { grid: 'autoplace' }
      }
    },
    loaders: {
      sass: {
        implementation: dartSass,
        sassOptions: {
          fiber: fibers,
          indentedSyntax: true,
          outputStyle: 'compressed'
        }
      }
    },
  },
  sitemap: {
    hostname: 'https://exmaple.com',
    exclude: [ '/404' ],
    .....
  },
  googleAnalytics: {
    id: 'UA-***********-*'
  },
  .....
}
  ここでは静的サイトとしてビルドする想定になりますので「ssr」の設定はtrueに、「target」の設定は「static」にしておきます。静的サイトとしてgenerateコマンドを使ってビルドする場合にはこの設定が基本となります。「generate」の設定ではビルド後のファイルに関する指定を行います。上記では404エラーページの指定と、下層ページをディレクトリ型で構成する設定にしています。この辺りは適宜プロジェクトの内容に合わせて調整していきます。そのほかは使用するモジュールの設定やheadタグに関する指定が基本となります。この他にもいくつか細かい設定もありますがここでは割愛させていただきます。また詳しい個別の設定に関しては別記事にてまとめてみたいと思います。  
ページテンプレート・コンポーネント・ストアファイルの作成
諸々の設定等が終わればいよいよコーディングに入ります。Nuxt.jsでは基本的にコンポーネントごとにコーディングを行なっていきますが、pagesディレクトリにはページ自体のコンポーネントを、componentsディレクトリにはページ内で使われるコンポーネントと分けて格納していきます。Nuxt.jsの場合ですとpagesディレクトリ配下に作成したディレクトリがそのままページのルーティングになりますので、実際のページ構成に合わせて作成していきます。静的なページの場合には「index.vue」という形で、投稿詳細ページなど動的なルーティングが当てられるページは、パーシャルファイルとして先頭にアンダーバーをつけたファイル名になります。今回は「_id.vue」としているので、コンポーネント側で$route.params.idとしてルーティングで使われる値(動的に当てられたURLパス)を取得できるようになります。動的なルーティングについてはまたこの後の記事で詳しく解説していきたいと思います。
/SRC_DIR
  ┣ ......
  ┣ components
    ┣ componentA.vue
    ┣ componentB.vue
    ┣ componentC.vue
    ......
  ┣ pages
    ┣ index.vue
    ......
    ┣ about
      ┗ index.vue
    ┣ contact
      ┗ index.vue
    ┗ blog
      ┣ index.vue
      ┗ _id.vue
  ┗ store
    ┣ index.js
    ......
    ┗ blog.js
  そのほか、グローバル変数や投稿データを格納するためのstoreファイルを必要に応じて作成しておきます。基本的にAPI経由で取得した投稿データはstateの値に格納しておくとコンポーネントを細かく分けても対応できるので、用意しておいたほうが良さそうですね。storeのファイルについては詳しくは過去記事にて紹介しています。 (参考記事) ・Vue.jsでactions、mutations、gettersをマッピングしてVuexを使いやすくする ・stateの値を参照するときに使えるgettersについて ・Vue CLIとVuexでアプリケーションの状態変化を扱う  
404エラーページの作成
必須ではないものの、404エラーページも独自のテンプレートで用意しておきたいですね、404エラーページのテンプレートとルーティングの設定も合わせて行なっておきます。generateでの静的ビルドでは、基本的に「404.html」というファイル名で生成されます。この時他のファイル名に変更したい場合には、nuxt.config.jsのgenerateのキーにある「fallback」の値に対象となるファイル名を指定します。
/SRC_DIR
  ┣ ......
  ┣ pages
    ┣ index.vue
    ......
    ┗ 404.vue
  ┣ ......
  404エラーページのルーティングについては下記のようにnuxt.config.jsの「router」オプションで設定します。 【nuxt.config.js】※一部抜粋
export default {
  ...... 
  router: {
    extendRoutes (routes, resolve) {
      routes.push({
        name: '404error',
        path: '*',
        component: resolve('~/pages/404.vue')
      })
    }
  }, 
  ...... 
}
  Nuxt.jsで404エラーページを作る方法について詳しくは過去記事でも紹介していますのでご参考にどうぞ。 (参考記事) ・Nuxt.jsで404エラーページのルーティングとテンプレートを作成する  
head要素のmetaタグ設定
静的サイトを作る上で重要なのが、ページごとの個別のmeta設定になります。Nuxt.jsではこの設定も自由にできる仕組みが用意されています。基本的にはデフォルトの設定はnuxt.config.jsの「head」オプションの「meta」キーにて、ページで個別の指定を行う場合には、ページテンプレート側で「headメソッド」を使って必要な設定を上書きするような形になります。 【nuxt.config.js】※一部抜粋
export default {
  ...... 
  meta: [
    { charset: 'utf-8' },
    { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' },
    { name: 'viewport', content: 'width=device-width, initial-scale=1' },
    { hid: 'robots', name: 'robots', content: 'index,follow,noodp' },
    ...... 
  ]
}
  ページテンプレート側で設定するmeta要素の指定は共通処理としてmixinなどで用意しておくと便利ですね。 【mixin/headMeta.js】
export default {
  head() {
    const head = { meta: [] }
    if (this.meta.title) {
      const title = this.meta.title
      head.title = title
      head.meta.push({ hid: 'og:title', property: 'og:title', content: title })
    }
    if (this.meta.description) {
      head.meta.push({ hid: 'description', name: 'description', content: this.meta.description })
      head.meta.push({ hid: 'og:description', property: 'og:description', content: this.meta.description })
    }
    if (this.meta.image) {
      head.meta.push({ hid: 'og:image', property: 'og:image', content: this.meta.image })
    }
    return head
  }
}
  こうすることでページテンプレート側での編集が容易になります。今回は動的なルーティングのページもあるので、固定値ではなくタイトルやOGPイメージなどAPI経由で取得したデータが入るようになる部分もあります。 【pages/index.vue】
<template>
  ...........
</template>

<script>
  import headMeta from '~/mixins/headMeta.js'
  ...........
  export default {
    ...........
    mixins: [headMeta],
    data() {
      return {
        meta: {
          title: 'ページ固有のタイトル',
          description: 'ページ固有のタイトル',
          ...........
        }
        ...........
      }
    },
    ...........
  } 
</script>
  head要素内のmeta設定については過去記事で詳しくまとめていますので、こちらも合わせてご参考ください。 (参考記事) ・Nuxt.jsでheadタグ内に含まれる各種メタタグの設定を行う  
パンくずリスト・JSON-LD構造化データへの対応
メディアサイトやブログサイトではSEO対策も重要になってきます。その際にはパンくずリストやJSON-LD構造化データの設定なども行なっておきたいですね。Nuxt.jsでは個別のコンポーネントや共通処理などで動的に処理していくことになります。パンくずリストの場合ですと下記のように専用のコンポーネントを作成し、ページコンポーネント側からパンくずリストの内容をpropsとして受け取りテンプレート上に展開していく形になります。 【components/BreadcrumbList.vue】
<template lang="pug">
  ul
    li(itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem")
      nuxt-link(to="/" itemprop="item")
        span(itemprop="name").
          HOME
        meta(itemprop="position" content="1")
        li(v-for="(page, index) in listData" :key="index" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem")
          nuxt-link(:to="page.path" itemprop="item")
            span(itemprop="name").
              {{ page.name }}
            meta(itemprop="position" :content="index + 2")
</template>

<script>
  export default {
    name: 'BreadcrumbList',
    props: {
      listData: {
        type: Array,
        default: () => []
      }
    }
  }
</script>
  ページテンプレート側ではパンくずリストをコンポーネントとして呼び出して、dataオプションの値でパンくずリストの内容を設定し、コンポーネントに渡してあげます。もしパンくずリスト以外のコンポーネントでも現在ページの情報を使いたい場合には、propsを使わずに、stateの値に格納する方法を採用すると良さそうですね。 【pages/index.vue】
<template lang="pug">
  div
    // ページコンテンツ
breadcrumb-list(:list-data="currentPage")
</template>

<script>
  import BreadcrumbList from '~/components/BreadcrumbList.vue'
  export default {
    components: {
      BreadcrumbList
    },
    data() {
      return {
        currentPage: [
          {
            path: '/example/',
            name: 'ページタイトル'
          }
        ]
      }
    },
  }
</script>
  JSON-LD構造化データの場合はheadタグ内にscriptを埋め込むことになるので、ページコンポーネント内にheadメソッドで直接指定する形になります。もし文字列としてinnerHTMLの値で指定する場合にはクオーテーションマークなどがエスケープされるので少し注意が必要です。 【pages/index.vue】※一部抜粋
head() {
  return {
    script: [
      {
        hid: 'ld-json',
        type: 'application/ld+json',
        json: {
          '@type': 'ListItem',
          'position',
          'item': {
            '@id': 'https://exmaple.com',
            'name': 'HOME'
          }
        }
      }
    ],
  }
}
  Nuxt.jsでパンくずリストやJSON-LD構造化データを設定する方法についても過去記事で詳しくまとめていますので、合わせてご参考ください。 (参考記事) ・Nuxt.jsでVue-metaを使ってhead要素へ動的にスクリプトを挿入する ・Nuxt.jsでSheme.orgに準拠したパンくずリストを作成する  
  今回はざっとではありますが、ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackのサイトを作るベースの部分をまとめてみました。これ以外にもいろんな処理や設定もありますが、また改めて別記事にてまとめていきたいと思います。次回は投稿一覧や投稿詳細ページなど動的なページを作成する流れについて引き続きまとめていきたいと思います。   (過去記事) ・ヘッドレスCMSのWordPressとNuxt.jsのSSGでJamstackなサイトを作成してみる #1:ヘッドレスCMSの構築
  • はてなブックマーク
  • Pocket
  • Linkedin
  • Feedly

この記事を書いた人

Twitter

sponserd

    keyword search

    recent posts

    • Twitter
    • Github
    contact usscroll to top
      • Facebook
      • Twitter
      • Github
      • Instagram