MicroCMSで取得したデータをGridSomeのGraphQLへインポートして表示する
この記事では、MicroCMSで取得した投稿データをGridSomeのGraphQLへインポートして、表示する方法を解説します。
1.MicroCMSの投稿データを取得
まずはgridsome.server.jsに以下のように投稿データを取得します。
[gridsome.server.js]
// MicroCMSのAPIキー
const API_KEY = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
const axios = require('axios');
// リスト形式の投稿タイプ用に付与するイテレーターの関数
const equipIterator = function(target) {
target[Symbol.iterator] = function() {
let i = 0;
return {
next() {
return target.length <= i ? { done: true } : { value: target[i++] };
}
}
}
return target;
}
// axisoで投稿データを取得する関数、何度も使うので関数化
const getMicroCMSPosts = (URL, API_KEY) => {
return axios.get(URL, { headers: { 'X-API-KEY': API_KEY } })
.then(res => {
equipIterator(res.data.contents) : false; // 投稿がリストタイプの時はイテレーターを付与して戻す
if(res.data.contents) {
return equipIterator(res.data.contents);
} else {
return res.data // 投稿がJSON形式の場合はそのまま戻す
}
})
.catch(err => { console.log(err) })
}
const homePosts = getMicroCMSPosts('https://your.microcms.io/api/v1/home', YOUR_API_KEY);
const worksPosts = getMicroCMSPosts('https://your.microcms.io/api/v1/blog', YOUR_API_KEY);
const aboutPosts = getMicroCMSPosts('https://your.microcms.io/api/v1/company', YOUR_API_KEY);
// URLにはあなたのMicroCMSのURLを入力してください2.取得した投稿データをGraphQLで使用できるようにする
次に、GridSomeのLoadSourceAPIを利用して、投稿データをGraphQLへインポートします。
[gridsome.server.js]
module.exports = function(api) {
// homeポストをGraphQLへインポート(JSON形式)
api.loadSource(async actions => {
let post = await homePosts;
const collection = actions.addCollection('Home');
collection.addNode({
id: post.id,
title: post.page_title,
date: post.updatedAt,
content: post.content,
introduce: post.introduce,
hero: post.hero,
carousel: post.carousel,
feature: post.feature
})
});
// WorksポストをGraphQLへインポート(リスト形式)
api.loadSource(async actions => {
let post = await worksPosts;
const collection = actions.addCollection('Works');
for (const item of post) {
collection.addNode({
id: item.id,
title: item.page_title,
slug: item.permalink,
date: item.updatedAt,
content: item.content,
path: item.permalink // 後のSetup templatesで使用するスキーマ
})
}
})
}collection.addNodeの中のitem.idのidの部分はMicroCMSのスキーマの部分です。
これでGraphQLが利用できるようになりました。
3.リスト形式のそれぞれの投稿データの個別ページを静的に書き出す設定を追加
リスト形式は、WordPressでいうPost type(投稿タイプ)のようなものなので、投稿記事それぞれの個別ページを用意する必要があります。記事数が10件程度であれば、手作業でページテンプレートを作成してもいいかもしれませんが、投稿ページをそういう使い方するケースはほとんどないでしょう。
なので、投稿記事が増えても減ってもメンテナンスフリーにするため、リスト形式の投稿データの数だけ、個別ページを静的に書き出す設定を追加します。
GridSomeのSetup Templates機能を利用して、gridsome.config.jsへ設定を追加します。
// リスト形式のWorksでの例
module.exports = {
siteName: 'サイトの名',
templates: {
Works: [
{
path: '/works/:path', //Worksの個別ページのそれぞれのURL。パラメータのpathはGraphQLのpathスキーマから
component: './src/templates/WorksPost.vue' // templateディレクトリのWorksPost.vueを使用(あとで作成)
}
]
}
}4.リスト形式の投稿を一覧表示するページを用意する。
ここではGraphQLへインポートしたリスト形式の投稿タイプを一覧表示するためのページを用意します。
この例ではworksという投稿タイプなので、pagesディレクトリ直下にWorks.vueというページを作成します。
[pages/Works.vue]
<template>
<Layout>
<article v-for="(item, key) in blog" :key="key">
<h2>{{ item.node.title }}</h2>
<time>{{ item.node.date }}</time>
<div>{{ rawcontent[key] }}</div>
<div><g-link :to="item.node.path">READ MORE</g-link></div>
</article>
</Layout>
</template>
<page-query>
query {
allWorks {
edges {
node {
id
title
slug
date (format: "YYYY年MM月DD日 HH:mm:ss")
content
path
}
}
}
}
</page-query>
<script>
import axios from 'axios'
export default {
data() {
return {
blog: null, // 投稿データをvue側で使用するため
rawcontent: []
}
},
metaInfo: {
title: '記事のタイトル',
},
methods: {
putData() {
this.blog = this.$page.allWorks.edges;
for(let item in this.blog) { // 記事の概要を表示させるため、投稿のHTMLタグを削除して、rawcontentへ格納
this.rawcontent.push(this.blog[item].node.content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g,''));
}
}
},
mounted() {
this.putData(); // GraphQLの投稿データをvueへマウント
}
}
</script>5.リスト形式の投稿の個別表示するためのテンプレートを作成する
3の手順でやった「リスト形式のそれぞれの投稿データの個別ページを静的に書き出す設定を追加」の表示側テンプレートを作成します。
以下の例ではtemplateディレクトリ直下にWorksPost.vueを作成しています。
[template/WorksPost.vue]
<template>
<Layout>
<article>
<h1>{{ $page.works.title }}</h1>
<time>{{ $page.works.date }}</time>
<div v-html="$page.works.content"></div>
</article>
<nav>
<!-- Pager Links -->
<ul>
<li v-for="(item, i) in allPagelinks" :key="i">
<g-link :to="item.path">
<span v-if="pagercondition.prev & i == 0 | !pagercondition.next & i == 0">Prev</span>
{{item.title}}
<span v-if="pagercondition.next & i == 1 | !pagercondition.prev & i == 0">Next</span>
</g-link>
</li>
</ul>
</nav>
</Layout>
</template>
<!-- IDが入ってるQueryが個別記事の現在表示中の投稿データ -->
<page-query>
query($id: ID!) {
works(id: $id) {
id
title
slug
date(format: "YYYY年MM月DD日 HH:mm:ss")
content
path
}
allWorks {
edges {
node {
id
title
slug
date(format: "YYYY年MM月DD日 HH:mm:ss")
path
}
}
}
}
</page-query>
<script>
export default {
data() {
return {
currentpage: null,
allpages: null,
otherpagelink: [],
pagercondition: {
prev: false,
next: false
},
rawcontent: null
}
},
metaInfo() {
return {
title: this.$page.works.title
}
},
computed: {
getNowPage() { // 現在のページを取得
return this.$page.works.path;
},
allPagelinks() { // Worksの全ての記事のリンクを取得し、現在表示中の記事以外のリンクを取得する。
this.otherpagelink = [];
let self = this;
let allpage = self.allpages;
let indexNum = [];
for (let items in allpage) {
indexNum.push(allpage[items].node.path)
// 表示中の記事が最初の記事の場合のリンクを取得
if(indexNum.indexOf(this.getNowPage) === 0) {
this.otherpagelink.push(allpage[1].node)
this.pagercondition.prev = false;
this.pagercondition.next = true;
return this.otherpagelink;
}
// 表示中の記事が最後の記事の場合のリンクを取得
if(indexNum.indexOf(this.getNowPage) === allpage.length -1) {
this.otherpagelink.push(allpage[items -1].node)
this.pagercondition.prev = true;
this.pagercondition.next = false;
return this.otherpagelink;
}
// 表示中の記事が最初でも最後でもない記事のリンクを取得
if(indexNum.indexOf(this.getNowPage) !== 0 && indexNum.indexOf(this.getNowPage) !== allpage.length -1 && indexNum.indexOf(this.getNowPage) !== -1) {
this.otherpagelink.push(allpage[indexNum.indexOf(this.getNowPage) -1].node);
this.otherpagelink.push(allpage[indexNum.indexOf(this.getNowPage) +1].node);
this.pagercondition.prev = true;
this.pagercondition.next = true;
// console.log("Middle link condition : ",this.otherpagelink)
return this.otherpagelink;
}
}
}
},
mounted() {
this.currentpage = '/works/' + this.$route.params.path + '/';
this.allpages = this.$page.allWorks.edges;
}
}
</script>6.GraphQLにインポートしたJSON形式の投稿データを表示するページを作成する
ここでは、2の手順の「取得した投稿データをGraphQLで使用できるようにする」のJSON形式の投稿データを表示するためのページを作成します。
例ではhomeポストの投稿データを表示するため、pagesディレクトリ直下にIndex.vueを作成しています。
[pages/Index.vue]
<template>
<Layout>
<div class="hero">
<!-- Vue Carouselプラグインを使用しています -->
<ClientOnly>
<carousel :per-page="1" :mouse-drag="false" :autoplay="true">
<slide v-for="(item, key) in carousel" :key="key">
<img :src="item.carousel.url" />
</slide>
</carousel>
</ClientOnly>
<h1>{{ title }}</h1>
</div>
<section>
<ul>
<li v-for="(item, key) in feature" :key="key">
<div>
<img :src="item.feature_image.url" :alt="item.feature_title">
</div>
<div>
<h3>{{ item.feature_title }}</h3>
<p>{{ item.feature_content }}</p>
</div>
</li>
</ul>
</section>
</Layout>
</template>
<!-- carouselスキーマはMicroCMS側で複数コンテンツ参照を利用。配列形式で取得される点にご注意 -->
<page-query>
query {
allHome {
edges {
node {
id
title
date
introduce {
intro_title
intro_content
intro_image {
url
}
}
hero {
url
}
carousel {
id
carousel {
url
}
}
feature {
feature_title
feature_image {
url
}
feature_content
}
}
}
}
}
</page-query>
<script>
export default {
data() { // Vue側でGraphQLの投稿データを利用する
return {
title: null,
date: null,
introduce: {
intro_title: null,
intro_content: null,
intro_image: {
url: null
}
},
hero: {
url: null
},
carousel: [{
id: null,
carousel: {
url: null
}
}],
feature: [{
feature_title: null,
feature_image: {
url: null
},
feature_content: null
}]
}
},
components: {
// CarouselはNetlifyでサーバーサイドレンダリングできないため、その対策
Carousel: () =>
import('vue-carousel')
.then(m => m.Carousel)
.catch(),
Slide: () =>
import('vue-carousel')
.then(m => m.Slide)
.catch()
},
metaInfo: {
title: 'microCMSをGridSomeで構築してNetlifyで公開するための検証サイト'
},
methods: {
putData() {
this.title = this.$page.allHome.edges[0].node.title;
this.date = this.$page.allHome.edges[0].node.date
this.hero.url = this.$page.allHome.edges[0].node.hero.url
this.carousel = this.$page.allHome.edges[0].node.carousel
this.feature = this.$page.allHome.edges[0].node.feature
this.introduce = this.$page.allHome.edges[0].node.introduce
}
},
mounted() {
this.putData();
}
}
</script>※この手順で使用している「カルーセルスライダーは」vue-carouselをインストールする必要があります。
$ npm i --save-dev vue-carousel終わりに
以上になります。
何か抜けている部分があるかもしれません。
その場合はGithubのソースコードをご覧いただくか、
コチラまでおしらせください。
