GitHub Pages

ドキュメント作成ツール

GitHub Pages

概要

GitHub PagesはGitHubが提供する無料の静的サイトホスティングサービスです。GitHubリポジトリから直接HTML、CSS、JavaScriptファイルをデプロイし、Jekyllによるビルドプロセスを通じてウェブサイトを公開できます。

詳細

GitHub Pages(ギットハブページズ)は2008年にGitHubによって開始され、開発者とプロジェクトのドキュメント公開を革命的に簡単にしました。Jekyllという静的サイトジェネレータを基盤とし、MarkdownファイルとHTML/CSSから高品質なウェブサイトを自動生成します。Gitリポジトリとしてコンテンツをバージョン管理でき、プルリクエストを通じた協働編集が可能です。カスタムドメイン対応とSSL暗号化により、プロフェッショナルなウェブサイトを構築できます。2025年現在、GitHub Actionsとの深い統合により、自動ビルドとデプロイが強化されています。無料プランでもパブリックリポジトリで利用でき、有料プランではプライベートリポジトリでも使用可能です。Liquidテンプレート言語により動的コンテンツの表示が可能で、豊富なJekyllプラグインによる機能拡張ができます。Rouge構文ハイライターによりコードブロックの美しい表示をサポートし、開発者ドキュメントに最適化されています。シンプルなMarkdown記法から出版品質のドキュメントサイトを構築でき、Git連携による変更履歴管理と巻き戻し機能を提供します。

メリット・デメリット

メリット

  • 完全無料: パブリックリポジトリでの無制限ホスティング
  • Git統合: バージョン管理とコラボレーション機能の活用
  • Jekyll自動ビルド: MarkdownからHTMLへの自動変換
  • カスタムドメイン: 独自ドメインとSSL証明書の対応
  • GitHub Actions統合: CI/CDによる自動デプロイとワークフロー
  • 高速配信: 静的サイトによる高いパフォーマンス
  • セキュリティ: サーバーサイド処理不要による高いセキュリティ

デメリット

  • 静的サイト限定: 動的機能やデータベース利用不可
  • Jekyll依存: Rubyベースのビルドシステムの理解が必要
  • 制限事項: ファイルサイズ、リポジトリサイズ、帯域幅の制限
  • プラグイン制限: セキュリティ上の理由による一部プラグイン利用不可
  • パブリック要件: 無料版ではソースコードが公開される
  • ビルド時間: 大規模サイトでのJekyllビルド時間増加

主要リンク

書き方の例

リポジトリの設定と初期化

# 新しいリポジトリの作成とクローン
git clone https://github.com/username/username.github.io.git
cd username.github.io

# Jekyllサイトの初期化
echo "Hello GitHub Pages!" > index.html
git add .
git commit -m "Initial commit"
git push origin main

# リポジトリのPagesサイト構造例
username.github.io/
├── _config.yml          # Jekyll設定ファイル
├── _layouts/            # レイアウトテンプレート
│   ├── default.html
│   ├── post.html
│   └── page.html
├── _includes/           # 再利用可能な部分
│   ├── header.html
│   ├── footer.html
│   └── navigation.html
├── _posts/              # ブログ記事
│   └── 2025-06-20-welcome.md
├── _data/               # データファイル
│   └── navigation.yml
├── assets/              # CSS、JS、画像
│   ├── css/
│   ├── js/
│   └── images/
├── docs/                # ドキュメントページ
├── index.md             # ホームページ
└── README.md

Jekyll設定ファイル(_config.yml)

# _config.yml - GitHub Pages Jekyll設定
title: "プロジェクトドキュメント"
description: "技術プロジェクトの包括的なドキュメント"
baseurl: "" # サブディレクトリの場合のみ設定
url: "https://username.github.io"
author: "開発者名"
email: "[email protected]"

# Build settings
markdown: kramdown
highlighter: rouge
theme: minima

