NewtとNuxt3を利用してブログを作成する

最終更新日:

Table of contents

このチュートリアルでは、Newtと Nuxt3 を利用して、ブログを作成する手順を紹介します。
具体的には、Newtで管理しているコンテンツの一覧ページと詳細ページを作る手順を紹介した後、Vercel にデプロイして、静的生成(SSG)でページを表示します。

記事内で使用している主なソフトウェアのバージョン

  • Nuxt(nuxt): 3.10.3
  • newt-client-js(newt-client-js): 3.3.0

概要

Nuxt3でプロジェクトを作成し、Newtのコンテンツ情報を取得できるようにします。
コンテンツの一覧ページ(パス: /)と詳細ページ(パス: /articles/:slug 。slugがarticle-1の場合は /articles/article-1)を作成し、ローカル環境で表示できるようにします。
続いて、Vercelにデプロイし、静的生成でページを表示します。

1. Nuxt3のセットアップ

1-1. プロジェクトの作成

はじめに、Nuxt3のセットアップを行います。以下のコマンドでプロジェクトを作成します。
<project-name> には好きな名前を入力しましょう。ここでは nuxt3-blog という名前で作成します。

npx nuxi init <project-name>

コマンドを入力すると、以下の質問を聞かれるので、お好きな設定を選びましょう。

  • どのパッケージマネージャーを利用するか(ここでは yarn を選択)
  • gitリポジトリを初期化するか?(ここでは Yes を選択)

以下のように表示されます。

$ npx nuxi init nuxt3-blog
Need to install the following packages:
nuxi@3.10.1
Ok to proceed? (y)

✔ Which package manager would you like to use?
yarn
◐ Installing dependencies...
yarn install v1.22.22
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
warning vscode-languageclient@7.0.0: The engine "vscode" appears to be invalid.
[3/4] 🔗  Linking dependencies...
warning "nuxt > @nuxt/devtools@1.0.8" has unmet peer dependency "vite@*".
warning "nuxt > @nuxt/devtools > vite-plugin-inspect@0.8.3" has unmet peer dependency "vite@^3.1.0 || ^4.0.0 || ^5.0.0-0".
warning "nuxt > @nuxt/devtools > vite-plugin-vue-inspector@4.0.2" has unmet peer dependency "vite@^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0".
warning "nuxt > @nuxt/devtools > @nuxt/devtools-kit@1.0.8" has unmet peer dependency "vite@*".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
$ nuxt prepare
✔ Types generated in .nuxt
✨  Done in 13.21s.
✔ Installation completed.

✔ Initialize git repository?
Yes
ℹ Initializing git repository...

Initialized empty Git repository in /Users/foo/bar/nuxt3-blog/.git/
✨ Nuxt project has been created with the v3 template. Next steps:
 › cd nuxt3-blog
 › Start development server with yarn run dev

作成したプロジェクトに移動して、開発サーバーを立ち上げます。
yarnを利用する場合は以下のようになります。

$ cd nuxt3-blog
$ yarn dev

http://localhost:3000 にアクセスして、以下のような画面が表示されることを確認します。
nuxt3-blog1.png

1-2. TypeScriptの設定

開発環境でも型のチェックを行うために、以下の設定を行います。
※ 開発環境で型のチェックを行わない場合は、1-2のステップを飛ばして構いません。

まず vue-tsctypescript をdevDependenciesとしてインストールします。

yarn add -D vue-tsc@^1 typescript
最新のvue-tscでは型チェックの際に問題が発生する可能性があるため、ここではvue-tscのv1を利用しています。詳細については、Nuxtの TypeScript のドキュメントをご確認ください。

さらに、nuxt.config.ts ファイルで typescript.strict オプションと typescript.typeCheck オプションを有効にします。

nuxt.config.ts
export default defineNuxtConfig({
  devtools: { enabled: true }
  devtools: { enabled: true },
  typescript: {
    strict: true,
    typeCheck: true
  }
})

これで開発環境でも型のチェックができるようになりました。
TypeScriptの設定について、詳細はNuxtの TypeScript のドキュメントをご確認ください。

2. Newtのセットアップ

