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は、日本発のヘッドレスCMSで、シンプルなUIと柔軟なAPI設計が特徴です。無料プランでも十分に試せる機能が揃っており、小規模なブログやポートフォリオサイトには非常に相性が良いと感じています。
11tyは、Node.jsベースの静的サイトジェネレーターです。公式の説明にもある通り「高機能なのにシンプル」な構成で、HTMLやMarkdown中心で静的サイトを構築したい人には非常に親しみやすいツールです。
この役割は最近だとAstroと被るのですが、ビルド後に触りやすいHTMLを手っ取り早く準備するのに便利なので、個人的にはAstroとも使い分けて使っています。
ここでは、以下の手順でNewt + 11tyのブログサイトを構築していきます。
まず、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
次にNewtのセットアップをしていきます。
Newtでは、便利なテンプレートが準備されており、すぐに使い始めることができます。
手順としては、Newtでスペースを作り、Appを追加するときに「テンプレートから追加」を選んで、Appテンプレートの中の「Blog」を選択して、「このテンプレートを追加」をクリックで完成です。
今回は、これをベースに話していきますが、カスタムも簡単なので触ってみてください。
プロジェクトのルートディレクトリに.envファイルを作成し、Newtの認証情報を設定します。
NEWT_SPACE_UID=あなたのスペースUID
NEWT_CDN_API_TOKEN=あなたのCDN APIトークン
NEWT_APP_UID=あなたのアプリUID
NEWT_MODEL_UID=あなたのモデルUID
_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;
}
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>© 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>
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>
プロジェクトのルートに.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"
}
};
};
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も静的サイトジェネレーターも選択肢が増えてきてうれしいので、誰かの参考になれば幸いです。