# Jekyll plugins (GitHub Pages対応)
plugins:
  - jekyll-feed
  - jekyll-sitemap
  - jekyll-seo-tag
  - jekyll-redirect-from
  - jekyll-mentions
  - jekyll-relative-links
  - jekyll-optional-front-matter
  - jekyll-readme-index
  - jekyll-default-layout
  - jekyll-titles-from-headings

# Kramdown設定
kramdown:
  input: GFM
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    css_class: 'highlight'
    span:
      line_numbers: false
    block:
      line_numbers: true

# Collection設定
collections:
  docs:
    output: true
    permalink: /:collection/:name/
  api:
    output: true
    permalink: /api/:name/

# Default front matter
defaults:
  - scope:
      path: ""
      type: "posts"
    values:
      layout: "post"
      comments: true
  - scope:
      path: ""
      type: "docs"
    values:
      layout: "page"
  - scope:
      path: ""
      type: "api"
    values:
      layout: "api"

# Exclude from processing
exclude:
  - Gemfile
  - Gemfile.lock
  - node_modules
  - vendor/
  - .sass-cache/
  - .jekyll-cache/
  - gemfiles/

# Navigation configuration
navigation:
  - title: ホーム
    url: /
  - title: ドキュメント
    url: /docs/
  - title: API
    url: /api/
  - title: ブログ
    url: /blog/
  - title: About
    url: /about/

# SEO and social
twitter:
  username: username
  card: summary

facebook:
  app_id: 1234567890
  publisher: 1234567890

logo: /assets/images/logo.png

social:
  name: プロジェクト名
  links:
    - https://twitter.com/username
    - https://github.com/username
    - https://linkedin.com/in/username

# Analytics
google_analytics: G-XXXXXXXXXX

# Comments (GitHub Issues)
github:
  repository_url: https://github.com/username/project

レイアウトテンプレートの作成

<!-- _layouts/default.html -->
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: 'ja' }}">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  {%- seo -%}
  <link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
  <link rel="shortcut icon" type="image/png" href="{{ '/assets/images/favicon.png' | relative_url }}">
  
  {%- feed_meta -%}
  {%- if jekyll.environment == 'production' and site.google_analytics -%}
    {%- include google-analytics.html -%}
  {%- endif -%}
</head>

<body>
  {%- include header.html -%}
  
  <main class="page-content" aria-label="Content">
    <div class="wrapper">
      {{ content }}
    </div>
  </main>
  
  {%- include footer.html -%}
  
  <script src="{{ '/assets/js/main.js' | relative_url }}"></script>
</body>
</html>
<!-- _layouts/post.html -->
---
layout: default
---
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
  
  <header class="post-header">
    <h1 class="post-title p-name" itemprop="name headline">{{ page.title | escape }}</h1>
    <p class="post-meta">
      <time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
        {%- assign date_format = site.minima.date_format | default: "%Y年%m月%d日" -%}
        {{ page.date | date: date_format }}
      </time>
      {%- if page.modified_date -%}
        ~ 
        <time class="dt-modified" datetime="{{ page.modified_date | date_to_xmlschema }}" itemprop="dateModified">
          更新: {{ page.modified_date | date: date_format }}
        </time>
      {%- endif -%}
      {%- if page.author -%}
        • {% for author in page.author %}
            <span itemprop="author" itemscope itemtype="http://schema.org/Person">
              <span class="p-author h-card" itemprop="name">{{ author }}</span>
            </span>
            {%- if forloop.last == false %}, {% endif -%}
          {% endfor %}
      {%- endif -%}
    </p>
  </header>

  <div class="post-content e-content" itemprop="articleBody">
    {{ content }}
  </div>

  {%- if site.disqus.shortname -%}
    {%- include disqus_comments.html -%}
  {%- endif -%}

  <a class="u-url" href="{{ page.url | relative_url }}" hidden></a>
</article>

ナビゲーションとヘッダー

