NextJSでNetlify CMSをローカルに構築してみる

# はじめに

興味本位でNetlifyCMSがどんなものなのか使ってみたかったので、NetlifyCMS with NextJSで構築してみました。

参考にした公式ドキュメント
https://www.netlifycms.org/docs/nextjs/

# プロジェクトディレクトリ作成
```bash
mkdir demo-cms
cd demo-cms
```

# 新規プロジェクトの初期化

```bash
yarn init -y
```

# 必須パッケージをインストール
```bash
yarn add react react-dom next
```

# Markdown形式のwebpackローダのインストール
```bash
yarn add --dev frontmatter-markdown-loader
```

# ページフォルダを作成、インデックスファイルを追加

```bash
mkdir pages
touch pages/index.js
```

# コンテンツ用フォルダを作成、コンテンツファイルを作成
```bash
mkdir content
touch content/home.md
```

# 静的なassetsを配置するフォルダを作成
```bash
mkdir public
```

# スクリプトを追加
```json:package.json
{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "export": "yarn run build && next export"
  }
}
```

# コンテンツ本文を追加

```md:content/home.md
---
title: Awesome kitties
date: 2019-03-17T19:31:20.591Z
cats:
  - description: 'Maru is a Scottish Fold from Japan, and he loves boxes.'
    name: Maru (まる)
  - description: Lil Bub is an American celebrity cat known for her unique appearance.
    name: Lil Bub
  - description: 'Grumpy cat is an American celebrity cat known for her grumpy appearance.'
    name: Grumpy cat (Tardar Sauce)
---
Welcome to my awesome page about cats of the internet.

This page is built with NextJS, and content is managed in Netlify CMS
```

# Markdownをロードする方法をwebpackに定義
```
touch next.config.js
```
```js:next.config.js
module.exports = {
    webpack: (cfg) => {
        cfg.module.rules.push(
            {
                test: /\.md$/,
                loader: 'frontmatter-markdown-loader',
                options: { mode: ['react-component'] }
            }
        )
        return cfg;
    }
}
```

# コンテンツの骨組みを定義する
```js:pages/index.js
import Head from "next/head"
import { Component } from 'react'
import { attributes, react as HomeContent } from '../content/home.md';

export default class Home extends Component {
  render() {
    let { title, cats } = attributes;
    return (
      <>
        <Head>
          <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
        </Head>
        <article>
          <h1>{title}</h1>
          <HomeContent />
          <ul>
            {cats.map((cat, k) => (
              <li key={k}>
                <h2>{cat.name}</h2>
                <p>{cat.description}</p>
              </li>
            ))}
          </ul>
        </article>
      </>
    )
  }
}
```

# コンテンツサイトの動作確認
```
yarn run dev
```

# 管理画面の作成

```bash
mkdir -p public/admin
```

# htmlの作成

```bash
touch public/admin/index.html
```

```html:public/admin/index.html
<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>content manager</title>
  <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
  <!-- include the script that builds the page and powers netlify cms -->
  <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
</body>
</html>
```
# yamlの作成

```bash
touch public/admin/config.yml
```

```yaml:public/admin/config.yml
backend:
# ローカルで検証する場合、`test-repo`を指定
#  name: git-gateway
  name: test-repo
  branch: master
media_folder: public/img
public_folder: img
collections:
  - name: "pages"
    label: "Pages"
    files:
    - label: "Home"
      name: "home"
      file: "content/home.md"
      fields:
        - { label: "Title", name: "title", widget: "string"}
        - { label: "Publish Date", name: "date", widget: "datetime" }
        - { label: "Body", name: "body", widget: "markdown"}
        - label: 'Cats'
          name: "cats"
          widget: list
          fields:
            - { label: "Name", name: "name", widget: "string"}
            - { label: "Description", name: "description", widget: "text"}
```

# Gitの管理対象外を定義

```bash
touch .gitignore
```

```:.gitignore
.next/
node_modules/
/npm-debug.log
.DS_Store
out/
```

# 管理画面にアクセス
http://localhost:3000/admin/index.html

Loginボタンを押して、こんな画面が表示されたら構築完了！

![スクリーンショット 2021-04-05 5.26.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288712/c8c75f28-3db6-05c5-1114-28efbd998433.png)

# トラブルシューティング
## Failed to import @babel/core or/and @babel/preset-react
```bash:実行コマンド／エラー
$ yarn run dev
~~省略~~
Error: Failed to import @babel/core or/and @babel/preset-react: 
If you intend to use 'react' mode, install both to your project: 
https://hmsk.github.io/frontmatter-markdown-loader/react.html
```

```bash:対処方法
yarn add --dev @babel/core @babel/preset-react @babel/preset-env
```

## Syntax error: Support for the experimental syntax 'jsx' isn't currently enabled 
```bash:実行コマンド／エラー
$ yarn run dev
~~省略~~
Syntax error: Support for the experimental syntax 'jsx' isn't currently enabled (9:7):
~~省略~~
Add @babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add @babel/plugin-syntax-jsx (https://git.io/vb4yA) to the 'plugins' section to enable parsing.
```

```bash:対処方法
touch .babelrc
# 下記を追記
{
    "presets": ["@babel/preset-react"],
    "plugins": [
        [
            "@babel/plugin-transform-react-jsx",
            {
                "runtime": "automatic"
            }
        ]
    ]
}
```