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

最終更新日:

Table of contents

このチュートリアルでは、Newtと Astro を利用して、ブログを作成する手順を紹介します。
具体的には、Newtで管理しているコンテンツの一覧ページと詳細ページを作る手順を紹介します。

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

  • Astro(astro): 4.4.0
  • newt-client-js(newt-client-js): 3.3.0
Astro v4を利用する場合、Node 18.14.1 以上が必要となります。ご注意ください。

概要

Astroでプロジェクトを作成し、Newtのコンテンツ情報を取得できるようにします。
コンテンツの一覧ページ(パス: /)と詳細ページ(パス: /articles/:slug 。slugがarticle-1の場合は /articles/article-1)を作成し、ローカル環境で表示を行うまでを説明します。
また、ここではビルド時にHTMLを生成する、静的生成(Static Generation)の方法を紹介します。

1. Astroのセットアップ

はじめに、Astroのセットアップを行います。create-astro を利用することで、簡単にAstroのプロジェクトを作成できます。
以下のどれかのコマンドを入力します。

npm create astro@latest
# or
pnpm create astro@latest
# or
yarn create astro

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

  • どこにプロジェクトを作成するか(ここでは ./astro-blog と入力)
  • プロジェクトをどのように始めるか(ここでは Include sample files を選択)
  • TypeScriptを利用するか(ここでは Yes を選択)
  • TypeScriptの設定をどうするか(ここでは Strict を選択)
  • dependenciesをインストールするか(ここでは Yes を選択)
  • gitリポジトリを初期化するか?(ここでは Yes を選択)

yarnを利用した場合、以下のように表示されます。

$  yarn create astro
yarn create v1.22.19
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...

success Installed "create-astro@4.7.3" with binaries:
      - create-astro
[################################################] 48/48
 astro   Launch sequence initiated.

   dir   Where should we create your new project?
         ./astro-blog

  tmpl   How would you like to start your new project?
         Include sample files

    ts   Do you plan to write TypeScript?
         Yes

   use   How strict should TypeScript be?
         Strict

  deps   Install dependencies?
         Yes

   git   Initialize a new git repository?
         Yes

      ✔  Project initialized!
         ■ Template copied
         ■ TypeScript customized
         ■ Dependencies installed
         ■ Git initialized

  next   Liftoff confirmed. Explore your project!

         Enter your project directory using cd ./astro-blog
         Run yarn dev to start the dev server. CTRL+C to stop.
         Add frameworks like react or tailwind using astro add.

         Stuck? Join us at https://astro.build/chat

╭─────╮  Houston:
│ ◠ ◡ ◠  Good luck out there, astronaut! 🚀
╰─────╯
✨  Done in 88.10s.

作成したプロジェクトに移動して、開発サーバーを立ち上げます。

$ cd astro-blog
$ yarn dev

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

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-3や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. 環境変数の設定

Astroの環境変数は、プロジェクトディレクトリの .env ファイルから読み込めます。詳細はAstroの 環境変数 のドキュメントをご確認ください。

ここでは、.env ファイルを作成し、2-2で確認したスペースUID、2-3で作成したトークンの値を定義します。以下を、実際の値で置き換えて定義してください。

.env
1NEWT_SPACE_UID=sample-for-docs
2NEWT_CDN_API_TOKEN=xxxxxxxxxxxxxxx

上記のように定義しておくと、import.meta.env.NEWT_SPACE_UIDimport.meta.env.NEWT_CDN_API_TOKEN として利用できるようになります。

また、src/env.d.tsImportMetaEnv を以下のように設定することで、環境変数の自動補完が効くようになります。

src/env.d.ts
/// <reference types="astro/client" />

interface ImportMetaEnv {
  readonly NEWT_SPACE_UID: string
  readonly NEWT_CDN_API_TOKEN: string
}

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

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

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

3-3. APIクライアントの作成

CDN APIを利用するためのクライアントを作成します。
spaceUidtoken のところには3-1で設定した環境変数を入力します。
ここではCDN APIを利用するので、apiType には cdn を指定しましょう。

src/lib/newt.ts
1import { createClient } from 'newt-client-js'
2
3export const newtClient = createClient({
4  spaceUid: import.meta.env.NEWT_SPACE_UID,
5  token: import.meta.env.NEWT_CDN_API_TOKEN,
6  apiType: 'cdn',
7})

これで、NewtにAPIリクエストを送るための準備ができました。

4. 一覧ページの作成

4-1. 言語の設定とディスクリプションの設定をする

src/layouts/Layout.astro を修正します。
言語の設定では、lang 属性を修正します。ここでは日本語 ja を指定します。
また、引数として description を渡すと、メタディスクリプションに設定されるようにします。
※ 背景色が黒だと少し見づらいため、htmlの background のスタイルを削除しています。

src/layouts/Layout.astro
---
export interface Props {
  title: string
  description: string
}

const { title } = Astro.props
const { title, description } = Astro.props
---

<!DOCTYPE html>
  <html lang="en">
  <html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="description" content="Astro description" />
    <meta name="description" content={description} />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="generator" content={Astro.generator} />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

(省略)

  html {
    font-family: system-ui, sans-serif;
    background: #13151A;
    background-size: 224px;
  }

(省略)

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

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

src/lib/newt.ts
import { createClient } from 'newt-client-js'

export interface Article {
  title: string
  slug: string
  body: string
}

export const newtClient = createClient({
  spaceUid: import.meta.env.NEWT_SPACE_UID,
  token: import.meta.env.NEWT_CDN_API_TOKEN,
  apiType: 'cdn',
})

4-3. 投稿一覧の取得メソッドを作成する

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

  • src/pages/blog/index.astro/blog
  • src/pages/blog/first-post.astro/blog/first-post

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

ここではトップページ(パス: /)で投稿一覧を表示したいので、src/pages/index.astro のファイルを修正します。

投稿一覧を取得するために、SDKが提供している getContents メソッドを利用します。getContentsはNewtのコンテンツ一覧を取得するためのメソッドです。getContentsのパラメータに Article の型を渡すことで、返却される items の型として Article[] が指定されます。
また、selectパラメータを利用して、取得するフィールドを titleslugbody のみに制限します。

src/pages/index.astro
1---
2import Layout from '../layouts/Layout.astro'
3import { newtClient } from '../lib/newt'
4import type { Article } from '../lib/newt'
5
6const { items: articles } = await newtClient.getContents<Article>({
7  appUid: 'blog',
8  modelUid: 'article',
9  query: {
10    select: ['title', 'slug', 'body'],
11  },
12})
13---
14
15<Layout title="Newt・Astroブログ" description="NewtとAstroを利用したブログです">
16  <main></main>
17</Layout>

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

次に、投稿一覧を表示します。src/pages/index.astro は以下のようになります。

src/pages/index.astro
1---
2import Layout from '../layouts/Layout.astro'
3import { newtClient } from '../lib/newt'
4import type { Article } from '../lib/newt'
5
6const { items: articles } = await newtClient.getContents<Article>({
7  appUid: 'blog',
8  modelUid: 'article',
9  query: {
10    select: ['title', 'slug', 'body'],
11  },
12})
13---
14
15<Layout title="Newt・Astroブログ" description="NewtとAstroを利用したブログです">
16  <main>
17    <ul>
18      {
19        articles.map((article) => {
20          return (
21            <li>
22              <a href={`/articles/${article.slug}`}>{article.title}</a>
23            </li>
24          )
25        })
26      }
27    </ul>
28  </main>
29</Layout>

ここでは詳細ページへのリンクとして、HTML標準の <a> 要素を利用しています。
詳細については、Astroの ページ間のリンク をご確認ください。

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

astro-blog2.png

5. 詳細ページの作成

5-1. 動的ルーティングを設定する

Astroで 動的ルーティング を設定するためには、以下の2つが必要です。

  1. src/pages/blog/[slug].astrosrc/pages/[username]/settings.astro のように、角括弧を使って動的なパラメータを識別すること
  2. getStaticPaths() 関数をエクスポートして、Astroでプリレンダリングされるパスを正確に指定すること

まず、ここでは /articles/:slug/articles/article-1 など)のパスで投稿の詳細を表示したいので、src/pages/articles/[slug].astro のファイルを作成します。