次にNewtにコンテンツとAPIトークンを用意し、コンテンツの取得を行うための準備を行います。

2-1. Appを追加する

「Appを追加」をクリックして「テンプレートから追加」を選択します。

Appを追加する

表示されるテンプレートの中から「Blog」を選択して、「このテンプレートを追加」をクリックします。
Appテンプレート

テンプレートが追加されると、「投稿データ」「タグデータ」「著者データ」が追加されます。

quick-start03.jpg

2-2. スペースUID・App UID・モデルUIDを確認する

スペースUIDは「スペース設定」から確認できます。

quick-start0402.jpg
quick-start0503.jpg

上記の例だと、スペースUIDは sample-for-docs となります。
この値は3-1で環境変数として定義します。

また「Blog」テンプレートを追加した場合、App UIDは blog、「投稿データ」モデルUIDは article となります。
これらの値は、4-4や5-1で投稿情報を取得する際に利用します。

2-3. Newt CDN API Tokenを作成する

続いて、APIリクエストに必要なトークンを発行します。
スペース設定 > APIキー のページからNewt CDN API Tokenを作成します。

quick-start06.jpg

名前と取得対象を決めて「作成」を押します。

quick-start07.jpg

ここで作成したトークンの値は3-1で環境変数として定義します。

3. リクエストの準備

Newtの SDK を利用することで、NewtのAPIをより簡単に利用できます。
ここではSDKを利用して、NewtのAPIクライアントを作成します。

3-1. 環境変数の設定

Nuxtの Runtime Config を利用して、環境変数を利用できるようにします。
まず、.env ファイルを作成し、2-2で確認したスペースUID、2-3で作成したトークンの値を定義します。以下を、実際の値で置き換えて定義してください。

.env
1NUXT_NEWT_SPACE_UID=sample-for-docs
2NUXT_NEWT_CDN_API_TOKEN=xxxxxxxxxxxxxxx

あわせて、nuxt.config.ts に以下のように runtimeConfig の設定を追加します。

nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    newt: {
      spaceUid: '',
      cdnApiToken: ''
    }
  },
  devtools: { enabled: true },
  typescript: {
    strict: true,
    typeCheck: true
  }
})

Runtime Confingは実行時にマッチする環境変数に自動的に置き換えられるため、上記のように定義しておくと、runtimeConfig.newt.spaceUid の値は .env ファイルの NUXT_NEWT_SPACE_UID の値に置き換えられ、runtimeConfig.newt.cdnApiToken の値は .env ファイルの NUXT_NEWT_CDN_API_TOKEN の値に置き換えられます。
また、これらの変数はサーバーサイドでのみ参照できる、プライベートな変数となります。

Runtime Configの詳細については、Nuxtの Runtime Config のドキュメントをご確認ください。

3-2. newt-client-jsのインストール

次に newt-client-js をインストールします。

npm install newt-client-js
# or
yarn add newt-client-js

3-3. プラグインの作成

プラグインを作成し、CDN APIを利用するためのクライアントを定義します。
プラグインはNuxtアプリケーションの初期化時に実行されます。デフォルトではサーバーサイド、クライアントサイド双方で実行されます。

Nuxtは plugins ディレクトリにあるファイルを自動的に読み込んで、Vueアプリケーションの作成時にロードします。ファイル名に .server または .client というサフィックスを付けると、サーバー側またはクライアント側でのみプラグインを読み込むことができます。

ここではサーバーサイドでのみ読み込めれば良いので、plugins ディレクトリを作成し、その中に newt.server.ts というファイルを作成します。

plugins/newt.server.ts
1import { createClient } from 'newt-client-js'
2
3export default defineNuxtPlugin(() => {
4  const config = useRuntimeConfig()
5  const newtClient = createClient({
6    spaceUid: config.newt.spaceUid,
7    token: config.newt.cdnApiToken,
8    apiType: 'cdn'
9  })
10  return {
11    provide: {
12      newtClient
13    }
14  }
15})

これで、Vueコンポーネント内から、Newtのクライアントを利用できるようになりました。
プラグインの詳細については、Nuxtの plugins のドキュメントをご確認ください。

