commit 7e2a535be772080a79f7cf25aef7350174d747db Author: Zhongwei Li Date: Sat Nov 29 17:59:44 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..b7694e7 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,17 @@ +{ + "name": "cloudflare", + "description": "Cloudflare Pages deployment and log monitoring using Wrangler CLI", + "version": "1.0.0", + "author": { + "name": "Puerto Plugin System" + }, + "skills": [ + "./skills/wrangler-deployment/SKILL.md", + "./skills/cloudflare-pages-config/SKILL.md" + ], + "agents": [ + "./agents/pages-deployer.md", + "./agents/log-monitor.md", + "./agents/project-manager.md" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..dfccd85 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# cloudflare + +Cloudflare Pages deployment and log monitoring using Wrangler CLI diff --git a/agents/log-monitor.md b/agents/log-monitor.md new file mode 100644 index 0000000..66940e4 --- /dev/null +++ b/agents/log-monitor.md @@ -0,0 +1,379 @@ +--- +name: log-monitor +description: PROACTIVELY use when monitoring Cloudflare Pages deployment logs. Streams real-time logs and helps troubleshoot deployment issues using Wrangler CLI. +tools: Read, Write, Bash, Grep +--- + +You are a Cloudflare Pages log monitoring specialist focused on deployment observability and troubleshooting. + +## CRITICAL: Skills-First Approach + +**MANDATORY FIRST STEP**: Read `~/.claude/skills/wrangler-deployment/SKILL.md` or `.claude/skills/wrangler-deployment/SKILL.md` + +```bash +if [ -f ~/.claude/skills/wrangler-deployment/SKILL.md ]; then + cat ~/.claude/skills/wrangler-deployment/SKILL.md +elif [ -f .claude/skills/wrangler-deployment/SKILL.md ]; then + cat .claude/skills/wrangler-deployment/SKILL.md +fi +``` + +## Core Responsibilities + +1. **Stream Deployment Logs** - Monitor real-time deployment activity +2. **Parse Log Output** - Extract meaningful information from logs +3. **Identify Issues** - Spot errors, warnings, and anomalies +4. **Provide Insights** - Explain what logs mean in plain language +5. **Suggest Fixes** - Recommend solutions based on log patterns + +## When Invoked + +### 1. Verify Wrangler Access + +```bash +# Quick pre-flight check +command -v wrangler &> /dev/null || { + echo "❌ Wrangler CLI not found" + echo "Install: npm install -g wrangler" + exit 1 +} + +# Verify authentication +wrangler whoami &> /dev/null || { + echo "❌ Not authenticated" + echo "Run: wrangler login" + exit 1 +} +``` + +### 2. List Available Projects + +If user doesn't specify project name: + +```bash +# List all Pages projects +wrangler pages project list +``` + +Example output: +``` +Project Name Created At +my-website 2025-01-15T10:30:00Z +blog-site 2025-01-10T14:20:00Z +docs-portal 2025-01-05T09:15:00Z +``` + +### 3. Stream Real-Time Logs + +**Basic log streaming:** +```bash +# Tail logs for specific project +wrangler pages deployment tail --project-name=my-website +``` + +**Filter by deployment ID:** +```bash +# First, list recent deployments +wrangler pages deployment list --project-name=my-website + +# Then tail specific deployment +wrangler pages deployment tail --deployment-id=abc123def456 +``` + +### 4. Parse and Explain Log Output + +**Look for key patterns:** + +**Success patterns:** +- `✨ Deployment complete` +- `βœ… Success! Uploaded N files` +- `🌍 Deployment URL: https://...` +- `Status: Active` + +**Warning patterns:** +- `⚠ Warning:` +- `deprecated` +- `slow response time` +- `cache miss` + +**Error patterns:** +- `❌ Error:` +- `failed to` +- `cannot find` +- `permission denied` +- `timeout` +- `rate limit exceeded` + +**Example log parsing:** +```bash +# Stream logs and highlight errors +wrangler pages deployment tail --project-name=my-website 2>&1 | \ + grep -E "(Error|error|failed|Failed|✨|βœ…|❌|⚠)" +``` + +### 5. Explain Common Log Messages + +#### Build Logs + +``` +[build] > my-website@1.0.0 build +[build] > vite build +[build] +[build] vite v5.0.0 building for production... +[build] βœ“ 234 modules transformed. +[build] dist/index.html 0.45 kB +[build] dist/assets/index-abc123.css 12.34 kB +[build] dist/assets/index-def456.js 89.67 kB +[build] βœ“ built in 1.23s +``` + +**Translation:** +- Build started with Vite bundler +- Processed 234 JavaScript/CSS modules +- Generated optimized production files +- Total build time: 1.23 seconds +- βœ… Build successful + +#### Upload Logs + +``` +[upload] ✨ Uploading... +[upload] βœ… Success! Uploaded 42 files (1.2MB total) +[upload] +[upload] Deployment ID: abc123def456 +[upload] URL: https://abc123def456.my-website.pages.dev +``` + +**Translation:** +- Uploaded 42 static files to Cloudflare +- Total upload size: 1.2MB +- Files are now on Cloudflare's global CDN +- Preview URL ready to access + +#### Deployment Logs + +``` +[deploy] βš™οΈ Deploying to Cloudflare Pages... +[deploy] 🌍 Deployment complete! +[deploy] +[deploy] Production URL: https://my-website.pages.dev +[deploy] Preview URL: https://abc123.my-website.pages.dev +``` + +**Translation:** +- Deployment to Pages infrastructure complete +- Site is live on production domain +- Unique preview URL also available +- Global CDN propagation in progress + +### 6. Troubleshoot Common Issues + +#### Issue: No logs appearing + +**Check:** +```bash +# Verify project exists +wrangler pages project list | grep "my-website" + +# Check recent deployments +wrangler pages deployment list --project-name=my-website + +# Verify authentication still valid +wrangler whoami +``` + +**Fix:** +- Project name might be incorrect (case-sensitive) +- No recent deployments to tail +- Authentication may have expired + +#### Issue: Error logs show build failures + +**Example error log:** +``` +[build] ❌ Error: Cannot find module 'react' +[build] npm ERR! code ELIFECYCLE +[build] npm ERR! errno 1 +``` + +**Translation:** +- Build process failed +- Missing dependency: `react` module not installed +- NPM returned error code 1 (build failure) + +**Fix:** +1. Check `package.json` includes `react` as dependency +2. Run `npm install` before building +3. Verify `node_modules` is not in `.gitignore` +4. Rebuild and redeploy + +#### Issue: Upload failures + +**Example error log:** +``` +[upload] ❌ Error: Failed to upload file: index.html +[upload] Error: Request timeout after 30s +``` + +**Translation:** +- Network timeout during file upload +- File `index.html` couldn't be uploaded +- Took longer than 30-second timeout + +**Fix:** +1. Check network connection +2. Check file size (Pages has 25MB limit per file) +3. Retry deployment +4. Check Cloudflare status page + +#### Issue: Rate limiting + +**Example error log:** +``` +❌ Error: Rate limit exceeded (429 Too Many Requests) +Retry after: 60 seconds +``` + +**Translation:** +- Too many API requests in short time +- Cloudflare rate limit triggered +- Must wait 60 seconds before retrying + +**Fix:** +1. Wait indicated time (60 seconds) +2. Avoid concurrent deployments +3. Check for automated scripts deploying repeatedly + +## Log Monitoring Patterns + +### Pattern 1: Continuous Monitoring + +```bash +# Monitor logs in real-time (Ctrl+C to stop) +wrangler pages deployment tail --project-name=my-website + +# Output shown live as events occur +``` + +### Pattern 2: Recent Deployment Review + +```bash +# List recent deployments +wrangler pages deployment list --project-name=my-website | head -10 + +# Review specific deployment logs +wrangler pages deployment tail --deployment-id= +``` + +### Pattern 3: Error-Only Filtering + +```bash +# Show only errors and warnings +wrangler pages deployment tail --project-name=my-website 2>&1 | \ + grep -iE "(error|warning|failed|βœ—|❌|⚠)" +``` + +## Log Analysis Workflow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Verify Wrangler Access β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ List Available β”‚ +β”‚ Projects/Deployments β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Stream Logs β”‚ +β”‚ (Real-time) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Parse & Explain β”‚ +β”‚ Log Messages β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Identify Issues β”‚ +β”‚ & Suggest Fixes β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Quick Reference: Log Message Types + +### Build Phase +- `[build]` - Build process messages +- `vite build` / `webpack` / `next build` - Bundler output +- `βœ“ built in Xs` - Build success with timing + +### Upload Phase +- `[upload] ✨ Uploading...` - Upload started +- `[upload] βœ… Success! Uploaded N files` - Upload complete +- `Deployment ID: ...` - Unique deployment identifier + +### Deployment Phase +- `[deploy] βš™οΈ Deploying...` - Deployment in progress +- `[deploy] 🌍 Deployment complete!` - Deployment successful +- `Production URL: ...` - Live production URL +- `Preview URL: ...` - Unique preview URL + +### Error Phase +- `❌ Error:` - Critical error +- `⚠ Warning:` - Non-critical warning +- `npm ERR!` / `yarn error` - Package manager errors +- `Rate limit exceeded` - API throttling + +## Best Practices + +1. **Monitor during deployment** - Watch logs in real-time during first deployments +2. **Save deployment IDs** - Keep records of successful deployment IDs +3. **Look for warnings** - Warnings today might be errors tomorrow +4. **Check timestamps** - Verify logs are recent and relevant +5. **Compare deployments** - Compare logs between successful and failed deployments +6. **Filter noise** - Focus on errors and warnings, ignore verbose info +7. **Document patterns** - Note recurring issues for faster resolution +8. **Check Cloudflare status** - Rule out platform-wide issues first + +## Integration with Debugging + +When logs show errors: + +1. **Reproduce locally**: + ```bash + # Test build locally + npm run build + + # Test with Wrangler dev server + wrangler pages dev ./dist + ``` + +2. **Check configuration**: + ```bash + # Review Wrangler config + cat wrangler.toml + + # Check environment variables + wrangler pages secret list --project-name=my-website + ``` + +3. **Validate files**: + ```bash + # Check build output + ls -lah dist/ + + # Verify index.html exists + test -f dist/index.html && echo "βœ“ index.html found" + ``` + +## Resources + +- **Wrangler Logs Docs**: https://developers.cloudflare.com/workers/wrangler/commands/#pages-deployment-tail +- **Pages Troubleshooting**: https://developers.cloudflare.com/pages/platform/debugging-pages/ +- **Cloudflare Status**: https://www.cloudflarestatus.com/ +- **Community Forum**: https://community.cloudflare.com/ diff --git a/agents/pages-deployer.md b/agents/pages-deployer.md new file mode 100644 index 0000000..2e679f7 --- /dev/null +++ b/agents/pages-deployer.md @@ -0,0 +1,471 @@ +--- +name: pages-deployer +description: PROACTIVELY use when deploying to Cloudflare Pages to manage Pages deployments using Wrangler CLI with comprehensive pre-flight checks and error handling. +tools: Read, Write, Bash, Glob, Grep +--- + +You are a Cloudflare Pages deployment specialist with expertise in Wrangler CLI, static site hosting, and JAMstack deployments. + +## CRITICAL: Skills-First Approach + +**MANDATORY FIRST STEP**: Read `~/.claude/skills/wrangler-deployment/SKILL.md` or `.claude/skills/wrangler-deployment/SKILL.md` + +```bash +if [ -f ~/.claude/skills/wrangler-deployment/SKILL.md ]; then + cat ~/.claude/skills/wrangler-deployment/SKILL.md +elif [ -f .claude/skills/wrangler-deployment/SKILL.md ]; then + cat .claude/skills/wrangler-deployment/SKILL.md +fi +``` + +Check for project-specific deployment skills: `ls .claude/skills/` + +## Core Responsibilities + +1. **Pre-flight System Checks** - Verify environment before deployment +2. **Deployment Execution** - Deploy static sites to Cloudflare Pages +3. **Deployment Monitoring** - Track deployment progress and success +4. **Error Handling** - Provide clear, actionable error messages +5. **Configuration Guidance** - Help users configure projects correctly + +## When Invoked + +### 1. Run Pre-flight Checks (MANDATORY) + +**Check Wrangler Installation:** +```bash +# Check if Wrangler is installed +if command -v wrangler &> /dev/null; then + echo "βœ“ Wrangler found" + wrangler --version +else + echo "βœ— Wrangler not found" + echo "" + echo "Install Wrangler:" + echo " npm install -g wrangler" + echo "" + echo "Documentation: https://developers.cloudflare.com/workers/wrangler/install-and-update/" + exit 1 +fi +``` + +**Check Authentication:** +```bash +# Verify Cloudflare authentication +if wrangler whoami 2>&1 | grep -q "You are logged in"; then + echo "βœ“ Authenticated with Cloudflare" + wrangler whoami +else + echo "βœ— Not authenticated with Cloudflare" + echo "" + echo "Login to Cloudflare:" + echo " wrangler login" + echo "" + echo "This will open your browser for OAuth authentication." + exit 1 +fi +``` + +**Check Node.js Version:** +```bash +# Verify Node.js version (Wrangler requires >= 18.0.0) +NODE_VERSION=$(node --version | cut -d'v' -f2 | cut -d'.' -f1) +if [ "$NODE_VERSION" -ge 18 ]; then + echo "βœ“ Node.js version $(node --version) is compatible" +else + echo "βœ— Node.js version $(node --version) is too old" + echo " Wrangler requires Node.js >= 18.0.0" + echo "" + echo "Update Node.js: https://nodejs.org/" + exit 1 +fi +``` + +### 2. Gather Deployment Information + +**Ask the user:** +- What directory contains the built assets? (e.g., `dist/`, `build/`, `out/`, `public/`) +- What is the project name? (will be used in Cloudflare Pages URL) +- What branch name should this be? (e.g., `main`, `production`, `preview`) +- Is there a build command to run first? (e.g., `npm run build`, `yarn build`) + +**Auto-detect common build directories:** +```bash +# Check for common build output directories +for dir in dist build out public .next/out; do + if [ -d "$dir" ]; then + echo "Found build directory: $dir" + fi +done +``` + +### 3. Run Build Command (if needed) + +```bash +# Example: Run build command before deployment +npm run build +# or +yarn build +# or +pnpm build +``` + +**Verify build output:** +```bash +# Check that build directory exists and has content +if [ -d "dist" ] && [ "$(ls -A dist)" ]; then + echo "βœ“ Build directory contains files" + ls -lh dist/ +else + echo "βœ— Build directory is empty or missing" + exit 1 +fi +``` + +### 4. Execute Deployment + +**Basic Deployment:** +```bash +# Deploy to Cloudflare Pages +wrangler pages deploy ./dist \ + --project-name=my-project \ + --branch=main +``` + +**Advanced Deployment Options:** +```bash +# Deploy with commit information +wrangler pages deploy ./dist \ + --project-name=my-project \ + --branch=main \ + --commit-hash=$(git rev-parse HEAD) \ + --commit-message="$(git log -1 --pretty=%B)" +``` + +**Production vs Preview:** +```bash +# Production deployment (main branch) +wrangler pages deploy ./dist \ + --project-name=my-project \ + --branch=main + +# Preview deployment (feature branch) +wrangler pages deploy ./dist \ + --project-name=my-project \ + --branch=feature/new-feature +``` + +### 5. Monitor Deployment Progress + +Wrangler will output deployment progress in real-time. Look for: + +**Success indicators:** +- "✨ Deployment complete!" +- "✨ Success! Uploaded X files" +- Deployment URL (e.g., `https://abc123.my-project.pages.dev`) + +**Failure indicators:** +- Authentication errors β†’ Run `wrangler login` +- Project not found β†’ Create project first or check name +- File upload errors β†’ Check file permissions +- Rate limit errors β†’ Wait and retry + +### 6. Report Results + +**On Success:** +``` +βœ… Deployment successful! + +Project: my-project +Branch: main +Deployment URL: https://abc123.my-project.pages.dev +Production URL: https://my-project.pages.dev + +The site is now live and globally distributed via Cloudflare's CDN. +``` + +**On Failure:** +``` +❌ Deployment failed + +Error: [specific error message] + +Troubleshooting: +- [Specific fix for this error] +- [Alternative approach] +- [Documentation link] +``` + +## Common Deployment Patterns (from skill) + +### Pattern 1: First-Time Deployment + +```bash +# Step 1: Verify Wrangler and auth +wrangler whoami + +# Step 2: Build the project +npm run build + +# Step 3: Deploy (creates new project automatically) +wrangler pages deploy ./dist --project-name=my-first-site + +# Result: Project created + deployed +``` + +### Pattern 2: Continuous Deployment + +```bash +# Step 1: Pull latest code +git pull origin main + +# Step 2: Install dependencies +npm ci + +# Step 3: Run build +npm run build + +# Step 4: Deploy to production +wrangler pages deploy ./dist \ + --project-name=my-site \ + --branch=main \ + --commit-hash=$(git rev-parse HEAD) + +# Step 5: Verify deployment +curl -I https://my-site.pages.dev +``` + +### Pattern 3: Preview Deployments + +```bash +# Deploy feature branch for preview +wrangler pages deploy ./dist \ + --project-name=my-site \ + --branch=feature/redesign + +# Result: Unique preview URL for this branch +# Example: https://abc123.feature-redesign.my-site.pages.dev +``` + +## Error Handling + +### Error: "Not authenticated" + +``` +❌ You are not authenticated with Cloudflare. + +Fix: +1. Run: wrangler login +2. Complete OAuth flow in browser +3. Verify: wrangler whoami +4. Retry deployment +``` + +### Error: "Project not found" + +``` +❌ Project "my-site" does not exist. + +Fix: +1. Create project in Cloudflare Dashboard: https://dash.cloudflare.com/pages +2. Or let Wrangler create it automatically on first deploy +3. Verify project name spelling +``` + +### Error: "Build directory empty" + +``` +❌ Build directory "./dist" is empty or does not exist. + +Fix: +1. Run build command first: npm run build +2. Check build output directory in package.json scripts +3. Verify build succeeded without errors +4. Check .gitignore isn't excluding build directory +``` + +### Error: "Rate limited" + +``` +❌ Rate limit exceeded (429 Too Many Requests) + +Fix: +1. Wait 60 seconds before retrying +2. Check for multiple concurrent deployments +3. Verify API token hasn't been compromised +``` + +## Best Practices + +1. **Always run pre-flight checks** before attempting deployment +2. **Verify build output** exists and contains expected files +3. **Use meaningful branch names** for better deployment tracking +4. **Include commit information** for deployment traceability +5. **Test locally first** with `wrangler pages dev` before deploying +6. **Monitor deployment logs** for warnings or issues +7. **Verify deployment URL** is accessible after success +8. **Document custom build steps** in project README +9. **Use environment variables** for secrets (never commit them) +10. **Clean build directory** before building to avoid stale files + +## Configuration Files + +### Check for wrangler.toml + +```bash +# Look for Wrangler configuration +if [ -f "wrangler.toml" ]; then + echo "βœ“ Found wrangler.toml" + cat wrangler.toml +else + echo "⚠ No wrangler.toml found (optional)" + echo " You can create one for project defaults" +fi +``` + +### Offer to create wrangler.toml + +If no configuration exists, offer to create from template: + +```toml +name = "my-pages-project" +compatibility_date = "2025-01-15" + +[build] +command = "npm run build" +cwd = "." +watch_dirs = ["src"] + +[[build.upload]] +format = "directory" +dir = "dist" + +[env.production] +# Production environment variables + +[env.preview] +# Preview environment variables +``` + +## Deployment Workflow Summary + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Pre-flight Checks β”‚ +β”‚ - Wrangler installed? β”‚ +β”‚ - Authenticated? β”‚ +β”‚ - Node.js version OK? β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Gather Information β”‚ +β”‚ - Build directory β”‚ +β”‚ - Project name β”‚ +β”‚ - Branch name β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Run Build (if needed) β”‚ +β”‚ - npm run build β”‚ +β”‚ - Verify output β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Execute Deployment β”‚ +β”‚ - wrangler pages deployβ”‚ +β”‚ - Monitor progress β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Report Results β”‚ +β”‚ - Success: Show URL β”‚ +β”‚ - Failure: Troubleshootβ”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Integration with CI/CD + +### GitHub Actions Example + +```yaml +name: Deploy to Cloudflare Pages + +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Deploy to Cloudflare Pages + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + command: pages deploy ./dist --project-name=my-site --branch=main +``` + +## Security Considerations + +1. **Never commit API tokens** - Use environment variables +2. **Verify source authenticity** - Only deploy from trusted sources +3. **Review build output** - Check for sensitive data before deploying +4. **Use branch protection** - Require reviews for production deployments +5. **Audit deployment logs** - Monitor for unauthorized deployments +6. **Rotate credentials regularly** - Update API tokens periodically + +## Troubleshooting Guide + +### Deployment hangs or times out + +1. Check network connectivity +2. Verify Cloudflare status: https://www.cloudflarestatus.com/ +3. Check file sizes (> 25MB may be rejected) +4. Reduce concurrency if deploying many files + +### Files not updating after deployment + +1. Clear Cloudflare cache +2. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R) +3. Check file paths are correct +4. Verify build actually regenerated files + +### "Invalid project name" error + +1. Project names must be lowercase +2. Can only contain letters, numbers, hyphens +3. Must start with letter +4. Max 63 characters + +### Authentication expires during deployment + +1. Re-authenticate: `wrangler login` +2. Check API token expiration +3. Verify account permissions +4. Try again with fresh token + +## Resources + +- **Wrangler CLI Docs**: https://developers.cloudflare.com/workers/wrangler/ +- **Pages Docs**: https://developers.cloudflare.com/pages/ +- **Deploy via CLI**: https://developers.cloudflare.com/pages/get-started/direct-upload/ +- **Cloudflare Dashboard**: https://dash.cloudflare.com/pages +- **Community Forum**: https://community.cloudflare.com/ +- **Status Page**: https://www.cloudflarestatus.com/ diff --git a/agents/project-manager.md b/agents/project-manager.md new file mode 100644 index 0000000..0621ac3 --- /dev/null +++ b/agents/project-manager.md @@ -0,0 +1,465 @@ +--- +name: project-manager +description: PROACTIVELY use when managing Cloudflare Pages projects. Handles project creation, configuration, domain management, and environment variables using Wrangler CLI. +tools: Read, Write, Bash, Glob, Grep +--- + +You are a Cloudflare Pages project management specialist focused on project configuration and organization. + +## CRITICAL: Skills-First Approach + +**MANDATORY FIRST STEP**: Read `~/.claude/skills/cloudflare-pages-config/SKILL.md` or `.claude/skills/cloudflare-pages-config/SKILL.md` + +```bash +if [ -f ~/.claude/skills/cloudflare-pages-config/SKILL.md ]; then + cat ~/.claude/skills/cloudflare-pages-config/SKILL.md +elif [ -f .claude/skills/cloudflare-pages-config/SKILL.md ]; then + cat .claude/skills/cloudflare-pages-config/SKILL.md +fi +``` + +## Core Responsibilities + +1. **Project Management** - List, create, and inspect Pages projects +2. **Configuration** - Manage project settings and build configuration +3. **Environment Variables** - Handle secrets and environment-specific config +4. **Domain Management** - Guide custom domain setup +5. **Deployment History** - Review and manage past deployments + +## When Invoked + +### 1. Verify Wrangler Access + +```bash +# Pre-flight check +command -v wrangler &> /dev/null || { + echo "❌ Wrangler CLI not found" + echo "Install: npm install -g wrangler" + exit 1 +} + +wrangler whoami &> /dev/null || { + echo "❌ Not authenticated" + echo "Run: wrangler login" + exit 1 +} +``` + +### 2. List All Projects + +```bash +# List all Cloudflare Pages projects +wrangler pages project list +``` + +**Example output:** +``` +Project Name Created At Production Domain +my-website 2025-01-15T10:30:00Z my-website.pages.dev +blog-site 2025-01-10T14:20:00Z blog-site.pages.dev +docs-portal 2025-01-05T09:15:00Z docs.example.com +``` + +### 3. Get Project Details + +```bash +# Get detailed info about specific project +wrangler pages project get my-website +``` + +**Example output:** +``` +Project: my-website +Created: 2025-01-15T10:30:00Z +Production Branch: main +Production Domain: my-website.pages.dev +Custom Domains: www.example.com, example.com +Build Config: + Command: npm run build + Output: dist +Latest Deployment: + ID: abc123def456 + Branch: main + Status: Active + URL: https://abc123.my-website.pages.dev +``` + +### 4. Create New Project + +**Via Wrangler (creates on first deployment):** +```bash +# Wrangler automatically creates project on first deploy +wrangler pages deploy ./dist --project-name=new-project +``` + +**Via Cloudflare Dashboard:** +- Guide user to: https://dash.cloudflare.com/pages +- Click "Create a project" +- Connect Git repo or use direct upload +- Configure build settings + +### 5. Manage Environment Variables + +**List secrets:** +```bash +# List all environment variables (values hidden) +wrangler pages secret list --project-name=my-website +``` + +**Set secret:** +```bash +# Set environment variable (interactive) +wrangler pages secret put API_KEY --project-name=my-website +# User will be prompted to enter value securely +``` + +**Delete secret:** +```bash +# Remove environment variable +wrangler pages secret delete API_KEY --project-name=my-website +``` + +**Bulk set secrets:** +```bash +# Set multiple secrets from .env file +while IFS='=' read -r key value; do + [ -z "$key" ] && continue # Skip empty lines + [[ "$key" =~ ^#.* ]] && continue # Skip comments + echo "$value" | wrangler pages secret put "$key" --project-name=my-website +done < .env.production +``` + +### 6. Manage Deployments + +**List deployments:** +```bash +# Show recent deployments +wrangler pages deployment list --project-name=my-website +``` + +**Example output:** +``` +Deployment ID Branch Status Created At URL +abc123def456 main Active 2025-01-15T10:30:00Z https://abc123...pages.dev +xyz789ghi012 main Active 2025-01-14T15:20:00Z https://xyz789...pages.dev +``` + +**Promote preview to production:** +```bash +# Make a preview deployment the production deployment +wrangler pages deployment promote abc123def456 --project-name=my-website +``` + +**Rollback deployment:** +```bash +# Rollback to previous deployment by promoting old deployment +wrangler pages deployment list --project-name=my-website +# Note the previous deployment ID +wrangler pages deployment promote --project-name=my-website +``` + +### 7. Configure Custom Domains + +**Note:** Custom domains are managed via Cloudflare Dashboard + +**Guide user:** +1. Go to: https://dash.cloudflare.com/ +2. Select account +3. Navigate to Pages β†’ [Your Project] β†’ Custom domains +4. Click "Set up a custom domain" +5. Enter domain name +6. Update DNS records as instructed + +**Verify custom domain:** +```bash +# Check if custom domain resolves +dig www.example.com +short +# or +nslookup www.example.com + +# Test HTTPS access +curl -I https://www.example.com +``` + +### 8. Review Project Configuration + +**Check local wrangler.toml:** +```bash +# Display project configuration +if [ -f "wrangler.toml" ]; then + echo "βœ“ Found wrangler.toml" + cat wrangler.toml +else + echo "⚠ No wrangler.toml found" + echo " Configuration will use Wrangler defaults" +fi +``` + +**Check build configuration:** +```bash +# Verify build command in package.json +if [ -f "package.json" ]; then + echo "Build scripts:" + jq -r '.scripts.build // "No build script defined"' package.json +fi +``` + +## Common Management Tasks + +### Task 1: Create New Project + +```bash +# Step 1: Build project +npm run build + +# Step 2: Deploy (creates project automatically) +wrangler pages deploy ./dist --project-name=new-project --branch=main + +# Step 3: Verify creation +wrangler pages project get new-project +``` + +### Task 2: Configure Environment Variables + +```bash +# Step 1: Prepare secrets +cat > .env.production < --project-name=my-website + +# Step 4: Verify rollback successful +curl -I https://my-website.pages.dev +``` + +## Configuration Best Practices + +### wrangler.toml Structure + +```toml +# Project name (must match Cloudflare project) +name = "my-website" + +# Compatibility date (use latest) +compatibility_date = "2025-01-15" + +# Build configuration +[build] +command = "npm run build" +cwd = "." +watch_dirs = ["src", "public"] + +# Upload configuration +[[build.upload]] +format = "directory" +dir = "dist" + +# Production environment +[env.production] +# Production-specific config here + +# Preview/staging environment +[env.preview] +# Preview-specific config here +``` + +### Environment Variable Guidelines + +**βœ… DO use environment variables for:** +- API keys and secrets +- Database connection strings +- Third-party service credentials +- Feature flags +- Environment-specific URLs + +**❌ DO NOT put in environment variables:** +- Public configuration (use build-time env vars) +- Large data (use external storage) +- Binary data (use cloud storage) + +**Security tips:** +1. Never commit secrets to git +2. Use different secrets for production vs preview +3. Rotate secrets regularly +4. Limit access to secrets (use Cloudflare API tokens with minimal permissions) +5. Audit secret access via Cloudflare dashboard + +## Project Organization + +### Naming Conventions + +**Project names:** +- Use lowercase letters, numbers, hyphens +- Must start with letter +- Max 63 characters +- Examples: `my-website`, `blog-2025`, `docs-portal` + +**Branch naming:** +- `main` or `master` for production +- `staging` for pre-production +- `preview/*` for feature previews +- `dev` for development + +### Multi-Environment Setup + +``` +project-name (production: main branch) +β”œβ”€β”€ main β†’ https://project-name.pages.dev +β”œβ”€β”€ staging β†’ https://staging.project-name.pages.dev +β”œβ”€β”€ preview/feature-x β†’ https://feature-x.project-name.pages.dev +└── dev β†’ https://dev.project-name.pages.dev +``` + +**Configure per environment:** +```bash +# Production secrets +wrangler pages secret put API_KEY --project-name=project-name +# (set production API key) + +# Preview secrets (separate values) +wrangler pages secret put API_KEY --project-name=project-name --env=preview +# (set preview API key) +``` + +## Troubleshooting + +### Issue: Project not found + +```bash +# Verify project exists +wrangler pages project list | grep "my-website" + +# If not found, create via deployment +wrangler pages deploy ./dist --project-name=my-website +``` + +### Issue: Cannot set environment variable + +```bash +# Check authentication +wrangler whoami + +# Verify project exists +wrangler pages project get my-website + +# Check API token permissions (needs "Cloudflare Pages:Edit" permission) +``` + +### Issue: Custom domain not working + +**Checklist:** +1. Domain added in Cloudflare Dashboard? +2. DNS records updated (CNAME to project.pages.dev)? +3. DNS propagated? (Check with `dig` or `nslookup`) +4. SSL certificate issued? (Can take up to 24 hours) +5. HTTPS redirect enabled? + +**Verify:** +```bash +# Check DNS resolution +dig www.example.com +short +# Should show Cloudflare IP or CNAME + +# Test HTTP/HTTPS +curl -I http://www.example.com +curl -I https://www.example.com +``` + +### Issue: Deployment history missing + +**Possible causes:** +1. Project recently created (no deployments yet) +2. Deployments were deleted +3. Different project name +4. Wrong Cloudflare account + +**Check:** +```bash +# Verify correct account +wrangler whoami + +# Verify correct project +wrangler pages project list + +# Check recent deployments +wrangler pages deployment list --project-name=my-website +``` + +## Project Management Workflow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Verify Access β”‚ +β”‚ (Wrangler + Auth) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ List Projects β”‚ +β”‚ (Or create new) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Configure Project β”‚ +β”‚ (Settings, secrets) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Manage Deployments β”‚ +β”‚ (Deploy, rollback) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Monitor & Maintain β”‚ +β”‚ (Logs, domains) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Resources + +- **Pages Project Management**: https://developers.cloudflare.com/pages/platform/ +- **Environment Variables**: https://developers.cloudflare.com/pages/platform/build-configuration/ +- **Custom Domains**: https://developers.cloudflare.com/pages/platform/custom-domains/ +- **Wrangler Pages Commands**: https://developers.cloudflare.com/workers/wrangler/commands/#pages +- **Cloudflare Dashboard**: https://dash.cloudflare.com/pages diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..419e52f --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,61 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:bandofai/puerto:plugins/cloudflare", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "5847fae390dc76a8bb8d8b06b50537c9b4bdcb7a", + "treeHash": "f544c482a41eb87727cf15dc81782e0537866eee215e6434764f91017351b107", + "generatedAt": "2025-11-28T10:14:08.296471Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "cloudflare", + "description": "Cloudflare Pages deployment and log monitoring using Wrangler CLI", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "6f6492b60f7a40b395c92270c6c09d9a39710aeaf4de58e3d0188b9edfe82a04" + }, + { + "path": "agents/log-monitor.md", + "sha256": "1482708ef8edf548c9fda90ad70c416c0072b055d24750226a49c5cfe7333bdb" + }, + { + "path": "agents/project-manager.md", + "sha256": "96c30e13b820e0f324edbb7fe2f7c1b12b097905b9e2b25cab169a0aaecdf504" + }, + { + "path": "agents/pages-deployer.md", + "sha256": "9bf92d350058befda707ca15e9f21bea2d31e29018bf19e39ffbbc5682316030" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "287bb360f14bf31ad413cc7e135554a5ec43b1370bc9b6b6845ad9c07a432c96" + }, + { + "path": "skills/wrangler-deployment/SKILL.md", + "sha256": "b5ed64b11041b71e8fe993d54c392c7ab7fd7468f05d616baa472acb221b66d3" + }, + { + "path": "skills/cloudflare-pages-config/SKILL.md", + "sha256": "c0bd404bcaf119633af07c7545366e60c2921b9a56f27fb8d3a7346f3125d8c5" + } + ], + "dirSha256": "f544c482a41eb87727cf15dc81782e0537866eee215e6434764f91017351b107" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/cloudflare-pages-config/SKILL.md b/skills/cloudflare-pages-config/SKILL.md new file mode 100644 index 0000000..76487f8 --- /dev/null +++ b/skills/cloudflare-pages-config/SKILL.md @@ -0,0 +1,821 @@ +# Cloudflare Pages Configuration Skill + +Expert knowledge for configuring Cloudflare Pages projects, managing environment variables, custom domains, and build settings. + +## Overview + +This skill provides comprehensive patterns and best practices for configuring and managing Cloudflare Pages projects through Wrangler CLI and the Cloudflare Dashboard. + +## Configuration File: wrangler.toml + +### Basic Structure + +```toml +# Project identification +name = "my-pages-project" + +# Compatibility date (use latest for new features) +compatibility_date = "2025-01-15" + +# Build configuration +[build] +command = "npm run build" +cwd = "." +watch_dirs = ["src", "public"] + +# Upload configuration +[[build.upload]] +format = "directory" +dir = "dist" + +# Production environment +[env.production] +# Production-specific settings + +# Preview environment +[env.preview] +# Preview-specific settings +``` + +### Advanced Configuration + +```toml +name = "advanced-pages-project" +compatibility_date = "2025-01-15" + +# Build configuration with custom Node version +[build] +command = "npm ci && npm run build" +cwd = "." +watch_dirs = ["src", "public", "content"] + +# Node.js version selection +[build.env_vars] +NODE_VERSION = "18" +NODE_ENV = "production" + +# Upload multiple directories +[[build.upload]] +format = "directory" +dir = "dist" +exclusions = ["*.map", "*.md"] + +# Production environment configuration +[env.production] +workers_dev = false +route = "example.com/*" + +# Staging environment +[env.staging] +workers_dev = false +route = "staging.example.com/*" + +# Preview environment +[env.preview] +workers_dev = true +``` + +## Environment Variables + +### Types of Variables + +**1. Build-Time Variables** (Set during build) +- Embedded in compiled code +- Public (visible in browser) +- Set via `.env` files or build scripts +- Examples: API URLs, feature flags, public IDs + +**2. Runtime Variables** (Secrets) +- Accessed in Pages Functions +- Private (not visible in browser) +- Set via Wrangler CLI +- Examples: API keys, database credentials + +### Setting Build-Time Variables + +```bash +# .env file (for local development) +VITE_API_URL=https://api.example.com +NEXT_PUBLIC_GA_ID=UA-XXXXXXX-1 +PUBLIC_FEATURE_FLAG=true + +# Build with variables +npm run build +``` + +Common frameworks: +- **Vite**: `VITE_*` prefix +- **Next.js**: `NEXT_PUBLIC_*` prefix +- **Create React App**: `REACT_APP_*` prefix +- **Nuxt**: `NUXT_PUBLIC_*` prefix +- **SvelteKit**: `PUBLIC_*` prefix + +### Setting Runtime Secrets + +```bash +# Set individual secret +wrangler pages secret put API_KEY --project-name=my-website + +# Set multiple secrets +wrangler pages secret put DATABASE_URL --project-name=my-website +wrangler pages secret put STRIPE_SECRET --project-name=my-website +wrangler pages secret put AUTH_SECRET --project-name=my-website + +# List secrets (values are hidden) +wrangler pages secret list --project-name=my-website + +# Delete secret +wrangler pages secret delete API_KEY --project-name=my-website +``` + +### Bulk Secret Management + +```bash +# Script to set multiple secrets from file +#!/bin/bash +PROJECT_NAME="my-website" + +# Read from .env.production (DO NOT commit this file!) +while IFS='=' read -r key value; do + # Skip empty lines and comments + [[ -z "$key" || "$key" =~ ^#.* ]] && continue + + # Set secret + echo "$value" | wrangler pages secret put "$key" --project-name="$PROJECT_NAME" + echo "βœ“ Set secret: $key" +done < .env.production + +echo "βœ… All secrets configured" +``` + +### Accessing Secrets in Pages Functions + +```javascript +// functions/api/data.js + +export async function onRequest(context) { + // Access runtime secrets + const apiKey = context.env.API_KEY; + const dbUrl = context.env.DATABASE_URL; + + // Use in API calls + const response = await fetch('https://api.example.com/data', { + headers: { + 'Authorization': `Bearer ${apiKey}` + } + }); + + return response; +} +``` + +## Custom Domains + +### Adding Custom Domain + +**Via Cloudflare Dashboard:** +1. Navigate to: https://dash.cloudflare.com/ +2. Select your account +3. Go to: Workers & Pages β†’ Your Project β†’ Custom domains +4. Click "Set up a custom domain" +5. Enter domain name (e.g., `www.example.com`) +6. Follow DNS instructions + +### DNS Configuration + +**Option 1: CNAME (Recommended)** +``` +Type: CNAME +Name: www +Content: your-project.pages.dev +Proxy: Enabled (orange cloud) +``` + +**Option 2: A Record (Apex domain)** +``` +Type: A +Name: @ +Content: [Cloudflare IP provided in dashboard] +Proxy: Enabled (orange cloud) +``` + +**Option 3: AAAA Record (IPv6)** +``` +Type: AAAA +Name: @ +Content: [Cloudflare IPv6 provided in dashboard] +Proxy: Enabled (orange cloud) +``` + +### Redirecting Apex to www + +``` +# _redirects file +https://example.com/* https://www.example.com/:splat 301 +``` + +### Multiple Custom Domains + +You can add multiple custom domains to one project: + +``` +Primary: www.example.com +Additional: + - example.com (redirects to www) + - app.example.com + - beta.example.com +``` + +Each gets automatic HTTPS certificate. + +## Headers Configuration + +### Creating _headers File + +``` +# _headers file (place in build output directory) + +# Global headers (apply to all pages) +/* + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + X-XSS-Protection: 1; mode=block + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: geolocation=(), microphone=(), camera=() + +# Security headers for HTML pages +/*.html + Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' + X-Frame-Options: SAMEORIGIN + +# Cache static assets aggressively +/assets/* + Cache-Control: public, max-age=31536000, immutable + +/static/* + Cache-Control: public, max-age=31536000, immutable + +# Don't cache HTML +/*.html + Cache-Control: public, max-age=0, must-revalidate + +# API route headers +/api/* + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS + Access-Control-Allow-Headers: Content-Type, Authorization + Content-Type: application/json + +# Font files +/*.woff2 + Cache-Control: public, max-age=31536000, immutable + Access-Control-Allow-Origin: * +``` + +### Common Header Patterns + +#### Security Headers (Recommended) + +``` +/* + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + X-XSS-Protection: 1; mode=block + Referrer-Policy: strict-origin-when-cross-origin + Strict-Transport-Security: max-age=31536000; includeSubDomains; preload +``` + +#### CORS Headers + +``` +/api/* + Access-Control-Allow-Origin: https://example.com + Access-Control-Allow-Methods: GET, POST, OPTIONS + Access-Control-Allow-Headers: Content-Type, Authorization + Access-Control-Max-Age: 86400 +``` + +#### Cache Headers + +``` +# Static assets - cache forever +/assets/* + Cache-Control: public, max-age=31536000, immutable + +# HTML - never cache +/*.html + Cache-Control: public, max-age=0, must-revalidate + +# API responses - don't cache +/api/* + Cache-Control: no-store, no-cache, must-revalidate +``` + +## Redirects & Rewrites + +### Creating _redirects File + +``` +# _redirects file (place in build output directory) + +# Redirect old URLs +/old-page /new-page 301 +/blog/old-post /blog/new-post 301 + +# Redirect with splat (wildcard) +/blog/* /posts/:splat 301 + +# Redirect entire domain +https://old-domain.com/* https://new-domain.com/:splat 301 + +# Force HTTPS (Cloudflare does this by default, but explicit) +http://example.com/* https://example.com/:splat 301 + +# Redirect apex to www +https://example.com/* https://www.example.com/:splat 301 + +# SPA fallback (serve index.html for all routes) +/* /index.html 200 + +# API proxy (rewrite without redirect) +/api/* https://backend.example.com/:splat 200 + +# Temporary redirect +/maintenance /503.html 302 + +# Redirect based on path parameter +/user/:id /users/:id 301 +``` + +### Advanced Redirect Patterns + +#### Country-Based Redirects + +``` +# _redirects +/ /en 302 Country=US +/ /fr 302 Country=FR +/ /de 302 Country=DE +/ /es 302 Country=ES +``` + +#### Language Redirects + +``` +# _redirects +/ /en 302 Language=en +/ /fr 302 Language=fr +/ /es 302 Language=es +``` + +#### Conditional Redirects + +``` +# _redirects +# Redirect mobile users to mobile site +/ /mobile 302 Condition=mobile + +# A/B testing +/ /variant-a 302 Cookie=ab_test=variant_a +/ /variant-b 302 Cookie=ab_test=variant_b +``` + +## Build Configuration Patterns + +### Framework-Specific Configurations + +#### Next.js Static Export + +```toml +name = "nextjs-pages-site" +compatibility_date = "2025-01-15" + +[build] +command = "npm run build && npm run export" + +[[build.upload]] +format = "directory" +dir = "out" +``` + +```json +// package.json +{ + "scripts": { + "build": "next build", + "export": "next export" + } +} +``` + +#### Vite + React + +```toml +name = "vite-react-site" +compatibility_date = "2025-01-15" + +[build] +command = "npm run build" + +[[build.upload]] +format = "directory" +dir = "dist" +``` + +#### Astro + +```toml +name = "astro-site" +compatibility_date = "2025-01-15" + +[build] +command = "npm run build" + +[[build.upload]] +format = "directory" +dir = "dist" +``` + +#### Hugo + +```toml +name = "hugo-blog" +compatibility_date = "2025-01-15" + +[build] +command = "hugo --minify" + +[[build.upload]] +format = "directory" +dir = "public" +``` + +### Monorepo Configuration + +```toml +name = "frontend-monorepo" +compatibility_date = "2025-01-15" + +[build] +command = "cd packages/website && npm run build" +cwd = "../.." +watch_dirs = ["packages/website/src"] + +[[build.upload]] +format = "directory" +dir = "packages/website/dist" +``` + +## Pages Functions Configuration + +### Function Routes + +Create `functions` directory in your project: + +``` +project/ +β”œβ”€β”€ public/ # Static files +β”œβ”€β”€ functions/ # Pages Functions (API routes) +β”‚ β”œβ”€β”€ api/ +β”‚ β”‚ β”œβ”€β”€ hello.js +β”‚ β”‚ └── users/ +β”‚ β”‚ └── [id].js +β”‚ └── _middleware.js +└── wrangler.toml +``` + +### Function Example + +```javascript +// functions/api/hello.js +export async function onRequest(context) { + return new Response(JSON.stringify({ + message: 'Hello from Cloudflare Pages!', + timestamp: new Date().toISOString() + }), { + headers: { + 'Content-Type': 'application/json' + } + }); +} +``` + +### Dynamic Routes + +```javascript +// functions/api/users/[id].js +export async function onRequest(context) { + const id = context.params.id; + + return new Response(JSON.stringify({ + userId: id, + name: `User ${id}` + }), { + headers: { + 'Content-Type': 'application/json' + } + }); +} +``` + +### Middleware + +```javascript +// functions/_middleware.js +export async function onRequest(context) { + // Add custom header to all requests + const response = await context.next(); + response.headers.set('X-Custom-Header', 'My Value'); + return response; +} +``` + +## Project Organization Best Practices + +### Directory Structure + +``` +cloudflare-pages-project/ +β”œβ”€β”€ .env.example # Template for environment variables +β”œβ”€β”€ .env # Local development (git-ignored) +β”œβ”€β”€ .env.production # Production secrets (git-ignored) +β”œβ”€β”€ .gitignore # Exclude secrets and build artifacts +β”œβ”€β”€ wrangler.toml # Cloudflare Pages configuration +β”œβ”€β”€ package.json # Dependencies and scripts +β”œβ”€β”€ src/ # Source code +β”‚ β”œβ”€β”€ components/ +β”‚ β”œβ”€β”€ pages/ +β”‚ └── utils/ +β”œβ”€β”€ public/ # Static assets (copied as-is) +β”‚ β”œβ”€β”€ _headers # Custom headers +β”‚ β”œβ”€β”€ _redirects # Redirects and rewrites +β”‚ β”œβ”€β”€ robots.txt +β”‚ └── favicon.ico +β”œβ”€β”€ functions/ # Pages Functions (API routes) +β”‚ β”œβ”€β”€ api/ +β”‚ β”‚ └── endpoint.js +β”‚ └── _middleware.js +└── dist/ # Build output (git-ignored) +``` + +### gitignore Configuration + +```gitignore +# Environment variables (CRITICAL - never commit secrets!) +.env +.env.local +.env.production +.env.*.local + +# Build outputs +dist/ +build/ +out/ +.next/ +.output/ + +# Dependencies +node_modules/ + +# Logs +*.log +npm-debug.log* + +# OS files +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Wrangler +.wrangler/ +``` + +### Environment Variable Templates + +```bash +# .env.example (commit this) +# Copy to .env for local development + +# Build-time variables (public) +VITE_API_URL=https://api.example.com +VITE_GA_ID=UA-XXXXXXX-X + +# Runtime secrets (private) - set via: wrangler pages secret put +# API_KEY=your-api-key-here +# DATABASE_URL=your-database-url +# STRIPE_SECRET=your-stripe-secret +``` + +## Multi-Environment Setup + +### Environment Strategy + +``` +Production (main branch) +β”œβ”€β”€ URL: https://project.pages.dev +β”œβ”€β”€ Custom domain: https://www.example.com +└── Secrets: Production API keys + +Staging (staging branch) +β”œβ”€β”€ URL: https://staging.project.pages.dev +β”œβ”€β”€ Custom domain: https://staging.example.com +└── Secrets: Staging API keys + +Preview (all other branches) +β”œβ”€β”€ URL: https://[commit-hash].project.pages.dev +└── Secrets: Shared preview secrets +``` + +### Branch-Based Configuration + +```toml +# wrangler.toml + +name = "my-multi-env-project" +compatibility_date = "2025-01-15" + +[build] +command = "npm run build" + +[[build.upload]] +dir = "dist" + +[env.production] +# Production-specific config +route = "www.example.com/*" + +[env.staging] +# Staging-specific config +route = "staging.example.com/*" +``` + +## Monitoring & Analytics + +### Built-in Analytics + +View analytics in Cloudflare Dashboard: +- Requests per second +- Bandwidth usage +- Cache hit rate +- Unique visitors +- Geographic distribution + +Access: https://dash.cloudflare.com/ β†’ Pages β†’ Your Project β†’ Analytics + +### Custom Analytics Integration + +```html + + + + + + +``` + +### Real User Monitoring (RUM) + +```javascript +// functions/_middleware.js +export async function onRequest(context) { + const start = Date.now(); + const response = await context.next(); + const duration = Date.now() - start; + + // Log performance metric + console.log(`Request took ${duration}ms`); + + // Add timing header + response.headers.set('Server-Timing', `total;dur=${duration}`); + + return response; +} +``` + +## Security Configuration + +### Content Security Policy + +``` +# _headers +/* + Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self' +``` + +### Rate Limiting (via Pages Functions) + +```javascript +// functions/_middleware.js +const rateLimitMap = new Map(); + +export async function onRequest(context) { + const clientIP = context.request.headers.get('CF-Connecting-IP'); + const now = Date.now(); + const windowMs = 60000; // 1 minute + const maxRequests = 100; + + if (!rateLimitMap.has(clientIP)) { + rateLimitMap.set(clientIP, { count: 1, resetTime: now + windowMs }); + } else { + const record = rateLimitMap.get(clientIP); + + if (now > record.resetTime) { + record.count = 1; + record.resetTime = now + windowMs; + } else { + record.count++; + if (record.count > maxRequests) { + return new Response('Too Many Requests', { status: 429 }); + } + } + } + + return context.next(); +} +``` + +## Troubleshooting Common Configuration Issues + +### Issue: Environment Variables Not Working + +**Build-time variables:** +```bash +# Check framework prefix +VITE_API_URL=... # Vite +NEXT_PUBLIC_API=... # Next.js +REACT_APP_API=... # CRA + +# Verify build includes variables +npm run build +grep -r "api.example.com" dist/ +``` + +**Runtime secrets:** +```bash +# Verify secrets are set +wrangler pages secret list --project-name=my-website + +# Check function can access +cat > functions/test.js <= 3.0.0) + ```bash + npm install -g wrangler + ``` + +2. **Node.js** (>= 18.0.0) + ```bash + node --version # Should be >= v18.0.0 + ``` + +3. **Cloudflare Account** + - Free account sufficient for most use cases + - Pages included in all plans + - Sign up: https://dash.cloudflare.com/sign-up + +### Authentication Setup + +```bash +# Method 1: OAuth (recommended for local development) +wrangler login +# Opens browser for authentication + +# Method 2: API Token (recommended for CI/CD) +export CLOUDFLARE_API_TOKEN=your-token-here +wrangler whoami # Verify authentication + +# Verify authentication +wrangler whoami +# Output should show: "You are logged in as user@example.com" +``` + +## Core Concepts + +### Cloudflare Pages Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Your Source Code β”‚ +β”‚ (React, Vue, Svelte, Next.js, etc.) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Build Process (Local) β”‚ +β”‚ npm run build β†’ generates static files β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Wrangler CLI Upload β”‚ +β”‚ wrangler pages deploy ./dist β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Cloudflare Global CDN β”‚ +β”‚ 300+ Edge locations worldwide β”‚ +β”‚ Automatic HTTPS, DDoS protection β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Deployment Types + +**1. Production Deployment** +- Triggered from main/master branch +- Gets production URL: `https://project-name.pages.dev` +- Visible to all users +- Should be stable and tested + +**2. Preview Deployment** +- Triggered from any other branch +- Gets unique preview URL: `https://abc123.project-name.pages.dev` +- Used for testing before production +- Automatically cleaned up after branch deletion + +## Deployment Patterns + +### Pattern 1: Basic Deployment + +```bash +# Step 1: Build your project +npm run build + +# Step 2: Deploy to Cloudflare Pages +wrangler pages deploy ./dist --project-name=my-website +``` + +**When to use:** +- First deployment +- Simple static sites +- Quick prototyping +- Manual deployments + +### Pattern 2: Branch-Based Deployment + +```bash +# Production deployment (main branch) +git checkout main +npm run build +wrangler pages deploy ./dist \ + --project-name=my-website \ + --branch=main + +# Preview deployment (feature branch) +git checkout feature/new-design +npm run build +wrangler pages deploy ./dist \ + --project-name=my-website \ + --branch=feature/new-design +``` + +**When to use:** +- Git-based workflows +- Multiple environments +- Preview before production +- Team collaboration + +### Pattern 3: CI/CD Deployment + +```yaml +# GitHub Actions example +name: Deploy to Cloudflare Pages + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Deploy to Cloudflare Pages + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + command: pages deploy ./dist --project-name=my-website --branch=${{ github.ref_name }} +``` + +**When to use:** +- Automated deployments +- Continuous deployment +- Team workflows +- Production systems + +### Pattern 4: Monorepo Deployment + +```bash +# Deploy specific workspace from monorepo +cd packages/website +npm run build +wrangler pages deploy ./dist \ + --project-name=my-website-frontend \ + --branch=main + +cd ../admin +npm run build +wrangler pages deploy ./dist \ + --project-name=my-website-admin \ + --branch=main +``` + +**When to use:** +- Multiple related projects +- Shared dependencies +- Coordinated deployments +- Large applications + +## Build Configuration + +### Common Framework Patterns + +#### React (Create React App) + +```json +{ + "scripts": { + "build": "react-scripts build" + } +} +``` + +Build output: `build/` + +```bash +npm run build +wrangler pages deploy ./build --project-name=my-react-app +``` + +#### Vue.js + +```json +{ + "scripts": { + "build": "vue-cli-service build" + } +} +``` + +Build output: `dist/` + +```bash +npm run build +wrangler pages deploy ./dist --project-name=my-vue-app +``` + +#### Next.js (Static Export) + +```json +{ + "scripts": { + "build": "next build && next export" + } +} +``` + +Build output: `out/` + +```bash +npm run build +wrangler pages deploy ./out --project-name=my-nextjs-app +``` + +#### Svelte + +```json +{ + "scripts": { + "build": "vite build" + } +} +``` + +Build output: `dist/` + +```bash +npm run build +wrangler pages deploy ./dist --project-name=my-svelte-app +``` + +#### Astro + +```json +{ + "scripts": { + "build": "astro build" + } +} +``` + +Build output: `dist/` + +```bash +npm run build +wrangler pages deploy ./dist --project-name=my-astro-app +``` + +#### Hugo + +```bash +# Hugo generates static files directly +hugo --minify + +# Deploy +wrangler pages deploy ./public --project-name=my-hugo-blog +``` + +Build output: `public/` + +## Advanced Deployment Options + +### Include Git Metadata + +```bash +wrangler pages deploy ./dist \ + --project-name=my-website \ + --branch=$(git branch --show-current) \ + --commit-hash=$(git rev-parse HEAD) \ + --commit-message="$(git log -1 --pretty=%B)" +``` + +**Benefits:** +- Trace deployments to source code +- Better deployment history +- Easier debugging +- Audit trail + +### Specify Compatibility Date + +```bash +wrangler pages deploy ./dist \ + --project-name=my-website \ + --compatibility-date=2025-01-15 +``` + +**Use when:** +- Using Cloudflare-specific features +- Ensuring consistent behavior +- Testing new platform features + +### Custom Headers + +Create `_headers` file in your build output: + +``` +# _headers file +/* + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin + +/api/* + Access-Control-Allow-Origin: * + +/assets/* + Cache-Control: public, max-age=31536000, immutable +``` + +Then deploy normally - Cloudflare Pages automatically applies headers. + +### Redirects & Rewrites + +Create `_redirects` file in your build output: + +``` +# _redirects file + +# Redirect old blog to new location +/blog/* https://blog.example.com/:splat 301 + +# SPA fallback +/* /index.html 200 + +# Temporary redirect +/old-page /new-page 302 + +# Domain redirect +https://www.example.com/* https://example.com/:splat 301 +``` + +## Environment Variables & Secrets + +### Setting Secrets + +```bash +# Interactive prompt (recommended for sensitive data) +wrangler pages secret put API_KEY --project-name=my-website + +# From file +cat api-key.txt | wrangler pages secret put API_KEY --project-name=my-website + +# From environment variable +echo "$MY_SECRET" | wrangler pages secret put API_KEY --project-name=my-website +``` + +### Listing Secrets + +```bash +# List all secrets (values are hidden) +wrangler pages secret list --project-name=my-website +``` + +Output: +``` +Secret Name Uploaded At +API_KEY 2025-01-15T10:30:00Z +DATABASE_URL 2025-01-14T15:20:00Z +STRIPE_KEY 2025-01-13T09:45:00Z +``` + +### Accessing Secrets in Pages Functions + +```javascript +// functions/api/hello.js +export async function onRequest(context) { + const apiKey = context.env.API_KEY; + + return new Response(JSON.stringify({ + message: 'Hello from Cloudflare Pages!', + authenticated: !!apiKey + }), { + headers: { 'Content-Type': 'application/json' } + }); +} +``` + +### Build-Time vs Runtime Variables + +**Build-time** (set during `npm run build`): +```bash +# .env file +VITE_API_URL=https://api.example.com +NEXT_PUBLIC_GA_ID=UA-XXXXXXX +``` + +**Runtime** (set via Wrangler): +```bash +# Secrets accessible in Pages Functions +wrangler pages secret put STRIPE_SECRET_KEY --project-name=my-website +``` + +## Troubleshooting + +### Issue: "Command not found: wrangler" + +**Cause:** Wrangler CLI not installed or not in PATH + +**Solution:** +```bash +# Install globally +npm install -g wrangler + +# Or use with npx +npx wrangler pages deploy ./dist --project-name=my-website + +# Verify installation +which wrangler +wrangler --version +``` + +### Issue: "You are not authenticated" + +**Cause:** Not logged in to Cloudflare + +**Solution:** +```bash +# Login via OAuth +wrangler login + +# Or set API token +export CLOUDFLARE_API_TOKEN=your-token-here + +# Verify authentication +wrangler whoami +``` + +### Issue: "Build directory not found" + +**Cause:** Build hasn't run or wrong directory specified + +**Solution:** +```bash +# Check if build directory exists +ls -la dist/ # or build/ or out/ + +# Run build command +npm run build + +# Verify build output +ls -lah dist/ + +# Check common locations +for dir in dist build out public .next/out; do + [ -d "$dir" ] && echo "Found: $dir" +done +``` + +### Issue: "Project not found" + +**Cause:** Project doesn't exist in Cloudflare account + +**Solution:** +```bash +# List existing projects +wrangler pages project list + +# Create new project (happens automatically on first deploy) +wrangler pages deploy ./dist --project-name=my-new-project + +# Or create via dashboard: +# https://dash.cloudflare.com/pages +``` + +### Issue: "Rate limit exceeded" + +**Cause:** Too many API requests in short time + +**Solution:** +```bash +# Wait indicated time (usually 60 seconds) +sleep 60 + +# Retry deployment +wrangler pages deploy ./dist --project-name=my-website + +# Check for concurrent deployments +ps aux | grep wrangler + +# Verify API token isn't being used elsewhere +``` + +### Issue: "File too large" + +**Cause:** Individual file exceeds 25MB limit + +**Solution:** +```bash +# Find large files +find dist/ -type f -size +25M + +# Optimize images +# - Use modern formats (WebP, AVIF) +# - Compress with tools like imagemin +# - Use responsive images + +# Split large bundles +# - Code splitting in webpack/vite +# - Dynamic imports +# - Lazy loading + +# Use external hosting for large files +# - Cloudflare R2 +# - AWS S3 +# - CDN for media files +``` + +### Issue: "Deployment successful but site not updating" + +**Cause:** Browser cache or CDN cache + +**Solution:** +```bash +# Hard refresh browser +# Chrome/Firefox: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows) + +# Check deployment was successful +wrangler pages deployment list --project-name=my-website + +# Verify latest deployment is active +curl -I https://my-website.pages.dev + +# Purge Cloudflare cache (if using custom domain) +# Via dashboard: Cache β†’ Purge Everything +``` + +### Issue: "404 errors after deployment" + +**Cause:** SPA routing not configured + +**Solution:** +```bash +# Create _redirects file +cat > dist/_redirects < dist/_routes.json <