Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:59:44 +08:00
commit 7e2a535be7
8 changed files with 2972 additions and 0 deletions

View File

@@ -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"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# cloudflare
Cloudflare Pages deployment and log monitoring using Wrangler CLI

379
agents/log-monitor.md Normal file
View File

@@ -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=<RECENT_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/

471
agents/pages-deployer.md Normal file
View File

@@ -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/

465
agents/project-manager.md Normal file
View File

@@ -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 <PREVIOUS_DEPLOYMENT_ID> --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 <<EOF
API_KEY=your-api-key-here
DATABASE_URL=your-database-url
ANALYTICS_ID=your-analytics-id
EOF
# Step 2: Set secrets one by one
wrangler pages secret put API_KEY --project-name=my-website
wrangler pages secret put DATABASE_URL --project-name=my-website
wrangler pages secret put ANALYTICS_ID --project-name=my-website
# Step 3: Verify secrets set
wrangler pages secret list --project-name=my-website
# Step 4: Clean up .env.production (don't commit!)
rm .env.production
```
### Task 3: Review Deployment History
```bash
# Step 1: List all deployments
wrangler pages deployment list --project-name=my-website
# Step 2: Get details of specific deployment
wrangler pages deployment tail --deployment-id=abc123
# Step 3: Check deployment status
curl -I https://abc123.my-website.pages.dev
```
### Task 4: Rollback to Previous Version
```bash
# Step 1: List recent deployments
wrangler pages deployment list --project-name=my-website | head -5
# Step 2: Identify previous working deployment
# (Note the deployment ID of the last known good deployment)
# Step 3: Promote previous deployment to production
wrangler pages deployment promote <PREVIOUS_DEPLOYMENT_ID> --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

61
plugin.lock.json Normal file
View File

@@ -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": []
}
}

View File

@@ -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
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
</script>
<!-- Plausible Analytics (privacy-friendly) -->
<script defer data-domain="example.com" src="https://plausible.io/js/script.js"></script>
```
### 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 <<EOF
export async function onRequest(context) {
return new Response(JSON.stringify({
hasApiKey: !!context.env.API_KEY
}));
}
EOF
```
### Issue: Custom Domain Not Working
**Checklist:**
1. DNS records added? (Check Dashboard)
2. DNS propagated? (Check with `dig` or `nslookup`)
3. SSL certificate issued? (Can take up to 24 hours)
4. Proxying enabled? (Orange cloud in DNS settings)
```bash
# Check DNS
dig www.example.com +short
# Check HTTPS
curl -I https://www.example.com
```
### Issue: _headers or _redirects Not Applied
**Verify file location:**
```bash
# Must be in build output directory
ls -la dist/_headers
ls -la dist/_redirects
# Check after build
npm run build
ls -la dist/
```
**Test redirect:**
```bash
curl -I https://my-website.pages.dev/old-page
# Should show: Location: /new-page
```
## Resources
- **Pages Configuration**: https://developers.cloudflare.com/pages/configuration/
- **Build Configuration**: https://developers.cloudflare.com/pages/platform/build-configuration/
- **Custom Domains**: https://developers.cloudflare.com/pages/platform/custom-domains/
- **Headers**: https://developers.cloudflare.com/pages/platform/headers/
- **Redirects**: https://developers.cloudflare.com/pages/platform/redirects/
- **Pages Functions**: https://developers.cloudflare.com/pages/platform/functions/
- **Environment Variables**: https://developers.cloudflare.com/pages/platform/build-configuration/#environment-variables

View File

