nuxt/contentでサクッとブログを作る

6 min read読了の目安(約5900字 2

一部表示が崩れてしまっているところがあります。TailwindCSSの部分のみなので各自修正をお願いします。
動作には問題ないと思うのでCSSをそのまま書いている方には問題ありません。

2020/11 から始まった、ものづくりをする高校生のための新しい団体、Palettteが主催する Palettte Advent Calendar 2020 の2日目の記事です。

最近はデザインばかりでめっきりコードに触れていないのでほぼマークアップだけで作れるnuxt/contentを使ってブログを作る話をします。
スタイリングはSCSSとTailwindCSSで行います。

試験期間中に書いているのでほぼコード乗っけただけになっているのは許してください...。
(すでにスマホ表示が崩れているのを確認しました、後ほど直します)

プロジェクトの作成

とりあえずyarnでnuxtのプロジェクトを作成します。

yarn create nuxt-app プロジェクト名

何を使うかを聞かれるので

JavaScript, Yarn, TailwindCSS, Content(nuxt/content), Universal, Staticを選択します。途中LinterやTestについて聞かれますがここはお好きなように選択してもらって構いません。

プロジェクトの作成が完了したら、フォルダを開きます。

SCSSの設定

スタイルはSCSSで記述したいのでscssを追加しておきます。

yarn add -D node-sass sass-loader

GitHubにプッシュ

このタイミングで後ほどVercelでホスティングするためにGitHubにソースコードを載せておきましょう。

console
git add -A
git commit -m "first commit"
git remote add origin https://github.com/...
git push origin master

デフォルトスタイルの削除

現在だとデフォルトのページやスタイルが残ってしまっているので削除します。

  • /layouts/default.vue
  • /pages/index.vue
  • /components/Logo.vue

からスタイルとデフォルトのHTMLを削除しておきます。

記事カードの作成

まずはトップページにあたる記事一覧ページを作成するため、一つ一つの記事のカードとして /components/Card.vue を作成します。

カテゴリータグの作成

カードにカテゴリーを表示するタグをつけたいのでタグ用のコンポーネントも作成しておきましょう。

/components/Tag.vue
<template>
  <div class="tag bg-red-500 rounded-sm px-2 text-sm inline-block font-bold text-white">
    <slot>Uncategorized</slot>
  </div>
</template>

<script>
export default {
}
</script>

<style>

</style>

記事カード

タグが完成したのでカードを作っていきます。

/components/Card.vue
<template>
  <nuxt-link :to="slug">
    <article class="border p-4 rounded my-4">
    <h2 class="text-xl font-bold">{{ title }}</h2>
    <time class="text-right text-sm text-gray-700">{{ date }}</time>
    <div class="tags"><Tag>{{ category }}</Tag></div>
  </article>
  </nuxt-link>
</template>

<script>
import Tag from '~/components/Tag'

export default {
  props: {
    title: String,
    date: String,
    category: String,
    slug: String
  }
}
</script>

<style>

</style>

記事一覧ページの作成

次に、 /pages/index.vue に上で作成したコンポーネントを使用して記事一覧を作成していきます。

/pages/index.vue
<template>
  <div class="container mx-auto my-8">
    <Card v-for="(article, index) in articles" :key="index" :title="article.title" :date="article.date" :category="article.category" :slug="article.slug" />
  </div>
</template>

<script>
import Card from '~/components/Card'

export default {
  async asyncData({ $content }) {
    const query = await $content('blog').limit(15)
    const articles = await query.fetch()
    return { articles }
  }
}
</script>

ここまでで一旦動かしてみましょう。 yarn dev で開発サーバーを起動し、 http://localhost:3000 にアクセスします。

表示の確認用に、 /content/blog/hello.md を作成し以下のように適当なデータを入力しておきましょう。

---
title: nuxt/contentでサクッとブログを作る
date: 2020.11.30
category: dev
---

# Hello

このように表示されていればOKです。

記事詳細ページの作成

一覧ページが完成したら、今度は一つ一つの記事の詳細ページを作ります。
/pages/_slug.vue を作成してください。

/pages/_slug.vue
<template>
  <article class="container mx-auto my-8 px-20 md:px-0">
    <h1 class="text-center text-3xl font-bold my-8">{{ article.title || '' }}</h1>
    <div class="content bg-white rounded">
      <nuxt-content :document="article" />
    </div>
  </article>
</template>

<script>
export default {
  async asyncData({ $content, params }) {
    const query = $content('blog', params.slug)
    const article = await query.fetch()
    return { article }
  }
}
</script>

<style lang="scss">
.nuxt-content {
  h1 {
    margin: 48px 0px 28px;
    font-size: 1.6rem;
    font-weight: bold;
    padding: 8px 12px 8px 16px;
    border-left: 6px solid rgb(59, 130, 246);
    background: #f2f2f2;
  }

  h2 {
    border-left: 6px solid rgb(59, 130, 246);
    padding: 8px 12px 8px 16px;
    margin: 28px 0px 16px;
    font-size: 1.2rem;
    font-weight: bold;
  }

  h3 {
    font-size: 1.1rem;
    font-weight: bold;
  }

  h4, h5, h6 {
    font-weight: bold;
  }

  strong {
    font-weight: bold;
  }

  em {

  }

  a {
    color: rgb(59, 130, 246);
    text-decoration: underline;
  }

  p {
    margin: 20px 0 10px;
  }

  code {

  }

  pre code {

  }
}
</style>

これで記事一覧ページ、詳細ページが完成しました。
このままだと詳細ページからトップページに戻る方法がないのでヘッダーを作成しましょう。

ヘッダーの作成

/components/Header.vue
<template>
  <header class="bg-white py-4 px-4 md:px-20">
    <div class="inner flex justify-between mx-auto">
      <nuxt-link to="/"><div class="logo">Blog</div></nuxt-link>
      <nav>リンクとか</nav>
    </div>
  </header>
</template>

<script>
export default {

}
</script>

<style>

</style>

ヘッダーが完成したら、 /layouts/default.vue を編集し、全てのページにヘッダーを付けるようにします。

/layouts/default.vue
<template>
  <div>
    <Header />
    <Nuxt />
  </div>
</template>

<style>
html {
  font-family:
    'Source Sans Pro',
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    'Helvetica Neue',
    Arial,
    sans-serif;
  font-size: 16px;
  word-spacing: 1px;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
}
</style>

Vercelで公開

もうほとんど完成です。Vercelを設定して実際にサイトを公開してみましょう。

Vercelにアクセスし、 "Import Project" をクリックしましょう。

最初に作成したGitHubのリポジドリのURLを入力してください。

build commandnuxt generateに変更しましょう。
設定が完了したら"Deploy"を押して完成です。

おわり

一時間もかからずに一応動くものが作れました。
もう少し時間があればCloudinaryでOGP生成、MicroCMSで記事投稿などできるようにしたかったです。また時間のあるときに。

初心者なのでなにかより良い方法等ございましたら教えていただけると幸いです。