【Vue版Gatsby】Gridosomeで自作ブログ作ってみた~プロジェクト作成からブログの表示まで~

パーソンリンクアドベントカレンダー19日の記事です！
自作ブログ作成に挑戦しました！

# Gridsomeってなに？
GridsomeはVue.jsで書けるJAMStackフレームワーク
Vueで書けるJAMStackフレームワークとしては他にも、NuxtとかVuePressとかあります。
[JAMStack公式ページ](https://gridsome.org/)に色々紹介されているのでそちらを御覧いただけるといいんじゃないかなって思います。
そもそもJAMStackがわからないっていう方は[こちらの](https://qiita.com/ozaki25/items/4075d03278d1fb51cc37)サイトをみていただけるといいんじゃないかなあと思います。


# Gridsomeって何がいいの？
- Vueでマークダウンでブログとかかける
- Vueのプラグインが使える
- GraphQLのちょっとした勉強にもなる
- パフォーマンスの向上
- より高いセキュリティ
- 高速
- [JAMStackの公式ページ](https://jamstack.org/why-jamstack/)に他にもメリットがたくさん書かれていますのでみてみてください

# Gridsomeをはじめよう

### GridsomeCLIのインストール

```
YARNの使用：yarn global add @gridsome/cli
NPMの使用：npm install --global @gridsome/cli
```

### Gridsomeプロジェクトを作成します

```
gridsome create my-gridsome-site
  新しいプロジェクトを作成するには
cd my-gridsome-site 
  フォルダを開く
gridsome develop 
  ローカル開発サーバーを起動するには http://localhost:8080
  ハッピーコーディング🎉🙌
```

インストールが完了してローカルホストにアクセスすると下記のような画面になっていたらひとまずOKです。
![スクリーンショット 2020-12-08 10.58.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/f4fd8b00-ef4c-0b78-4fd5-8ca60131210d.png)


しかし、このままではマークダウンで記事かけません。
そこでマークダウンで記事をかけるようにしてくれるプラグインをインストールします。

```
yarn add @gridsome/source-filesystem
npm install @gridsome/source-filesystem

yarn add @gridsome/transformer-remark
npm install @gridsome/transformer-remark

npm install @gridsome/remark-prismjs
yarn add @gridsome/remark-prismjs
```

インストールをしたら`gridsome.config.js`と`main.js`を編集しないといけません。

```javascript:gridsome.config.js

module.exports = {
  siteName: 'Gridsome',
  templates: {
    Post: '/blog/:path'
  },
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Post',
        path: 'content/**/*.md'
      }
    }
  ],
  transformers: {
    //Add markdown support to all file-system sources
    remark: {
      externalLinksTarget: '_blank',
      externalLinksRel: ['nofollow', 'noopener', 'noreferrer'],
      plugins: [
        '@gridsome/remark-prismjs'
      ]
    }
  },
}
```

```javascript:main.js

import DefaultLayout from '~/layouts/Default.vue'
import 'prismjs/themes/prism.css'


export default function (Vue, { router, head, isClient }) {
  head.link.push({
    rel: 'stylesheet',
    href: 'https://fonts.googleapis.com/css?family=Stylish&display=swap'
  }),
  // Set default layout as a global component
  Vue.component('Layout', DefaultLayout)
}
```

2つのファイルを編集したらCtrl + C押して再起動してください。

# 各ファイルの紹介
ここまでで最低限ブログを書く準備はできました。お疲れさまでした。
次に各ファイルの使い方を説明したいと思います。

```
.
├── gridsome.config.js
├── gridsome.server.js
├── static/
├── content/
├── package-lock.json
├── package.json
├── src
│   ├── components
│   │   └── README.md
│   ├── favicon.png
│   ├── layouts
│   │   ├── Default.vue
│   │   └── README.md
│   ├── main.js
│   ├── pages
│   │   ├── About.vue
│   │   ├── Index.vue
│   │   └── README.md
│   └── templates
│       └── README.md
└── static
    └── README.md
```

こんな感じでgridsomeプロジェクトにいろんなファイルがあると思います。ご紹介します。
### /src/components
おなじみのコンポーネントを作成するフォルダ
コンポーネントについては解説しないのでわからない方は調べてください

### /src/layouts/Default.vue
ここでページのヘッダーやフッターを作成できます。

```html
<template>
  <div class="layout">
    <header class="header">
      <strong>
        <g-link to="/">{{ $static.metadata.siteName }}</g-link>
      </strong>
      <nav class="nav">
        <g-link class="nav__link" to="/">Home</g-link>
        <g-link class="nav__link" to="/about/">About</g-link>
      </nav>
    </header>
    <slot/>
  </div>
</template>
```
このコンポーネントの`<slot>`の部分にページのコンテンツが挿入されます。

### src/pages/**.vue
このディレクトリのファイル名がルーティングに使用されます。
例えば`About.vue`というファイルを作成したら`localhost:8080/about`にアクセスできるようになります。
これはブログのジャンル毎の記事に分けたい時とかに使えます。

### src/pages/templates/*.vue
ここには、先程の`sorce-filesystem`を入れたときに`gridsome.config.js`に記述した`typeName`と同じファイル名を作成する必要があります。
`typeName`に`Post`と記述したら`Post.vue`と命名する必要があります。
後にGraphQLからブログのデータを取得するためです。

# ブログを作成する
次にブログを作成して画面に表示させるところまでをやってみます。
`/content/my_blog/helloworld.md`を作成してください。

```:helloworld.md

---
title: HelloWorld!
description: FirstArticle
date: 2020-12-9
path: first
---

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Pariatur excepturi labore tempore expedita, et iste tenetur suscipit explicabo! Dolores, aperiam non officia eos quod asperiores

```

こんな感じで書いてみました。適宜内容変えて書いてみてください。

# ブログで書いた内容を取得する

```
http://localhost:8080/___explore
```
こちらを開いてみてください。GraphQLを試すことができます。
![スクリーンショット 2020-12-14 10.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/0a16e86c-0a91-c835-27ac-d0446ec29ddb.png)

こんな感じの画面が出てくるはずです。



先程試しに書いてみた記事の内容を取得してみます。

```graphql
query {
  allPost {
    edges {
      node {
        title
        description
        date
        path
        content
      }
    }
  }
}
```

上記を先程の画面にコピペしてみてください。

![スクリーンショット 2020-12-14 10.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/a29190b7-e259-db8a-a03f-5f92ccba75f3.png)


先程サンプルで書いたデータが返ってくるはずです。
この内容を`src/pages/index.vue`で取得してみたいと思います。
ファイルを下記のように編集してみてください。

```html:/src/pages/index.vue

<template>
  <Layout>
    <hr>
    <div v-for="(article, index) in $page.allPost.edges" :key="index">
      <p>タイトル：{{article.node.title}}</p>
      <p>サブタイトル：{{article.node.description}}</p>
      <p>日付：{{article.node.date}}</p>
      記事の内容
      <p v-html="article.node.content"></p>
      <g-link :to="article.node.path">記事のリンクに移動</g-link>
    </div>
  </Layout>
</template>

<page-query>
query {
  metadata {
    siteName
  }
  allPost {
    edges {
      node {
        id
        title
        content
        description
        date
        path
      }
    }
  }
}
</page-query>

<script>
export default {
  metaInfo: {
    title: 'Hello, world!'
  }
}
</script>

</page-query>
```

![スクリーンショット 2020-12-15 10.08.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/f0680ca1-8fb0-8149-3852-0566147a0fc6.png)


index.vueで記事のデータを全件取得してそれぞれ内容を表示させています
`<g-link>`というのはGridsomeが用意したGridsome内で使える`vue-router`のようなものです。基本これを使ってページ遷移をさせます。

しかし、現段階では記事でのデータを個別取得するように取得していないので記事のリンクに移動しても何も表示されていないかと思います。

### 記事の個別取得
記事の個別取得はGraphQLと紐付いたファイル名でないと出来ません。
`gridsome.config.js`の`source-filesystem`の箇所を見てみてください。

```
plugins: [
 {
    use: '@gridsome/source-filesystem',
    options: {
      typeName: 'Post',
      path: 'content/**/*.md'
    }
  }
],
```

ここの`typeName`と同じファイル名のものを`/src/templates`内に作成することで記事の個別のデータを取得することが出来ます。
自分の環境では、`typeName`が`Post`とあるので`Post.vue`というファイルを作成します。

```html:/src/templates/Post.vue

<template>
  <div>
    <Layout>
      <br>
      <h1>{{ $page.post.title }}</h1>
      <p v-html="$page.post.content"></p>
    </Layout>
  </div>
</template>

<script>
export default {
  
}
</script>

<page-query>
query Post  ($id: ID!) {
  post (id: $id) {
    title
    content
    date
    description
  }
}
</page-query>
```

作成したら上記のように編集してみてください。
編集したら先程の`index`のページのリンクから飛んでみてください。

リンクから飛んだらURLを確認してみてください。
実際に書いてあるブログの記事の`path`と同じになっていることを確認してください。

![スクリーンショット 2020-12-15 10.21.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518141/6a8a34e2-4560-2532-0834-cfc02dff4ceb.png)

実際に個別にデータが取得できていることが確認できました。
`g-link`からページ遷移した後、ブログのIDが渡され、GraphQLで一致するブログのデータを取得しているんじゃないかなと予想しています。

以上が、ブログを作成して表示するまでの一連の流れとなります。
お疲れさまでした。

# 便利なプラグインの紹介

### Vuetify
僕はCSSが嫌いです。極力書きたくありません。。
そんなときに便利なのがVuetifyとかBootstrapとかです。
今回自分はVuetifyを採用しました。

インストールとセットアップにあたってこちらの記事を参考にしましたので。[こちら](https://qiita.com/0622okakyo/items/4e5d4a4d29e4cd2b1576)の記事を参考にインストールしてみてください。
本記事では長くなるので割愛させていただきます。スミマセン。

### typescript 
正直ページネーション機能を実装する時くらいしか使っていません。
公式ページにtypescriptを導入するためのプラグインの紹介がされているのでそこを参考にしました。

```
yarn add -D typescript ts-loader gridsome-plugin-typescript

npm install -D typescript ts-loader gridsome-plugin-typescript
```

続いて`gridsome.config.js`を編集

```/gridsome.config.js
module.exports = {
  plugins: [
    {
      use: 'gridsome-plugin-typescript',
    }
  ]
}
```

ルートディレクトリに`tsconfig.json`を作成します。

```/tsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "es2015",
        "moduleResolution": "node",
        "noImplicitReturns": true,
        "outDir": "./built/",
        "sourceMap": true,
        "strict": true
    },
    "include": [
        "./src/**/*"
    ]
}
```

続いてsrcディレクトリ内に`vue-shims.d.ts`を作成します。

```/src/vue-shims.d.ts
declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}
```

あとは個々のvueファイル内のスクリプトタグにtsをつければ完了です
`<script lang="ts">`

### netlifycms
これはnetlifyにブログをデプロイしたら使えるようになるやつです。
ブログデプロイ後`サイトURL/admin`にアクセスすると自分のブログ上でブログが書ける様になるすごいやつです。
これは後日、自作ブログデプロイ編(書く気が起きれば)でご紹介したいと思います。

# 最後に
今回JAMStackフレームワークに触ってみたくてNuxtかGridsomeかで迷った末、Gridsomeを選択しました。Nuxtよりも知名度低かったので。。
デプロイするまでにかなりハマってしまいましたが、いい勉強になったと思います。
自分が作成したブログをデプロイして[PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/?hl=ja)で計測したところ８２点だったので１００点目指して、いつかサイトを軽量化に挑戦してみようと思いました。