Newtと11tyを使ったブログサイトの作り方

2025年05月03日

この記事では、ヘッドレストCMS「Newt」を使って静的サイトジェネレーター「11ty」を使ってブログサイトを作成する手順を紹介します。

JavaScript系のフレームワークだとGatsby、Next.js、Nuxt.jsなど、静的サイトジェネレーターでもAstroなどが使われることが多いのです。
しかし、今回、前の記事でも書いたように11tyで既に作られているサイトにヘッドレスCMSを使いたかったのですが、あまりNewtと11tyの組み合わせのサイトの情報が出てこなかったので、記事にしておきます。

説明とかいいから、コードを見たいという方は、下記のGitHubのリポジトリを試してみてください。

https://github.com/hanahana0201/newt-11ty-blog

使用技術の紹介

Newtとは?

Newtは、日本発のヘッドレスCMSで、シンプルなUIと柔軟なAPI設計が特徴です。無料プランでも十分に試せる機能が揃っており、小規模なブログやポートフォリオサイトには非常に相性が良いと感じています。

11ty(Eleventy)とは?

11tyは、Node.jsベースの静的サイトジェネレーターです。公式の説明にもある通り「高機能なのにシンプル」な構成で、HTMLやMarkdown中心で静的サイトを構築したい人には非常に親しみやすいツールです。

この役割は最近だとAstroと被るのですが、ビルド後に触りやすいHTMLを手っ取り早く準備するのに便利なので、個人的にはAstroとも使い分けて使っています。

Newt + 11tyのブログサイト作成の流れ

ここでは、以下の手順でNewt + 11tyのブログサイトを構築していきます。

  1. 環境構築
  2. Newtのセットアップ
  3. 環境変数の設定
  4. データ取得用スクリプトの作成
  5. テンプレートの作成
  6. 動的ページ生成の設定
  7. 11tyの設定ファイル
  8. ビルドと実行

1.環境構築

まず、11tyプロジェクトを作成し、必要なパッケージをインストールします。

mkdir newt-11ty-blog
cd newt-11ty-blog
npm init -y
npm install @11ty/eleventy dotenv

Newtのコンテンツを取得するためのSDKもインストールします。

npm install newt-client-js

必須ではないですが、.envファイルを使うための「dotenv」と記事の抜粋をトップページに表示するときにhtmlタグを除外するための「striptags」もインストールします。

npm install dotenv striptags

2.Newtのセットアップ

次にNewtのセットアップをしていきます。
Newtでは、便利なテンプレートが準備されており、すぐに使い始めることができます。

手順としては、Newtでスペースを作り、Appを追加するときに「テンプレートから追加」を選んで、Appテンプレートの中の「Blog」を選択して、「このテンプレートを追加」をクリックで完成です。

今回は、これをベースに話していきますが、カスタムも簡単なので触ってみてください。

3. 環境変数の設定

プロジェクトのルートディレクトリに.envファイルを作成し、Newtの認証情報を設定します。

NEWT_SPACE_UID=あなたのスペースUID
NEWT_CDN_API_TOKEN=あなたのCDN APIトークン
NEWT_APP_UID=あなたのアプリUID
NEWT_MODEL_UID=あなたのモデルUID

4. データ取得用スクリプトの作成

_dataディレクトリを作成し、Newtからデータを取得するスクリプトを作成します。

mkdir _data
touch _data/newtArticles.js

_data/newtArticles.jsファイルに以下のようなコードを記述します。

const { createClient } = require('newt-client-js')
require('dotenv').config()
// Newtクライアントの初期化
const client = createClient({
  spaceUid: process.env.NEWT_SPACE_UID,
  token: process.env.NEWT_CDN_API_TOKEN,
})
module.exports = async function () {
  // Newtからコンテンツを取得(_sysフィールドを含める)
  const articles = await client.getContents({
    appUid: process.env.NEWT_APP_UID,
    modelUid: process.env.NEWT_MODEL_UID,
    query: {
      select: ['title', 'slug', 'body', '_sys', 'tags'],
      order: ['-_sys.raw.publishedAt'] // 公開日時で並べ替え
    }
  })
  // _sys.raw.publishedAtをpublishedAtとして使用
  const formattedArticles = articles.items.map(article => {
    // システムフィールドから公開日時を取得
    const publishedAt = article._sys?.raw?.publishedAt || article._sys?.createdAt;
    return {
      ...article,
      publishedAt: publishedAt
    };
  });
  console.log('最初の記事の公開日時:', formattedArticles[0]?.publishedAt);
  return formattedArticles;
}