4. 一覧ページの作成

4-1. 言語の設定をする

nuxt.config.tslang 属性を設定します。ここでは日本語 ja を指定します。

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      htmlAttrs: {
        lang: 'ja'
      }
    }
  },
  runtimeConfig: {
    newt: {
      spaceUid: '',
      cdnApiToken: ''
    }
  },
  devtools: { enabled: true },
  typescript: {
    strict: true,
    typeCheck: true
  }
})

4-2. 投稿の型を定義する

投稿の型 Article を定義しておきます。
このチュートリアルでは、_idtitleslugbody のみを使うため、以下のように定義しておきます。

types/article.ts
1export interface Article {
2  _id: string
3  title: string
4  slug: string
5  body: string
6}

4-3. NuxtPageを設定する

この後に作成する pages ディレクトリ配下のページを表示できるように、app.vue ファイルを修正します。NuxtWelcomeNuxtPage に変更します。

app.vue
<template>
  <div>
    <NuxtWelcome />
    <NuxtPage />
  </div>
</template>

4-4. 投稿一覧を取得する

Nuxtではファイルシステムベースのルーティングを採用しており、pages ディレクトリの配下にファイルを作成すると、自動的にルートとして利用できるようになります。
例えば、以下のようにルーティングされます。

  • pages/blog/index.vue/blog
  • pages/blog/first-post.vue/blog/first-post

※ ルーティングの詳細については、Nuxtの Routing のドキュメントをご確認ください。

ここではトップページ(パス: /)で投稿一覧を表示したいので、pages ディレクトリを作成し、その中に index.vue というファイルを作成します。

まず、script タグに以下の内容を記載します。
useAsyncData を利用してNewtから投稿一覧を取得し、articles という変数で定義することで、template の中で参照できるようにしています。
また、useHead を利用して、タイトルとディスクリプションを設定しています。

pages/index.vue
1<script lang="ts" setup>
2import type { Article } from '~/types/article'
3
4const { data } = await useAsyncData('articles', async () => {
5  const { $newtClient } = useNuxtApp()
6  return await $newtClient.getContents<Article>({
7    appUid: 'blog',
8    modelUid: 'article',
9    query: {
10      select: ['_id', 'title', 'slug', 'body']
11    }
12  })
13})
14const articles = data.value?.items
15
16useHead({
17  title: 'Newt・Nuxtブログ',
18  meta: [
19    { name: 'description', content: 'NewtとNuxtを利用したブログです' }
20  ]
21})
22</script>

データの取得について詳細を説明します。
まず、useNuxtApp を利用して、3-3で登録した newtClient を利用できるようにします。
次に、SDKが提供している getContents メソッドを利用して、投稿一覧を取得します。getContentsのパラメータに Article の型を渡すことで、返却される items の型として Article[] が指定されます。
また、selectパラメータを利用して、取得するフィールドを _idtitleslugbody のみに制限します。
最後に articles として data.value?.items を定義することで、getContentsで返却されたオブジェクトの items 要素を articles として参照できるようにします。

4-5. 投稿一覧を表示する

4-4で定義した articles を利用して、template内で投稿一覧を表示できるようにします。
pages/index.vue に以下の部分を追加します。

pages/index.vue
1<template>
2  <div>
3    <ul>
4      <li v-for="article in articles" :key="article._id">
5        <NuxtLink :to="`/articles/${article.slug}`">
6          {{ article.title }}
7        </NuxtLink>
8      </li>
9    </ul>
10  </div>
11</template>

http://localhost:3000/ にアクセスして、以下のように投稿一覧が表示されれば成功です。

nuxt3-blog2.png

5. 詳細ページの作成

5-1. 投稿詳細を取得する

Nuxtでは [param] のようにしてページ名に角括弧を使うことで動的なルーティング(Dynamic Routes)を作成できます。ここでは、/articles/:slug/articles/article-1 など)のパスで投稿の詳細を表示したいので、pages/articles/[slug].vue のファイルを作成します。

まず、script タグに以下の内容を記載します。
投稿一覧の取得と同様に、useAsyncData を利用します。article という変数で定義することで、template の中で参照できるようにしています。

