【Nuxt.js + Prismic.io】第3回 簡単なサイトを作ってみよう

  • NuxtJS
  • Prismic

はじめに

第2回の記事がありますので、まだ読まれていない方はご覧ください。

今回はプロジェクトの用意になりますが、ファイル1つ1つについて書くとあまりに長くなるため、要点だけかいつまんでまとめようと思います。

前準備

プロジェクトのリポジトリ

クローン等してダウンロードしてください。

👉 https://github.com/nemuvski/nuxtjs-prismic-starter

その後、README.mdセットアップにある内容を実施してください。

インストールと開発サーバー起動

# Node.jsのv12系での実行を推奨
npm install
# localhost:3000で起動
npm run dev

http://localhost:3000にアクセスすると、ページが表示されると思います。下のキャプチャ画像は、記事を何件か登録したパターンを示しています。

最低限のことしかしていないので作りは簡素ですが、これをベースに自分で作り込んでいけるような想定で作っています。

@nuxtjs/prismic

基本的には@nuxtjs/prismicを利用して開発を行います。必要な設定がありますので、それについて記述したいと思います。

nuxt.config.js

APIのエンドポイントやあとで説明するLink Resolverの処理が記述されたファイルの在処を記述します。

export default {
  modules: ['@nuxtjs/prismic'],
  prismic: {
    endpoint: 'https://repository-name.cdn.prismic.io/api/v2',
    linkResolver: '@/plugins/link-resolver',
    htmlSerializer: '@/plugins/html-serializer',
  },
}

link-resolver.js

ディレクトリ内のplugins/link-resolver.jsをご覧ください。

記事のリンクフィールドとリッチテキストフィールドに、Prismicリポジトリ内の記事(つまり、CMSで作成した記事)へのリンクが含まれる場合があります。その記事への適切なパスを解決するためにLink Resolverを定義する必要があります。

例えば、「Pageというカスタムタイプのページのパスは/page/{uid}」と定義する場合は次のようになります。

// 引数doc : ドキュメントオブジェクト
// REF: https://prismic.io/docs/vuejs/beyond-the-api/link-resolving
export default function (doc) {
  if (doc.type === 'page') {
    return '/page/' + doc.uid
  }
  return '/'
}

html-serializer.js

ディレクトリ内のplugins/html-serializer.jsをご覧ください。

記事のリッチテキストフィールドのHTML出力をカスタマイズするためのものです。特定の要素にクラスやタグを追加したり、タグの構成をカスタマイズすることができます。

HTML Serializer for Rich Text fieldsにあるコードを利用すれば良いのですが、一部問題がありIssueで報告されており、書き換えてVueファイルの方で処理を追記する必要があります。リポジトリ内に用意したものは問題を考慮して改善したものです。(下に示すコード中のNoteのコメント部分が該当します)

import linkResolver from "./link-resolver"
import prismicDOM from 'prismic-dom'
const Elements = prismicDOM.RichText.Elements

export default function (type, element, content, children) {
  if (type === Elements.hyperlink) {
    let result = ''
    const url = prismicDOM.Link.url(element.data, linkResolver)
    if (element.data.link_type === 'Document') {
      // Note: https://github.com/nuxt-community/prismic-module/issues/60
      result = `<a data-nuxt-link href="${url}">${content}</a>`
    } else {
      const target = element.data.target ? `target="'${element.data.target}'" rel="noopener"` : ''
      result = `<a href="${url}" ${target}>${content}</a>`
    }
    return result
  }

  if (type === Elements.image) {
    let result = `<img src="${element.url}" alt="${element.alt || ''}" copyright="${element.copyright || ''}">`
    if (element.linkTo) {
      const url = prismicDOM.Link.url(element.linkTo, linkResolver)
      if (element.linkTo.link_type === 'Document') {
        // Note: https://github.com/nuxt-community/prismic-module/issues/60
        result = `<a data-nuxt-link href="${url}">${content}</a>`
      } else {
        const target = element.linkTo.target ? `target="${element.linkTo.target}" rel="noopener"` : ''
        result = `<a href="${url}" ${target}>${result}</a>`
      }
    }
    const wrapperClassList = [element.label || '', 'block-img']
    result = `<p class="${wrapperClassList.join(' ')}">${result}</p>`
    return result
  }

  return null
}

問題点 : サイト内部リンクの場合はNuxtLinkコンポーネントを使えばよいのですが、処理中でアンカータグ<a>への変換がされないため、<nuxt-link>のままブラウザ上で表示されてしまいます。このままではブラウザはリンクであると判断されずにレンダリングされるため、リンクで表示されません。

対策 : サイト内部リンクの場合は、アンカータグに属性値を付与して区別できるようにします。そして、Vueファイルの方でリンクをクリックした時にrouter.pushでページ遷移させるようにイベントを仕込めばよいです。 ディレクトリ内のpages/page/_uid.vueにあるaddRouterPushEvents()をご覧ください。

また、以前投稿した特定のアンカータグの遷移処理をrouter.pushでさせたいをご覧ください。

記事データの取得

pages/index.vueに、複数の記事データを取得する処理が書いてあります。「こんな感じで条件を定義して、データ取得するんだなぁ」と大まかに理解いただければよいです。だいたい構文は記述した通りです。細かいフィルター条件や並び順の定義は、公式のドキュメントが充実しているので、本格的に開発されたい方はぜひご覧ください。

📖 How to Query the API with Vue.js - Prismic

export default {
  async asyncData({ $prismic, error }) {
    // カスタムタイプpageの記事が対象
    const query = $prismic.predicates.at('document.type', 'page')
    // 取得する記事の順番基準 , 取得する件数を設定
    const queryOptions = {
      // 初回公開日時について降順
      orderings: '[document.first_publication_date desc]',
      // 取得する記事数の上限
      pageSize: 20,
    }

    try {
      const content = await $prismic.api.query(query, queryOptions)
      return {
        posts: content.results
      }
    } catch(e) {
      error({ statusCode: 404 })
    }
  },
}

pages/page/_uid.vueに、記事のユニークID(uid)で目的の記事データを取得する処理が書いてあります。

export default {
  async asyncData({ $prismic, params, error }) {
    // /page/{_uid} → params.uidでパス中のパラメータを取得
    try {
      const content = await $prismic.api.getByUID('page', params.uid)
      return {
        // レスポンスデータのタイトルフィールドの内容をテキストへ変換
        title: $prismic.asText(content.data.title),
        publicationDate: {
          first: content.first_publication_date,
          last: content.last_publication_date,
        },
        body: content.data.body,
      }
    } catch(e) {
      error({ statusCode: 404 })
    }
  },
}

レスポンスデータの構成がどうなっているか気になる方はconsole.log()やブラウザの開発者ツールで内容を確認してみてください。

または公式のドキュメントをご覧ください。

📖 The Response Object in Javascript - Prismic

さいごに

Nuxt.jsとPrimic.ioで簡単なサイトを作るテーマで3回に分けて記事にしてきました。

手本となる資料が数少なかった(英語は公式のドキュメントを含めてちらほらありますが、日本語が皆無😭)ので、自分も本サイトを構築するときはいろいろ迷いながらでした。試行錯誤しつつ2回ぐらいはまっさらな状態から作り直しました。😅

これからPrismic使ってみようと思われている方のご参考になれば幸いです。

また何かPrismicのネタがありましたら、投稿していこうと思います!

この記事を共有

アバター

K.Utsunomiya
男・20代
主にWebフロントエンド技術と気になった音楽について投稿していきます。
最近ハマっていることは、クロスバイクで走ることとジムでの運動です。
詳しいプロフィール

© 2020–2021 コレ棚