次に getStaticPaths() 関数を作成します。この関数の params キーによって、どのパスがプリレンダリングされるか決まります。
ここでは全投稿のスラッグを定義するため、以下のように params を指定します。
投稿一覧を取得する部分は4-3と同じです。

src/pages/articles/[slug].astro
1---
2import Layout from '../../layouts/Layout.astro'
3import { newtClient } from '../../lib/newt'
4import type { Article } from '../../lib/newt'
5
6export const getStaticPaths = async () => {
7  const { items: articles } = await newtClient.getContents<Article>({
8    appUid: 'blog',
9    modelUid: 'article',
10    query: {
11      select: ['title', 'slug', 'body'],
12    },
13  })
14  return articles.map((article) => ({
15    params: { slug: article.slug },
16  }))
17}
18---
19
20<Layout title="投稿詳細ページ" description="投稿詳細ページです">
21  <main></main>
22</Layout>

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

次に、投稿詳細を表示します。

ここでは getStaticPathsprops を利用して、投稿データを渡しています。
src/pages/articles/[slug].astro は以下のようになります。

src/pages/articles/[slug].astro
1---
2import Layout from '../../layouts/Layout.astro'
3import { newtClient } from '../../lib/newt'
4import type { Article } from '../../lib/newt'
5
6export const getStaticPaths = async () => {
7  const { items: articles } = await newtClient.getContents<Article>({
8    appUid: 'blog',
9    modelUid: 'article',
10    query: {
11      select: ['title', 'slug', 'body'],
12    },
13  })
14  return articles.map((article) => ({
15    params: { slug: article.slug },
16    props: { article },
17  }))
18}
19
20const { article } = Astro.props
21---
22
23<Layout title={article.title} description="投稿詳細ページです">
24  <main>
25    <h2>{article.title}</h2>
26    <article set:html={article.body} />
27  </main>
28</Layout>

※ bodyの表示で利用されている set:html はXSSの危険性があるため、利用には注意が必要です。ここでは、Newtで管理している投稿情報を表示するものであり、不特定多数のユーザーが入力できるものを表示するわけではないため、安全なものとして利用しています。

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

astro-blog3.png

次のステップ

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

ホスティングを行いたい方

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

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

NewtMade in Newt