@@ -0,0 +1,755 @@
# Wrangler Deployment Skill
Expert knowledge for deploying static sites to Cloudflare Pages using Wrangler CLI.
## Overview
This skill provides comprehensive patterns, best practices, and troubleshooting guidance for deploying web applications to Cloudflare Pages using the official Wrangler CLI tool.
## Prerequisites
### Required Tools
1. **Wrangler CLI** (>= 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 <<EOF
/* /index.html 200
EOF
# Or create _routes.json for more control
cat > dist/_routes.json <<EOF
{
"version": 1,
"include": ["/*"],
"exclude": ["/api/*"]
}
EOF
# Redeploy
wrangler pages deploy ./dist --project-name=my-website
```
## Performance Optimization
### Enable Compression
Cloudflare automatically compresses responses, but you can pre-compress:
```bash
# Pre-compress files with gzip
find dist/ -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) -exec gzip -k {} \;
# Pre-compress with brotli
find dist/ -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) -exec brotli -k {} \;
```
### Optimize Assets
```bash
# Minify JavaScript and CSS (usually done by build tool)
npm run build # with production mode
# Optimize images
npx @squoosh/cli --output-dir dist/images optimized/ *.{jpg,png}
# Remove source maps in production
# (configure in webpack/vite config)
```
### Cache Control Headers
```
# _headers file
/static/*
Cache-Control: public, max-age=31536000, immutable
/*.html
Cache-Control: public, max-age=0, must-revalidate
/api/*
Cache-Control: private, no-cache
```
## Deployment Verification
### Automated Checks
```bash
#!/bin/bash
# deploy-verify.sh
PROJECT_NAME="my-website"
DEPLOY_URL="https://$PROJECT_NAME.pages.dev"
# Deploy
wrangler pages deploy ./dist --project-name=$PROJECT_NAME
# Wait for deployment to propagate
sleep 10
# Check HTTP status
STATUS=$(curl -o /dev/null -s -w "%{http_code}" $DEPLOY_URL)
if [ "$STATUS" -eq 200 ]; then
echo "✅ Deployment successful: $DEPLOY_URL"
else
echo "❌ Deployment failed: HTTP $STATUS"
exit 1
fi
# Check critical pages
for page in "/about" "/contact" "/blog"; do
STATUS=$(curl -o /dev/null -s -w "%{http_code}" "$DEPLOY_URL$page")
if [ "$STATUS" -eq 200 ]; then
echo "✅ $page is accessible"
else
echo "⚠️ $page returned HTTP $STATUS"
fi
done
```
### Manual Verification Checklist
- [ ] Deployment URL accessible
- [ ] Homepage loads correctly
- [ ] All pages render properly
- [ ] Images load
- [ ] Forms work
- [ ] API endpoints respond
- [ ] Mobile layout correct
- [ ] HTTPS enabled
- [ ] Performance acceptable (Lighthouse check)
- [ ] No console errors
## Best Practices
### 1. Version Control Integration
```bash
# Tag releases
git tag -a v1.0.0 -m "Production release v1.0.0"
git push --tags
# Deploy with version info
wrangler pages deploy ./dist \
--project-name=my-website \
--commit-hash=$(git rev-parse HEAD)
```
### 2. Environment-Specific Builds
```bash
# Development build
NODE_ENV=development npm run build
wrangler pages deploy ./dist --project-name=my-website --branch=dev
# Production build
NODE_ENV=production npm run build
wrangler pages deploy ./dist --project-name=my-website --branch=main
```
### 3. Security Headers
```
# _headers file
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), microphone=()
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```
### 4. Clean Build Before Deploy
```bash
# Remove old build artifacts
rm -rf dist/
# Fresh build
npm run build
# Verify build output
ls -lah dist/
# Deploy
wrangler pages deploy ./dist --project-name=my-website
```
### 5. Rollback Strategy
```bash
# List recent deployments
wrangler pages deployment list --project-name=my-website
# Save deployment IDs
# Production: abc123def456
# Previous: xyz789ghi012
# Rollback if needed
wrangler pages deployment promote xyz789ghi012 --project-name=my-website
```
## Resources
- **Wrangler CLI Docs**: https://developers.cloudflare.com/workers/wrangler/
- **Pages Platform Docs**: https://developers.cloudflare.com/pages/
- **Direct Upload Guide**: https://developers.cloudflare.com/pages/get-started/direct-upload/
- **Framework Guides**: https://developers.cloudflare.com/pages/framework-guides/
- **Cloudflare Community**: https://community.cloudflare.com/
- **Status Page**: https://www.cloudflarestatus.com/