<!-- _includes/header.html -->
<header class="site-header" role="banner">
  <div class="wrapper">
    {%- assign default_paths = site.pages | map: "path" -%}
    {%- assign page_paths = site.header_pages | default: default_paths -%}
    
    <a class="site-title" rel="author" href="{{ "/" | relative_url }}">
      <img src="{{ '/assets/images/logo.png' | relative_url }}" alt="{{ site.title }}" class="site-logo">
      {{ site.title | escape }}
    </a>

    {%- if page_paths -%}
      <nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger" />
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewBox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
            </svg>
          </span>
        </label>

        <div class="trigger">
          <a class="page-link" href="{{ '/' | relative_url }}">ホーム</a>
          {%- for path in page_paths -%}
            {%- assign my_page = site.pages | where: "path", path | first -%}
            {%- if my_page.title -%}
              <a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
            {%- endif -%}
          {%- endfor -%}
          
          <!-- ドロップダウンメニュー -->
          <div class="dropdown">
            <button class="dropbtn">ドキュメント</button>
            <div class="dropdown-content">
              <a href="{{ '/docs/getting-started/' | relative_url }}">はじめに</a>
              <a href="{{ '/docs/installation/' | relative_url }}">インストール</a>
              <a href="{{ '/docs/configuration/' | relative_url }}">設定</a>
              <a href="{{ '/docs/api/' | relative_url }}">API リファレンス</a>
            </div>
          </div>
        </div>
      </nav>
    {%- endif -%}
  </div>
</header>

GitHub Actions自動デプロイ設定

# .github/workflows/pages.yml
name: Build and Deploy to GitHub Pages

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

# GitHub token permissions
permissions:
  contents: read
  pages: write
  id-token: write

# Concurrency to prevent multiple deployments
concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
          cache-version: 0

      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v3

      - name: Build with Jekyll
        run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
        env:
          JEKYLL_ENV: production

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

カスタムドメイン設定

<!-- CNAME file for custom domain -->
docs.example.com
# _config.yml - カスタムドメイン設定の追加
url: "https://docs.example.com"
enforce_ssl: true

# Custom domain redirect settings
plugins:
  - jekyll-redirect-from

# Redirect rules
redirect_from:
  - /old-url/
  - /another-old-url/

redirect_to: https://docs.example.com/new-location/

Markdownコンテンツの作成

---
layout: post
title: "プロジェクトドキュメントの始め方"
date: 2025-06-20 10:00:00 +0900
categories: [documentation, tutorial]
tags: [github-pages, jekyll, markdown]
author: "開発者"
description: "GitHub Pagesでプロジェクトドキュメントを作成する方法"
image: "/assets/images/documentation-guide.png"
toc: true
---

# プロジェクトドキュメントの始め方

GitHub Pagesを使ってプロジェクトドキュメントを作成する方法を解説します。

## 目次
{:.no_toc}

* toc
{:toc}

## はじめに

GitHub Pagesは、プロジェクトのドキュメントを簡単に公開できる強力なツールです。

### 必要な知識
- Git の基本的な使い方
- Markdown の記法
- 基本的な HTML/CSS(カスタマイズする場合)

## プロジェクト設定

### 1. リポジトリの準備

```bash
# リポジトリのクローン
git clone https://github.com/username/project.git
cd project

# docs ディレクトリの作成(プロジェクトドキュメントの場合)
mkdir docs
cd docs

2. Jekyll の初期化

# Gemfile の作成
cat > Gemfile << EOF
source "https://rubygems.org"
gem "github-pages", group: :jekyll_plugins
gem "jekyll-feed"
gem "jekyll-sitemap"
gem "jekyll-seo-tag"
EOF

# 依存関係のインストール
bundle install

# Jekyll サイトの初期化
bundle exec jekyll new . --force

コンテンツの作成

Markdown の活用

## API リファレンス

### `getUserData(userId)`

ユーザーデータを取得するAPI関数です。

**パラメータ:**
- `userId` (string): ユーザーID

**戻り値:**
- Promise<UserData>: ユーザーデータのPromise

**使用例:**

```javascript
const userData = await getUserData('user123');
console.log(userData.name);

