aRustyDev / aRustyDev/mdbook-htmx

docs(examples): GitHub Pages Deployment

Open
#41 0 comments 0 reactions 1 assignee Claimed by @aRustyDev View on GitHub
documentation
Dominant language
Rust
Stars
0
Forks
1
PR merge metrics
No merged PRs in 30d

Description

# GitHub Pages Deployment

Deploy mdbook-htmx to GitHub Pages for free static hosting.

## Overview

GitHub Pages is ideal for:
- Open source documentation
- Public API references
- Project documentation

Limitations:
- Static only (no server-side search/auth)
- 1GB repository size limit
- 100GB bandwidth/month

## Quick Start

### GitHub Actions Workflow

```yaml
# .github/workflows/deploy-pages.yml
name: Deploy to GitHub Pages

on:
push:
branches: [main]
workflow_dispatch:

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

concurrency:
group: "pages"
cancel-in-progress: false

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

- name: Setup Rust
uses: dtolnay/rust-action@stable

- name: Install mdbook and plugins
run: |
cargo install mdbook
cargo install mdbook-htmx

- name: Build documentation
run: mdbook build

- name: Setup Pages
uses: actions/configure-pages@v4

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './book'

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
```

## Repository Setup

### Enable GitHub Pages

1. Go to **Settings** → **Pages**
2. Source: **GitHub Actions**
3. (Optional) Add custom domain

### book.toml Configuration

```toml
[book]
title = "My Documentation"
authors = ["Your Name"]
language = "en"
src = "src"

[output.htmx]
# GitHub Pages URL format
base_url = "https://username.github.io/repo-name"

# Client-side search (no server available)
[output.htmx.search]
mode = "client"
enabled = true

# Asset hashing for cache busting
asset_hashing = true

# Prerender all pages
prerender = true

# No authentication (public)
[output.htmx.authn]
enabled = false
```

## Custom Domain

### Configure DNS

Add a CNAME record:
```
docs.example.com → username.github.io
```

### Add CNAME file

Create `book/CNAME` (or add to build):

```
docs.example.com
```

### Update workflow

```yaml
- name: Build documentation
run: mdbook build

- name: Add CNAME
run: echo "docs.example.com" > book/CNAME
```

### book.toml for custom domain

```toml
[output.htmx]
base_url = "https://docs.example.com"
```

## Multi-Version Documentation

### Version branches

```
main → /
v1.x → /v1/
v2.x → /v2/
```

### Workflow for versioned docs

```yaml
name: Deploy Versioned Docs

on:
push:
branches:
- main
- 'v[0-9]+.x'
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Determine version
id: version
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "version=latest" >> $GITHUB_OUTPUT
echo "path=." >> $GITHUB_OUTPUT
else
VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/heads\/v//')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "path=v${VERSION%.*}" >> $GITHUB_OUTPUT
fi

- name: Install mdbook
run: cargo install mdbook mdbook-htmx

- name: Build
run: mdbook build
env:
MDBOOK_OUTPUT__HTMX__BASE_URL: "https://docs.example.com/${{ steps.version.outputs.path }}"

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './book'
name: docs-${{ steps.version.outputs.version }}

deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: combined

- name: Combine versions
run: |
mkdir -p public
# Latest goes to root
if [ -d "combined/docs-latest" ]; then
cp -r combined/docs-latest/* public/
fi
# Versions go to subdirectories
for dir in combined/docs-v*/; do
version=$(basename "$dir" | sed 's/docs-//')
mkdir -p "public/$version"
cp -r "$dir"/* "public/$version/"
done

- name: Deploy
uses: actions/deploy-pages@v4
with:
artifact_name: combined-docs
```

## Version Switcher

Add version dropdown to documentation:

### Version config

```toml
# book.toml
[output.htmx.versions]
enabled = true
current = "v2.0"
available = [
{ version = "v2.0", url = "/", label = "2.0 (latest)" },
{ version = "v1.0", url = "/v1/", label = "1.0" },
]
```

### Version dropdown template

```html



{% for v in config.htmx.versions.available %}

{{ v.label }}

{% endfor %}


```

## Client-Side Search

Since GitHub Pages is static, use client-side search:

### lunr.js Integration

```html

document.addEventListener('DOMContentLoaded', async () => {
// Load search index generated by mdbook-htmx
const response = await fetch('/search-index.json');
const data = await response.json();

// Build lunr index
const idx = lunr(function() {
this.ref('path');
this.field('title', { boost: 10 });
this.field('content');
this.field('headings', { boost: 5 });

data.pages.forEach(page => {
this.add(page);
});
});

// Search handler
window.doSearch = (query) => {
const results = idx.search(query);
return results.map(r => data.pages.find(p => p.path === r.ref));
};
});

```

## SEO Optimization

### robots.txt

Create `book/robots.txt`:

```
User-agent: *
Allow: /

Sitemap: https://docs.example.com/sitemap.xml
```

### sitemap.xml

Generate sitemap in build:

```yaml
- name: Generate sitemap
run: |
echo '' > book/sitemap.xml
echo '' >> book/sitemap.xml
find book -name "*.html" | while read file; do
url=$(echo "$file" | sed 's|book/|https://docs.example.com/|')
echo " $url" >> book/sitemap.xml
done
echo '' >> book/sitemap.xml
```

## Performance Optimization

### Cache headers

GitHub Pages sets cache headers automatically:
- HTML: `Cache-Control: max-age=600` (10 minutes)
- Assets: `Cache-Control: max-age=31536000` (1 year)

### Asset optimization

```yaml
- name: Optimize assets
run: |
# Minify CSS
npx postcss book/assets/css/*.css --replace

# Optimize images
npx imagemin book/assets/images/* --out-dir=book/assets/images

# Compress with Brotli (served by GitHub)
find book -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" \) \
-exec brotli -k {} \;
```

## Monitoring

### Google Analytics

```html

{% if config.htmx.analytics.google_id %}

window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{ config.htmx.analytics.google_id }}');

{% endif %}
```

### Plausible (privacy-friendly)

```html

```

## Troubleshooting

### Build failures

```bash
# Check workflow logs
gh run view --log

# Test locally
mdbook build
```

### 404 errors

1. Check base_url in book.toml
2. Verify all links are relative
3. Add .nojekyll file: `touch book/.nojekyll`

### Slow deploys

- Reduce artifact size
- Use sparse checkout for large repos
- Cache cargo dependencies

```yaml
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
```

## Cost

GitHub Pages is **free** for public repositories.

For private repos:
- GitHub Pro: $4/month
- GitHub Team: $4/user/month

## Next Steps

- Add [Cloudflare CDN](./cf-pages-static.md) for better performance
- Set up [authentication](./cf-workers-d1.md) for private docs
- Deploy to [Kubernetes](./k8s-deployment.md) for more control

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.