pages/articles/[slug].vue
1<script lang="ts" setup>
2import type { Article } from '~/types/article'
3
4const route = useRoute()
5const { slug } = route.params
6
7const { data } = await useAsyncData(`article-${slug}`, async () => {
8  const { $newtClient } = useNuxtApp()
9  return await $newtClient.getFirstContent<Article>({
10    appUid: 'blog',
11    modelUid: 'article',
12    query: {
13      slug,
14      select: ['_id', 'title', 'slug', 'body']
15    }
16  })
17})
18const article = data.value
19
20useHead({
21  title: article?.title,
22  meta: [
23    { name: 'description', content: '投稿詳細ページです' }
24  ]
25})
26</script>

投稿詳細を取得するメソッドとして、SDKが提供している getFirstContent を利用しています。このメソッドはクエリに該当するコンテンツのうち、最初の1件を返却するメソッドです。指定したスラッグのコンテンツを取得したい場合は、このメソッドを利用します。

5-2. 投稿詳細を表示する

5-1で定義した article を利用して、template内で投稿詳細を表示できるようにします。
pages/articles/[slug].vue に以下の部分を追加します。

pages/articles/[slug].vue
1<template>
2  <main class="main">
3    <h1>{{ article?.title }}</h1>
4    <!-- eslint-disable-next-line vue/no-v-html -->
5    <div v-html="article?.body" />
6  </main>
7</template>

※ bodyの表示で利用されている v-html はXSSの危険性があるため、利用には注意が必要です。ここでは、Newtで管理している投稿情報を表示するものであり、不特定多数のユーザーが入力できるものを表示するわけではないため、安全なものとして利用しています。
また、v-htmlを利用すると、eslintの警告が出る場合があるため <!-- eslint-disable-next-line vue/no-v-html --> を記載しています。

これで、投稿詳細についての設定も完了です。
http://localhost:3000/articles/article-3 にアクセスして、以下のように投稿詳細が表示されれば成功です。

nuxt3-blog3.png

注意点

4-5で投稿詳細へのリンクとして、Nuxtの推奨している NuxtLink を利用しています。
本番環境で nuxt generate を利用して、プリレンダリングを行えば問題なくページが作成されますが、開発環境の場合は一覧ページから詳細ページに遷移しても、ページが表示されません。

これは開発環境の場合、初期ロード時にサーバーサイドレンダリングが行われ、NuxtLink での遷移時はクライアントサイドレンダリングが実行されるためです。
このチュートリアルでは、スペースUIDやトークンの値をクライアントサイドから隠すために、Newtのクライアントを newt.server.ts ファイルで作成し、クライアントサイドでの読み込みを許可していません。そのため、ページ遷移をした時に投稿情報を取得できず、ページが表示されなくなってしまいます。

ページ遷移後にリロードを行えば問題なくページが表示されますが、ご注意ください。

6. Vercelにデプロイする

最後に、Vercelへのデプロイを設定します。

まず、GitHubのリポジトリを作成し、これまで作成したコードをプッシュします。
詳細はGitHubの リポジトリを作成する のドキュメントをご確認ください。

続いて、作成したリポジトリとVercelを接続します。
Vercel のアカウントを持っていない方は、登録をお願いします。

接続方法の詳細については、GitHubのリポジトリとVercelを接続して、ホスティングする のチュートリアルを参考にしてください。

「Framework Preset」に「Nuxt.js」が設定されていることを確認し、「Build Command」に「nuxt generate」を指定しましょう。
また「Environment Variables」にご自身の環境変数を設定しましょう。
nuxt3-blog4.jpg

デプロイが成功し、サイトが表示されれば成功です!
nuxt3-blog5.png

次のステップ

このチュートリアルを行うことで、Nuxt3のプロジェクトを作成し、コンテンツの取得・表示を行う方法を学習しました。
更に深く学習したい方は、以下のチュートリアルもおすすめです。

Vercel以外でホスティングを行いたい方

問い合わせフォームを作成したい方

その他にも様々なチュートリアルを用意しているので、ぜひ チュートリアル のページもご確認ください。

NewtMade in Newt