aRustyDev / aRustyDev/mdbook-htmx
docs(examples): Cloudflare Pages Static Deployment
- Dominant language
- Rust
- Stars
- 0
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
# Cloudflare Pages Static Deployment
Deploy mdbook-htmx output as a static site on Cloudflare Pages.
## Implementation
The Cloudflare deployment configuration lives in the mdbook-htmx repository:
```
mdbook-htmx/
├── wrangler.jsonc # Wrangler configuration
├── workers/
│ ├── index.ts # Main worker with HTMX routing
│ ├── auth.ts # Auth utilities (Phase 3)
│ ├── search.ts # Search handler (Phase 4)
│ ├── analytics.ts # Analytics (Phase 5)
│ ├── package.json
│ └── tsconfig.json
├── migrations/
│ └── 0001_sessions.sql # D1 schema (Phase 3)
└── .github/workflows/
├── test-deployments.yml
└── deploy-cloudflare.yml
```
**Production URL:** `https://mdbook-htmx.arusty.dev`
See [ADR-0016](../adr/0016-implementation-phasing-strategy.md) for phase-by-phase additions.
## Overview
This is the simplest deployment option—pure static files served from Cloudflare's edge network. Ideal for public documentation without authentication requirements.
## Prerequisites
- Cloudflare account
- Wrangler CLI (`npm install -g wrangler`)
- mdbook-htmx built output
## Project Structure
```
my-docs/
├── book.toml
├── src/
│ └── ... (markdown files)
├── book/ # mdbook-htmx output
│ ├── index.html
│ ├── manifest.json
│ ├── search-index.json
│ └── assets/
└── wrangler.toml # Pages config
```
## Configuration
### book.toml
```toml
[book]
title = "My Documentation"
authors = ["Your Name"]
language = "en"
[output.htmx]
# Base URL for assets (Cloudflare Pages domain)
base_url = "https://docs.example.com"
# Enable asset hashing for cache busting
asset_hashing = true
# Prerender all pages for static deployment
prerender = true
# Disable server-side features
[output.htmx.search]
mode = "client" # Client-side search only
[output.htmx.authn]
enabled = false # No authentication
```
### wrangler.toml
```toml
name = "my-docs"
compatibility_date = "2024-01-01"
pages_build_output_dir = "book"
# Optional: Custom headers
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "strict-origin-when-cross-origin"
# Cache static assets aggressively
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
```
## Build Script
```bash
#!/bin/bash
# build.sh
set -e
echo "Building documentation..."
mdbook build
echo "Optimizing assets..."
# Optional: Compress images, minify CSS/JS
# npx postcss book/assets/css/main.css -o book/assets/css/main.min.css
echo "Build complete!"
```
## GitHub Actions Deployment
```yaml
# .github/workflows/deploy.yml
name: Deploy to Cloudflare Pages
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- uses: actions/checkout@v4
- name: Install mdbook
run: |
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.37/mdbook-v0.4.37-x86_64-unknown-linux-gnu.tar.gz | tar -xz
chmod +x mdbook
sudo mv mdbook /usr/local/bin/
- name: Install mdbook-htmx
run: |
cargo install mdbook-htmx
- name: Build documentation
run: mdbook build
- name: Deploy to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: my-docs
directory: book
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.head_ref || github.ref_name }}
```
## Custom Domain Setup
1. In Cloudflare Dashboard → Pages → your-project → Custom domains
2. Add domain: `docs.example.com`
3. DNS will be configured automatically if domain is on Cloudflare
## Redirects
Create `book/_redirects` for URL handling:
```
# Redirect old paths
/old-page /new-page 301
# SPA fallback (if needed)
/* /index.html 200
```
## Headers
Create `book/_headers` for custom response headers:
```
# All pages
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
# Cache static assets
/assets/*
Cache-Control: public, max-age=31536000, immutable
# Don't cache HTML
/*.html
Cache-Control: public, max-age=0, must-revalidate
```
## Performance Optimization
### Enable Brotli Compression
Cloudflare automatically compresses responses. Ensure it's enabled:
1. Dashboard → your-domain → Speed → Optimization
2. Enable "Brotli"
### Image Optimization
Use Cloudflare Image Resizing for dynamic image optimization:
```html
```
## Monitoring
### Web Analytics
Enable Cloudflare Web Analytics (privacy-friendly):
```html
```
### Page Views in Dashboard
View analytics at: Dashboard → Pages → your-project → Analytics
## Cost
- **Free tier**: Unlimited requests, 500 builds/month
- **Pro**: $20/month for advanced features
## Limitations
- No server-side rendering
- No authentication (use cf-workers-d1 for auth)
- No server-side search (client-side only)
- Build output limited to 25,000 files, 25 MB per file
## Next Steps
- Add [authentication with Workers](./cf-workers-d1.md)
- Set up [Meilisearch for server-side search](./meilisearch-cf-tunnel.md)
- Configure [KV caching](./cf-workers-kv-cache.md)
Contributor guide
Assessment
This issue has not been assessed yet.