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

最終更新日:

Table of contents

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

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

  • Astro(astro): 3.0.8
  • newt-client-js(newt-client-js): 3.2.6
Astro v3を利用する場合、Node 18.4.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 を選択)
  • dependenciesをインストールするか(ここでは Yes を選択)
  • TypeScriptを利用するか(ここでは Yes を選択)
  • TypeScriptの設定をどうするか(ここでは Strict を選択)
  • 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.0.1" with binaries:
      - create-astro

╭─────╮  Houston:
│ ◠ ◡ ◠  Initiating launch sequence...
╰─────╯

 astro   v3.0.8 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
      ✔  Template copied

  deps   Install dependencies?
         Yes
      ✔  Dependencies installed

    ts   Do you plan to write TypeScript?
         Yes

   use   How strict should TypeScript be?
         Strict
      ✔  TypeScript customized

   git   Initialize a new git repository?
         Yes
      ✔  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 98.58s.

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

$ 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