Static campaign website built with Eleventy, deployed on Cloudflare Pages with Cloudflare Workers for edge API handling.
- Generator: Eleventy (11ty) v3.1.2
- Template Engine: Liquid (HTML), Nunjucks (feeds), Markdown (blog posts)
- Source Directory:
src/ - Output Directory:
_site/ - Data Layer: JSON files in
src/_data/for site metadata and California county registrar information
Modular CSS with a granular per-page optimization pipeline:
styles/
├── base/ (variables, reset, typography, animations)
├── components/ (header, footer, buttons, cards, forms, social)
├── layout/ (grid, sections, responsive)
├── pages/ (page-specific styles)
└── utils/ (helpers, dark-mode)
Build Process:
- PostCSS imports all modules via
styles/main.css - cssnano minifies and removes comments
- Global CSS written to
dist/styles.min.css - PurgeCSS generates per-page CSS files in
_site/dist/page-css/ - Each HTML file's stylesheet link is rewritten to its own purged CSS
This eliminates unused CSS on every page, reducing payload sizes significantly.
Vanilla JavaScript with no framework dependencies:
src/js/script.js- global utilities, dark mode, navigationsrc/js/ballot-petition.js- petition signature collectionsrc/js/declaration-interactive.js- declaration signing interfacesrc/js/shop.js- e-commerce frontend (cart, checkout handoff)
worker.js handles server-side logic:
API Endpoints:
/api/sign-declaration- Signature collection with rate limiting (24h/IP), sanitization, metadata capture/api/declaration-stats- Public stats retrieval (signature count, counties, list)/api/admin/edit-signature- Admin signature editing (requires Bearer auth)/api/admin/remove-signature- Admin signature removal (requires Bearer auth)/api/cart-handoff- Cart data handoff to WooCommerce with HMAC signature/api/shop/*- Proxy to WooCommerce REST API with Basic auth/api/shop/printful/order- Proxy to Printful API with Bearer auth
Storage: Cloudflare KV for:
- Signature data (
signatures_list,total_signatures) - County tracking (
counties_list,counties_represented) - Rate limiting (
rate_limit:{ip}) - IP tracking (
ip_county:{ip},ip_sign_count:{ip})
Security:
- CORS with strict origin whitelist
- XSS prevention via HTML escaping on all user input
- Rate limiting (1 signature per IP per 24h)
- County consistency enforcement (IP can't sign for multiple counties)
- Admin endpoints require Bearer token authentication
- Metadata logging (IP, user-agent, geolocation, device type) for fraud detection
Full build process (npm run build):
- CSS Compilation: PostCSS processes
styles/main.css→dist/styles.min.css - Site Generation: Eleventy builds HTML from
src/→_site/ - Font Awesome Localization: Inlines FA icons used in HTML
- Global PurgeCSS: Removes unused CSS from base stylesheet
- EXIF Stripping: Strips metadata from images, optimizes with Sharp
- Image Localization: Downloads external images to local resources
- Script Localization: Inlines external scripts
- Asset Fingerprinting: Generates content-hash filenames for cache busting
- Per-Page CSS: Generates and links individual purged CSS per HTML file
- Inline Small CSS: Inlines small CSS files directly into HTML
- Blog Thumbnail Fix: Ensures blog post thumbnails exist
- Precompression: Generates Brotli (.br) and Gzip (.gz) for all text assets
- Library: Sharp
- Formats: JPEG (mozjpeg, q82), PNG (level 9), WebP (q75), AVIF (q50)
- Process: EXIF stripping, chroma subsampling, palette optimization
- WebP Conversion: Automatic WebP generation for all raster images
Precompression:
- Brotli (quality 11) and Gzip (level 9) for HTML, CSS, JS, JSON, XML, SVG
- Served via content negotiation on Cloudflare
Cache Strategy (via _headers):
- HTML:
no-cache, must-revalidate(always fresh) - Feeds:
no-cache, must-revalidate - Assets (
/dist/*,/js/*,/resources/*):max-age=31536000, immutable(1 year) - Sitemap:
max-age=3600(1 hour)
Asset Fingerprinting:
- SHA-1 hash (8 chars) appended to CSS/JS filenames
- Automatic HTML reference updates
- Forces cache invalidation on content changes
Per-Page CSS:
- PurgeCSS scans each HTML + all JS files
- Generates minimal CSS containing only used selectors
- Safelist for dynamic classes (Font Awesome, active states, dropdowns)
Configured in _headers:
Content-Security-Policy: Strict CSP with explicit allowlistsX-Frame-Options: SAMEORIGINX-Content-Type-Options: nosniffStrict-Transport-Security: HSTS with preloadCross-Origin-Opener-Policy: same-originCross-Origin-Resource-Policy: cross-originPermissions-Policy: Blocks camera, microphone, geolocation, browsing-topics
- Markdown source files in
src/blog/*.md - Eleventy collections:
posts,postsSorted - Custom filters:
readableDate,htmlDateString,rfc822Date,isoDateString,striptags,urlencode - RSS feed (
feed.xml) and JSON Feed (feed.json) - Post layout template:
src/_includes/post.html
src/_data/site.json- Site metadata (title, author, feed paths)src/_data/registrars.json- California county registrar information (642 lines)
Core:
@11ty/eleventy^3.1.2 - Static site generatorpostcss^8.4.31 - CSS processingcssnano^7.1.0 - CSS minificationpurgecss^7.0.2 - Unused CSS removalsharp^0.34.5 - Image processing
Utilities:
luxon^3.7.1 - Date/time handlinghttp-server^14.1.1 - Local development serverrimraf^6.0.1 - Cross-platform file removal
Commands:
npm run dev # Build CSS + Eleventy dev server (with watch)
npm run serve # Same as dev
npm run build # Full production build with all optimizations
npm run build:clean # Clean _site/ then full build
npm run build:css # CSS compilation only
npm run build:eleventy # Eleventy build only
npm run serve:built # Build then serve on port 8082
npm run watch # Watch CSS changes
npm run clean # Remove _site/Dev Server: Eleventy serves on http://localhost:8080 with live reload
Platform: Cloudflare Pages
- Build command:
npm run build - Publish directory:
_site - Environment variables required:
ADMIN_KEY- Admin API authenticationWC_USER/WC_PASS- WooCommerce API credentialsPRINTFUL_KEY- Printful API tokenHANDOFF_SECRET- Cart handoff HMAC secret
Worker Bindings:
DECLARATION_KV- KV namespace for signature data
├── src/ # Eleventy source
│ ├── _data/ # JSON data files
│ ├── _includes/ # Layout templates
│ ├── blog/ # Markdown blog posts
│ ├── js/ # Client-side JavaScript
│ ├── shop/ # Shop product templates
│ └── *.html # Page templates
├── styles/ # Modular CSS source
├── scripts/ # Build pipeline scripts
├── resources/ # Images, PDFs, static assets
├── dist/ # Compiled CSS output
├── _site/ # Built site output (gitignored)
├── worker.js # Cloudflare Worker edge functions
├── .eleventy.js # Eleventy configuration
├── postcss.config.js # PostCSS configuration
├── purgecss.config.cjs # PurgeCSS safelist
├── _headers # HTTP headers for Cloudflare
└── package.json # Dependencies and build scripts
- Shop functionality integrates with external WooCommerce instance via API proxy
- Worker acts as middleware for authentication and CORS
- All user-generated content is sanitized server-side to prevent XSS
- IP-based rate limiting prevents spam/abuse on signature collection
- Geolocation and device fingerprinting via Cloudflare's request object
- Blog post dates handled in UTC via Luxon
- Responsive design without CSS frameworks (custom grid/flexbox)
- Dark mode toggle persists via localStorage
- No external CDN dependencies (all assets localized during build)
Licensed under the Liberty-ShareAlike Public License (LSA-1.0). You may use, share, and adapt this material for any purpose. If you distribute adaptations, you must license them under LSA-1.0 and include the full license text or a stable link to it. No attribution is required. No additional restrictions or DRM may be applied.