Eleventy (11ty)

JavaScript製のシンプルで柔軟なSSG。16k超のGitHubスターを持ち、設定不要ですぐに始められる。

言語:JavaScript
フレームワーク:None
ビルド速度:Fast
GitHub Stars:16k
初回リリース:2018
人気ランキング:第6位

トレンド・動向

シンプルさとパフォーマンスを重視する開発者に人気。企業主導でない人間的なアプローチが評価される。

# 静的サイトジェネレータ Eleventy (11ty) ## 概要 Eleventy(11ty)は「JavaScript製のシンプルで柔軟なSSG」として開発された、設定不要ですぐに始められる静的サイトジェネレータです。16k超のGitHubスターを誇り、シンプルさとパフォーマンスを重視する開発者に人気を集めています。企業主導でない人間的なアプローチが評価され、複雑な設定を避けて直感的にサイト構築を行いたい開発者にとって最適な選択肢です。豊富なテンプレート言語サポート(11種類)により、既存の知識を活かしながら効率的な開発が可能です。 ## 詳細 Eleventy 3.x版は2018年からの継続的な開発により、シンプルさと柔軟性のバランスを追求した成熟したSSGとして確立されています。最大の特徴は「ゼロ設定」でありながら高度なカスタマイズが可能な点で、HTML、Markdown、Nunjucks、Liquid、Handlebars、Mustache、EJS、Haml、Pug、JavaScript、WebCの11種類のテンプレート言語を標準サポート。データカスケードシステムにより、JSON、JavaScript、フロントマター等の複数データソースを統一的に管理でき、コレクション機能で動的なサイト構造を効率的に構築可能です。プラグインシステムによる拡張性と、高速なビルドパフォーマンスにより、個人ブログから企業サイトまで幅広い用途で採用されています。 ### 主な特徴 - **ゼロ設定**: 設定ファイル不要で即座にサイト構築開始 - **11種類のテンプレート言語サポート**: 既存知識を最大限活用 - **データカスケードシステム**: 複数データソースの統一管理 - **高速ビルド**: ミニマルな設計による優れたパフォーマンス - **柔軟なプラグインシステム**: 機能拡張と外部サービス統合 - **コレクション機能**: 動的サイト構造とナビゲーション生成 ## メリット・デメリット ### メリット - ゼロ設定による学習コストの低さと即座の開発開始 - 11種類のテンプレート言語サポートによる高い柔軟性 - 軽量でシンプルな設計による高速ビルドと安定性 - データカスケードによる直感的で柔軟なデータ管理 - 企業に依存しないコミュニティ主導の継続的な開発 - 豊富なプラグインエコシステムとカスタマイズ性 ### デメリット - 大規模サイトでの高度な機能や最適化が限定的 - React/Vue等のモダンフレームワークとの統合が複雑 - GraphQLデータレイヤーなどの先進的機能が未サポート - 企業レベルの大規模開発での実績や事例が少ない - ビルド時間が大規模サイトで他のSSGより劣る場合 - コミュニティサイズが大手SSGと比較して小規模 ## 参考ページ - [Eleventy 公式サイト](https://www.11ty.dev/) - [Eleventy ドキュメント](https://www.11ty.dev/docs/) - [Eleventy GitHub リポジトリ](https://github.com/11ty/eleventy) ## 書き方の例 ### インストールとプロジェクト作成 ```bash # Eleventyのインストール npm install @11ty/eleventy # 新しいプロジェクト作成 mkdir my-eleventy-site cd my-eleventy-site npm init -y npm install @11ty/eleventy # 開発サーバー起動 npx @11ty/eleventy --serve # プロダクションビルド npx @11ty/eleventy # 特定のディレクトリから出力 npx @11ty/eleventy --input=src --output=dist ``` ### 基本ページ作成 ```html <!-- index.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>私のEleventyサイト</title> </head> <body> <header> <h1>ようこそ、Eleventyサイトへ</h1> <nav> <a href="/">ホーム</a> <a href="/about/">概要</a> <a href="/blog/">ブログ</a> </nav> </header> <main> <h2>最新のブログ投稿</h2> <p>シンプルで高速なサイトをEleventyで構築しました。</p> <section> <h3>特徴</h3> <ul> <li>ゼロ設定で即座に開始</li> <li>高速なビルド処理</li> <li>柔軟なテンプレート</li> </ul> </section> </main> <footer> <p>&copy; 2024 My Eleventy Site</p> </footer> </body> </html> ``` ```markdown --- title: 概要ページ layout: base.njk permalink: /about/ --- # 私たちについて このサイトはEleventyで構築された静的サイトです。 ## 特徴 - **シンプル**: 複雑な設定不要 - **高速**: 最適化されたビルド - **柔軟**: 多様なテンプレート対応 ## お問い合わせ 何かご質問があれば、お気軽にお問い合わせください。 ``` ### データファイルとコレクション ```json // _data/site.json { "title": "私のEleventyサイト", "description": "Eleventyで構築した高速で美しいサイト", "author": "山田太郎", "url": "https://example.com", "social": { "twitter": "https://twitter.com/example", "github": "https://github.com/example" } } ``` ```javascript // _data/posts.js module.exports = [ { title: "Eleventyでサイト構築", slug: "getting-started-eleventy", date: "2024-01-15", excerpt: "Eleventyの基本的な使い方を学びます", tags: ["tutorial", "eleventy", "ssg"] }, { title: "静的サイトの利点", slug: "benefits-static-sites", date: "2024-01-20", excerpt: "静的サイトがもたらすメリットについて", tags: ["web", "performance", "ssg"] }, { title: "Eleventyプラグイン活用", slug: "eleventy-plugins", date: "2024-01-25", excerpt: "便利なプラグインでサイトを拡張", tags: ["plugins", "eleventy", "development"] } ]; ``` ### テンプレートとレイアウト ```html <!-- _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 }} - {{ site.title }}</title> <meta name="description" content="{{ description or site.description }}"> <link rel="stylesheet" href="/css/style.css"> </head> <body> <header class="site-header"> <div class="container"> <h1><a href="/">{{ site.title }}</a></h1> <nav> <a href="/">ホーム</a> <a href="/about/">概要</a> <a href="/blog/">ブログ</a> <a href="/contact/">お問い合わせ</a> </nav> </div> </header> <main class="main-content"> <div class="container"> {{ content | safe }} </div> </main> <footer class="site-footer"> <div class="container"> <p>&copy; 2024 {{ site.author }}. All rights reserved.</p> <div class="social-links"> <a href="{{ site.social.twitter }}">Twitter</a> <a href="{{ site.social.github }}">GitHub</a> </div> </div> </footer> </body> </html> ``` ```html <!-- blog/index.njk --> --- title: ブログ layout: base.njk permalink: /blog/ --- <h1>ブログ記事一覧</h1> <div class="blog-posts"> {% for post in posts %} <article class="blog-post-card"> <header> <h2><a href="/blog/{{ post.slug }}/">{{ post.title }}</a></h2> <time datetime="{{ post.date }}">{{ post.date | date: "%Y年%m月%d日" }}</time> </header> <p>{{ post.excerpt }}</p> <footer> <div class="tags"> {% for tag in post.tags %} <span class="tag">{{ tag }}</span> {% endfor %} </div> <a href="/blog/{{ post.slug }}/" class="read-more">続きを読む</a> </footer> </article> {% endfor %} </div> <aside class="blog-sidebar"> <h3>タグ一覧</h3> <div class="tag-cloud"> {% for tag in collections.all | getAllTags | sort %} <a href="/tags/{{ tag }}/" class="tag-link">{{ tag }}</a> {% endfor %} </div> </aside> ``` ### フィルターとショートコード ```javascript // .eleventy.js module.exports = function(eleventyConfig) { // カスタムフィルター eleventyConfig.addFilter("dateFormat", function(date, format) { return new Intl.DateTimeFormat('ja-JP', { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date(date)); }); eleventyConfig.addFilter("excerpt", function(content, limit = 150) { const text = content.replace(/<[^>]*>/g, ''); return text.length > limit ? text.substring(0, limit) + '...' : text; }); eleventyConfig.addFilter("getAllTags", function(collection) { let tagSet = new Set(); collection.forEach(item => { if (item.data.tags) { item.data.tags.forEach(tag => tagSet.add(tag)); } }); return [...tagSet]; }); // ショートコード eleventyConfig.addShortcode("currentYear", function() { return new Date().getFullYear(); }); eleventyConfig.addShortcode("button", function(text, url, style = "primary") { return `<a href="${url}" class="btn btn-${style}">${text}</a>`; }); eleventyConfig.addPairedShortcode("callout", function(content, type = "info") { return `<div class="callout callout-${type}">${content}</div>`; }); // コレクション eleventyConfig.addCollection("featuredPosts", function(collectionApi) { return collectionApi.getFilteredByTag("featured").reverse(); }); eleventyConfig.addCollection("postsByYear", function(collectionApi) { const posts = collectionApi.getFilteredByTag("post"); const postsByYear = {}; posts.forEach(post => { const year = new Date(post.data.date).getFullYear(); if (!postsByYear[year]) { postsByYear[year] = []; } postsByYear[year].push(post); }); return postsByYear; }); return { dir: { input: "src", output: "_site", includes: "_includes", data: "_data" }, templateFormats: ["html", "md", "njk", "liquid"], htmlTemplateEngine: "njk", markdownTemplateEngine: "njk" }; }; ``` ### 設定カスタマイズ ```javascript // eleventy.config.js import { EleventyHtmlBasePlugin } from "@11ty/eleventy"; import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight"; import rssPlugin from "@11ty/eleventy-plugin-rss"; export default function(eleventyConfig) { // プラグイン追加 eleventyConfig.addPlugin(EleventyHtmlBasePlugin); eleventyConfig.addPlugin(syntaxHighlight); eleventyConfig.addPlugin(rssPlugin); // 静的ファイルのコピー eleventyConfig.addPassthroughCopy("src/css"); eleventyConfig.addPassthroughCopy("src/js"); eleventyConfig.addPassthroughCopy("src/images"); eleventyConfig.addPassthroughCopy("src/favicon.ico"); // ウォッチ対象ファイル eleventyConfig.addWatchTarget("src/css/"); eleventyConfig.addWatchTarget("src/js/"); // グローバルデータ eleventyConfig.addGlobalData("currentYear", () => new Date().getFullYear()); eleventyConfig.addGlobalData("buildTime", () => new Date().toISOString()); // Markdownライブラリのカスタマイズ eleventyConfig.amendLibrary("md", mdLib => { mdLib.set({ html: true, breaks: true, linkify: true, typographer: true }); }); // 開発サーバー設定 eleventyConfig.setServerOptions({ port: 8080, showAllHosts: true, open: true, notify: true }); // ビルド設定 return { dir: { input: "src", output: "_site", includes: "_includes", layouts: "_layouts", data: "_data" }, templateFormats: ["html", "md", "njk", "liquid", "js"], htmlTemplateEngine: "njk", markdownTemplateEngine: "njk", pathPrefix: process.env.NODE_ENV === 'production' ? '/my-site/' : '/' }; }; ``` ```json { "scripts": { "start": "eleventy --serve --port=8080", "build": "eleventy", "build:production": "NODE_ENV=production eleventy", "clean": "rm -rf _site", "debug": "eleventy --debug" }, "devDependencies": { "@11ty/eleventy": "^3.0.0", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", "@11ty/eleventy-plugin-rss": "^2.0.0" } } ```