レスポンス例:

{
  "id": "user123",
  "name": "田中太郎",
  "email": "[email protected]",
  "created_at": "2025-01-01T00:00:00Z"
}

### コードブロックの強化

```markdown
## シンタックスハイライト

```python
def calculate_fibonacci(n):
    """フィボナッチ数列を計算する関数"""
    if n <= 1:
        return n
    return calculate_fibonacci(n-1) + calculate_fibonacci(n-2)

# 使用例
for i in range(10):
    print(f"F({i}) = {calculate_fibonacci(i)}")
# _config.yml設定例
title: "プロジェクト名"
description: "プロジェクトの説明"
highlighter: rouge
markdown: kramdown

kramdown:
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    css_class: 'highlight'
    line_numbers: true

## インクルードとレイアウトの活用

```liquid
<!-- API endpoint documentation include -->
<!-- _includes/api-endpoint.html -->
<div class="api-endpoint">
  <div class="method {{ include.method | downcase }}">{{ include.method }}</div>
  <div class="url">{{ include.url }}</div>
  <div class="description">{{ include.description }}</div>
</div>

<!-- 使用例 -->
{% include api-endpoint.html method="GET" url="/api/users" description="ユーザー一覧を取得" %}
{% include api-endpoint.html method="POST" url="/api/users" description="新しいユーザーを作成" %}

検索機能の実装

// assets/js/search.js
class SimpleSearch {
  constructor() {
    this.searchInput = document.getElementById('search-input');
    this.searchResults = document.getElementById('search-results');
    this.searchData = [];
    
    this.loadSearchData();
    this.bindEvents();
  }
  
  async loadSearchData() {
    try {
      const response = await fetch('/search.json');
      this.searchData = await response.json();
    } catch (error) {
      console.error('Search data loading failed:', error);
    }
  }
  
  bindEvents() {
    this.searchInput.addEventListener('input', (e) => {
      this.performSearch(e.target.value);
    });
  }
  
  performSearch(query) {
    if (query.length < 2) {
      this.searchResults.innerHTML = '';
      return;
    }
    
    const results = this.searchData.filter(item => 
      item.title.toLowerCase().includes(query.toLowerCase()) ||
      item.content.toLowerCase().includes(query.toLowerCase())
    );
    
    this.displayResults(results);
  }
  
  displayResults(results) {
    if (results.length === 0) {
      this.searchResults.innerHTML = '<p>検索結果が見つかりません。</p>';
      return;
    }
    
    const html = results.map(result => `
      <div class="search-result">
        <h3><a href="${result.url}">${result.title}</a></h3>
        <p>${this.truncateText(result.content, 150)}</p>
      </div>
    `).join('');
    
    this.searchResults.innerHTML = html;
  }
  
  truncateText(text, length) {
    return text.length > length ? text.substring(0, length) + '...' : text;
  }
}

// 初期化
document.addEventListener('DOMContentLoaded', () => {
  new SimpleSearch();
});

開発・デプロイコマンド

# ローカル開発サーバーの起動
bundle exec jekyll serve --port 4000 --livereload

# 本番用ビルド
JEKYLL_ENV=production bundle exec jekyll build

# デプロイ(GitHub Pagesの場合)
git add .
git commit -m "Update documentation"
git push origin main

# カスタムドメインでの確認
curl -I https://docs.example.com

# SSL設定の確認
openssl s_client -connect docs.example.com:443 -servername docs.example.com

# ビルド問題のデバッグ
bundle exec jekyll build --verbose
bundle exec jekyll doctor

# 依存関係の更新
bundle update
bundle outdated

# キャッシュクリア
bundle exec jekyll clean
rm -rf _site .jekyll-cache