5. テンプレートの作成

Nunjucksテンプレートを使用して、記事一覧ページと個別記事ページを作成します。

mkdir src
mkdir src/_includes
touch src/_includes/base.njk
touch src/index.njk
mkdir src/posts
touch src/posts/post.njk

src/_includes/base.njk(ベーステンプレート)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
  <link rel="stylesheet" href="/css/style.css">
</head>
<body>
  <header>
    <h1><a href="/">ブログタイトル</a></h1>
  </header>
  <main>
    {{ content | safe }}
  </main>
  <footer>
    <p>&copy; 2025 My Blog</p>
  </footer>
</body>
</html>

src/index.njk(トップページ)

---
layout: base.njk
title: ブログホーム
---
<h2>最新記事</h2>
<ul class="post-list">
{% for article in newtArticles %}
  <li>
    <h3><a href="/posts/{{ article.slug }}/">{{ article.title }}</a></h3>
    {% if article.publishedAt %}
<p>公開日: {{ article.publishedAt | date }}</p>
{% else %}
<p>公開日: 未設定</p>
{% endif %}
    <p>{{ article.body | striptags | truncate(100) }}</p>
  </li>
{% endfor %}
</ul>

6. 動的ページ生成の設定

src/posts/post.njkファイルで、個別記事ページのテンプレートを作成し、paginationを使って動的にページを生成します。

---
layout: base.njk
pagination:
  data: newtArticles
  size: 1
  alias: article
permalink: "posts/{{ article.slug }}/"
---
<article>
  <h1>{{ article.title }}</h1>
  {% if article.publishedAt %}
<p>公開日: {{ article.publishedAt | date }}</p>
{% else %}
<p>公開日: 未設定</p>
{% endif %}
  <div class="content">
    {{ article.body | safe }}
  </div>
  {% if article.tags and article.tags.length %}
  <div class="tags">
    <h3>タグ:</h3>
    <ul>
      {% for tag in article.tags %}
      <li>{{ tag }}</li>
      {% endfor %}
    </ul>
  </div>
  {% endif %}
</article>

7. 11tyの設定ファイル

プロジェクトのルートに.eleventy.jsファイルを作成して、11tyの設定を行います。

const { DateTime } = require("luxon");
const striptags = require('striptags');
module.exports = function (eleventyConfig) {
  // 日付フォーマットフィルターの追加
  eleventyConfig.addFilter("date", function (dateObj) {
    if (!dateObj) return "日付なし";
    try {
      // ISO形式の日付文字列をフォーマット
      return DateTime.fromISO(dateObj).toFormat("yyyy年MM月dd日");
    } catch (e) {
      console.error("日付変換エラー:", e);
      return "日付エラー";
    }
  });
  // 静的ファイルのコピー
  eleventyConfig.addPassthroughCopy("src/css");
  // htmlタグを取り除く
  eleventyConfig.addFilter("striptags", striptags);
  //  年月日の整形 
  eleventyConfig.addFilter("date", function (dateObj) {
    return DateTime.fromISO(dateObj).toFormat("yyyy年MM月dd日");
  });
  return {
    dir: {
      input: "src",
      output: "_site",
      includes: "_includes",
      data: "_data"
    }
  };
};

8. ビルドと実行

package.jsonにスクリプトを追加します。

"scripts": {
  "start": "eleventy --serve",
  "build": "eleventy"
}

開発サーバーを起動します。

npm start

これで、Newtで管理しているコンテンツを11tyで静的サイトとして生成できるようになります。
Newtでコンテンツを更新し、11tyでビルドすることで、常に最新のコンテンツを反映したサイトを生成できます。

ここまでのコードが下記のGitHubのリポジトリのコミットになるので参考にしてみてください。

https://github.com/hanahana0201/newt-11ty-blog/tree/5fe50965af9591277dfdaf02fefb69b2ab03f969

一応、リポジトリの方では、tagsやauthorsページも追加しているので、必要でしたら参考にしてみてください。

https://github.com/hanahana0201/newt-11ty-blog

まとめ

この記事では、Newtと11tyで作るブログサイトの作り方を紹介してきました。
データの生成でもっと悩むかなと思っていたのですが、Newt公式のSDKもあり比較的すんなり実装できました。
ヘッドレスCMSも静的サイトジェネレーターも選択肢が増えてきてうれしいので、誰かの参考になれば幸いです。

ブログ一覧へ