cloudflare-worker-base
Production-tested setup for Cloudflare Workers with Hono, Vite, and Static Assets. Use when: creating new Cloudflare Workers projects, setting up Hono routing with Workers, configuring Vite plugin for Workers, adding Static Assets to Workers, deploying with Wrangler, or encountering deployment errors, routing conflicts, or HMR crashes. Prevents 6 documented issues: export syntax errors, Static Assets routing conflicts, scheduled handler errors, HMR race conditions, upload race conditions, and Service Worker format confusion. Keywords: Cloudflare Workers, CF Workers, Hono, wrangler, Vite, Static Assets, @cloudflare/vite-plugin, wrangler.jsonc, ES Module, run_worker_first, SPA fallback, API routes, serverless, edge computing, "Cannot read properties of undefined", "Static Assets 404", "A hanging Promise was canceled", "Handler does not export", deployment fails, routing not working, HMR crashes
- License 许可
- MIT
- 最近更新
- 2026-09-09
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- cloudflare-worker-base
- license
- MIT
- description
- Production-tested setup for Cloudflare Workers with Hono, Vite, and Static Assets. Use when: creating new Cloudflare Workers projects, setting up Hono routing with Workers, configuring Vite plugin for Workers, adding Static Assets to Workers, deploying with Wrangler, or encountering deployment errors, routing conflicts, or HMR crashes. Prevents 6 documented issues: export syntax errors, Static Assets routing conflicts, scheduled handler errors, HMR race conditions, upload race conditions, and Service Worker format confusion. Keywords: Cloudflare Workers, CF Workers, Hono, wrangler, Vite, Static Assets, @cloudflare/vite-plugin, wrangler.jsonc, ES Module, run_worker_first, SPA fallback, API routes, serverless, edge computing, "Cannot read properties of undefined", "Static Assets 404", "A hanging Promise was canceled", "Handler does not export", deployment fails, routing not working, HMR crashes
02 资源文件 3
- 参考文档README.md6.4 KB
- 参考文档SKILL.json19.0 KB
- 其他SKILL.md.backup17.5 KB
03 SKILL.md 正文
Cloudflare Worker Base Stack
Production-tested: cloudflare-worker-base-test (https://cloudflare-worker-base-test.webfonts.workers.dev) Last Updated: 2025-10-20 Status: Production Ready ✅
Quick Start (5 Minutes)
1. Scaffold Project
npm create cloudflare@latest my-worker -- \
--type hello-world \
--ts \
--git \
--deploy false \
--framework none
Why these flags:
--type hello-world: Clean starting point--ts: TypeScript support--git: Initialize git repo--deploy false: Don't deploy yet (configure first)--framework none: We'll add Vite ourselves
2. Install Dependencies
cd my-worker
npm install hono@4.10.1
npm install -D @cloudflare/vite-plugin@1.13.13 vite@latest
Version Notes:
hono@4.10.1: Latest stable (verified 2025-10-20)@cloudflare/vite-plugin@1.13.13: Latest stable, fixes HMR race conditionvite: Latest version compatible with Cloudflare plugin
3. Configure Wrangler
Create or update wrangler.jsonc:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"account_id": "YOUR_ACCOUNT_ID",
"compatibility_date": "2025-10-11",
"observability": {
"enabled": true
},
"assets": {
"directory": "./public/",
"binding": "ASSETS",
"not_found_handling": "single-page-application",
"run_worker_first": ["/api/*"]
}
}
CRITICAL: run_worker_first Configuration
- Without this, SPA fallback intercepts API routes
- API routes return
index.htmlinstead of JSON - Source: workers-sdk #8879
4. Configure Vite
Create vite.config.ts:
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'
export default defineConfig({
plugins: [
cloudflare({
// Optional: Configure the plugin if needed
}),
],
})
Why @cloudflare/vite-plugin:
- Official plugin from Cloudflare
- Supports HMR with Workers
- Enables local development with Miniflare
- Version 1.13.13 fixes "A hanging Promise was canceled" error
The Four-Step Setup Process
Step 1: Create Hono App with API Routes
Create src/index.ts:
/**
* Cloudflare Worker with Hono
*
* CRITICAL: Export pattern to prevent build errors
* ✅ CORRECT: export default app
* ❌ WRONG: export default { fetch: app.fetch }
*/
import { Hono } from 'hono'
// Type-safe environment bindings
type Bindings = {
ASSETS: Fetcher
}
const app = new Hono<{ Bindings: Bindings }>()
/**
* API Routes
* Handled BEFORE static assets due to run_worker_first config
*/
app.get('/api/hello', (c) => {
return c.json({
message: 'Hello from Cloudflare Workers!',
timestamp: new Date().toISOString(),
})
})
app.get('/api/health', (c) => {
return c.json({
status: 'ok',
version: '1.0.0',
environment: c.env ? 'production' : 'development',
})
})
/**
* Fallback to Static Assets
* Any route not matched above is served from public/ directory
*/
app.all('*', (c) => {
return c.env.ASSETS.fetch(c.req.raw)
})
/**
* Export the Hono app directly (ES Module format)
* This is the correct pattern for Cloudflare Workers with Hono + Vite
*/
export default app
Why This Export Pattern:
- Source: honojs/hono #3955
- Using
{ fetch: app.fetch }causes: "Cannot read properties of undefined (reading 'map')" - Exception: If you need scheduled/tail handlers, use Module Worker format:
export default { fetch: app.fetch, scheduled: async (event, env, ctx) => { /* ... */ } }
Step 2: Create Static Frontend
Create public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Worker App</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div class="container">
<h1>Cloudflare Worker + Static Assets</h1>
<button onclick="testAPI()">Test API</button>
<pre id="output"></pre>
</div>
<script src="/script.js"></script>
</body>
</html>
Create public/script.js:
async function testAPI() {
const response = await fetch('/api/hello')
const data = await response.json()
document.getElementById('output').textContent = JSON.stringify(data, null, 2)
}
Create public/styles.css:
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 800px;
margin: 40px auto;
padding: 20px;
}
button {
background: #0070f3;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
}
pre {
background: #f5f5f5;
padding: 16px;
border-radius: 6px;
overflow-x: auto;
}
Step 3: Update Package Scripts
Update package.json:
{
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"cf-typegen": "wrangler types"
}
}
Step 4: Test & Deploy
# Generate TypeScript types for bindings
npm run cf-typegen
# Start local dev server (http://localhost:8787)
npm run dev
# Deploy to production
npm run deploy
Known Issues Prevention
This skill prevents 6 documented issues:
Issue #1: Export Syntax Error
Error: "Cannot read properties of undefined (reading 'map')"
Source: honojs/hono #3955
Prevention: Use export default app (NOT { fetch: app.fetch })
Issue #2: Static Assets Routing Conflicts
Error: API routes return index.html instead of JSON
Source: workers-sdk #8879
Prevention: Add "run_worker_first": ["/api/*"] to wrangler.jsonc
Issue #3: Scheduled/Cron Not Exported
Error: "Handler does not export a scheduled() function" Source: honojs/vite-plugins #275 Prevention: Use Module Worker format when needed:
export default {
fetch: app.fetch,
scheduled: async (event, env, ctx) => { /* ... */ }
}
Issue #4: HMR Race Condition
Error: "A hanging Promise was canceled" during development
Source: workers-sdk #9518
Prevention: Use @cloudflare/vite-plugin@1.13.13 or later
Issue #5: Static Assets Upload Race
Error: Non-deterministic deployment failures in CI/CD Source: workers-sdk #7555 Prevention: Use Wrangler 4.x+ with retry logic (fixed in recent versions)
Issue #6: Service Worker Format Confusion
Error: Using deprecated Service Worker format Source: Cloudflare migration guide Prevention: Always use ES Module format (shown in Step 1)
Configuration Files Reference
wrangler.jsonc (Full Example)
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"account_id": "YOUR_ACCOUNT_ID",
"compatibility_date": "2025-10-11",
"observability": {
"enabled": true
},
"assets": {
"directory": "./public/",
"binding": "ASSETS",
"not_found_handling": "single-page-application",
"run_worker_first": ["/api/*"]
}
/* Optional: Environment Variables */
// "vars": { "MY_VARIABLE": "production_value" }
/* Optional: KV Namespace Bindings */
// "kv_namespaces": [
// { "binding": "MY_KV", "id": "YOUR_KV_ID" }
// ]
/* Optional: D1 Database Bindings */
// "d1_databases": [
// { "binding": "DB", "database_name": "my-db", "database_id": "YOUR_DB_ID" }
// ]
/* Optional: R2 Bucket Bindings */
// "r2_buckets": [
// { "binding": "MY_BUCKET", "bucket_name": "my-bucket" }
// ]
}
Why wrangler.jsonc over wrangler.toml:
- JSON format preferred since Wrangler v3.91.0
- Better IDE support with JSON schema
- Comments allowed with JSONC
vite.config.ts (Full Example)
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'
export default defineConfig({
plugins: [
cloudflare({
// Persist state between HMR updates
persist: true,
}),
],
// Optional: Configure server
server: {
port: 8787,
},
// Optional: Build optimizations
build: {
target: 'esnext',
minify: true,
},
})
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022"],
"moduleResolution": "bundler",
"types": ["@cloudflare/workers-types/2023-07-01"],
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
API Route Patterns
Basic JSON Response
app.get('/api/users', (c) => {
return c.json({
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
})
})
POST with Request Body
app.post('/api/users', async (c) => {
const body = await c.req.json()
// Validate and process body
return c.json({ success: true, data: body }, 201)
})
Route Parameters
app.get('/api/users/:id', (c) => {
const id = c.req.param('id')
return c.json({ id, name: 'User' })
})
Query Parameters
app.get('/api/search', (c) => {
const query = c.req.query('q')
return c.json({ query, results: [] })
})
Error Handling
app.get('/api/data', async (c) => {
try {
// Your logic here
return c.json({ success: true })
} catch (error) {
return c.json({ error: error.message }, 500)
}
})
Using Bindings (KV, D1, R2)
type Bindings = {
ASSETS: Fetcher
MY_KV: KVNamespace
DB: D1Database
MY_BUCKET: R2Bucket
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/api/data', async (c) => {
// KV
const value = await c.env.MY_KV.get('key')
// D1
const result = await c.env.DB.prepare('SELECT * FROM users').all()
// R2
const object = await c.env.MY_BUCKET.get('file.txt')
return c.json({ value, result, object })
})
Static Assets Best Practices
Directory Structure
public/
├── index.html # Main entry point
├── styles.css # Global styles
├── script.js # Client-side JavaScript
├── favicon.ico # Favicon
└── assets/ # Images, fonts, etc.
├── logo.png
└── fonts/
SPA Fallback
The "not_found_handling": "single-page-application" configuration means:
- Unknown routes return
index.html - Useful for React Router, Vue Router, etc.
- BUT requires
run_worker_firstfor API routes!
Route Priority
With "run_worker_first": ["/api/*"]:
/api/hello→ Worker handles it (returns JSON)/→ Static Assets serveindex.html/styles.css→ Static Assets servestyles.css/unknown→ Static Assets serveindex.html(SPA fallback)
Caching Static Assets
Static Assets are automatically cached at the edge. To bust cache:
<link rel="stylesheet" href="/styles.css?v=1.0.0">
<script src="/script.js?v=1.0.0"></script>
Development Workflow
Local Development
npm run dev
- Server runs on http://localhost:8787
- HMR enabled (file changes reload automatically)
- Uses Miniflare for local simulation
- All bindings work locally (KV, D1, R2)
Testing API Routes
# Test GET endpoint
curl http://localhost:8787/api/hello
# Test POST endpoint
curl -X POST http://localhost:8787/api/echo \
-H "Content-Type: application/json" \
-d '{"test": "data"}'
Type Generation
npm run cf-typegen
Generates worker-configuration.d.ts with:
- Binding types (KV, D1, R2, etc.)
- Environment variable types
- Auto-completes in your editor
Deployment
# Deploy to production
npm run deploy
# Deploy to specific environment
wrangler deploy --env staging
# Tail logs in production
wrangler tail
# Check deployment status
wrangler deployments list
Complete Setup Checklist
- [ ] Project scaffolded with
npm create cloudflare@latest - [ ] Dependencies installed:
hono@4.10.1,@cloudflare/vite-plugin@1.13.13 - [ ]
wrangler.jsonccreated with:- [ ]
account_idset to your Cloudflare account - [ ]
assets.directorypointing to./public/ - [ ]
assets.run_worker_firstincludes/api/* - [ ]
compatibility_dateset to recent date
- [ ]
- [ ]
vite.config.tscreated with@cloudflare/vite-plugin - [ ]
src/index.tscreated with Hono app- [ ] Uses
export default app(NOT{ fetch: app.fetch }) - [ ] Includes ASSETS binding type
- [ ] Has fallback route:
app.all('*', (c) => c.env.ASSETS.fetch(c.req.raw))
- [ ] Uses
- [ ]
public/directory created with static files - [ ]
npm run cf-typegenexecuted successfully - [ ]
npm run devstarts without errors - [ ] API routes tested in browser/curl
- [ ] Static assets serve correctly
- [ ] HMR works without crashes
- [ ] Ready to deploy with
npm run deploy
Advanced Topics
Adding Middleware
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
const app = new Hono<{ Bindings: Bindings }>()
// Global middleware
app.use('*', logger())
app.use('/api/*', cors())
// Route-specific middleware
app.use('/admin/*', async (c, next) => {
// Auth check
await next()
})
Environment-Specific Configuration
// wrangler.jsonc
{
"name": "my-worker",
"env": {
"staging": {
"vars": { "ENV": "staging" }
},
"production": {
"vars": { "ENV": "production" }
}
}
}
Deploy: wrangler deploy --env staging
Custom Error Pages
app.onError((err, c) => {
console.error(err)
return c.json({ error: 'Internal Server Error' }, 500)
})
app.notFound((c) => {
return c.json({ error: 'Not Found' }, 404)
})
Testing with Vitest
npm install -D vitest @cloudflare/vitest-pool-workers
Create vitest.config.ts:
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
poolOptions: {
workers: {
wrangler: { configPath: './wrangler.jsonc' },
},
},
},
})
See reference/testing.md for complete testing guide.
File Templates
All templates are available in the templates/ directory:
- wrangler.jsonc - Complete Worker configuration
- vite.config.ts - Vite + Cloudflare plugin setup
- package.json - Dependencies and scripts
- tsconfig.json - TypeScript configuration
- src/index.ts - Hono app with API routes
- public/index.html - Static frontend example
- public/styles.css - Example styling
- public/script.js - API test functions
Copy these files to your project and customize as needed.
Reference Documentation
For deeper understanding, see:
- architecture.md - Deep dive into export patterns, routing, and Static Assets
- common-issues.md - All 6 issues with detailed troubleshooting
- deployment.md - Wrangler commands, CI/CD patterns, and production tips
Official Documentation
- Cloudflare Workers: https://developers.cloudflare.com/workers/
- Static Assets: https://developers.cloudflare.com/workers/static-assets/
- Vite Plugin: https://developers.cloudflare.com/workers/vite-plugin/
- Wrangler Configuration: https://developers.cloudflare.com/workers/wrangler/configuration/
- Hono: https://hono.dev/docs/getting-started/cloudflare-workers
- Context7 Library ID:
/websites/developers_cloudflare-workers
Dependencies (Latest Verified 2025-10-20)
{
"dependencies": {
"hono": "^4.10.1"
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.13.13",
"@cloudflare/workers-types": "^4.20251011.0",
"vite": "^7.0.0",
"wrangler": "^4.43.0",
"typescript": "^5.9.0"
}
}
Production Example
This skill is based on the cloudflare-worker-base-test project:
- Live: https://cloudflare-worker-base-test.webfonts.workers.dev
- Build Time: ~45 minutes (actual)
- Errors: 0 (all 6 known issues prevented)
- Validation: ✅ Local dev, HMR, production deployment all successful
All patterns in this skill have been validated in production.
Questions? Issues?
- Check
reference/common-issues.mdfirst - Verify all steps in the 4-step setup process
- Ensure
export default app(not{ fetch: app.fetch }) - Ensure
run_worker_firstis configured - Check official docs: https://developers.cloudflare.com/workers/
04 同仓库更多 Skills
zustand-state-management
Production-tested setup for Zustand state management in React applications with TypeScript. This skill provides comprehensive patterns for building scalable, type-safe global state. Use when: setting up global state in React, migrating from Redux or Context API, implementing state persistence with localStorage, configuring TypeScript with Zustand, using slices pattern for modular stores, adding devtools middleware for debugging, handling Next.js SSR hydration, or encountering hydration errors, TypeScript inference issues, or persist middleware problems. Prevents 5 documented issues: Next.js hydration mismatches, TypeScript double parentheses syntax errors, persist middleware export errors, infinite render loops, and slices pattern type inference failures. Keywords: zustand, state management, React state, TypeScript state, persist middleware, devtools, slices pattern, global state, React hooks, create store, useBoundStore, StateCreator, hydration error, text content mismatch, infinite render, localStorage, sessionStorage, immer middleware, shallow equality, selector pattern, zustand v5
zetic-mlange
Help users integrate the ZETIC Melange (MLange) on-device AI SDK into Android (Kotlin/Java) and iOS (Swift) mobile apps. Use this skill whenever the user mentions Zetic, MLange, Melange, ZeticMLangeModel, ZeticMLangeLLMModel, ZeticMLangeHFModel, on-device NPU inference for mobile, or deploying ML models to Android/iOS with NPU acceleration. Also trigger when users ask about running LLMs on-device with GGUF quantization, mobile NPU model deployment, or converting PyTorch/ONNX models for mobile inference. Covers general model inference, LLM inference (streaming token generation), and HuggingFace model loading.
youtube-downloader
Download videos, audio, playlists, and channels from YouTube and 1000+ websites using yt-dlp. Supports quality selection, format conversion, subtitle download, playlist filtering, metadata extraction, thumbnail download, and batch operations. Use when downloading YouTube videos in any quality (4K, 8K, HDR), extracting audio as MP3/M4A/FLAC, downloading entire playlists/channels, getting subtitles in multiple languages, converting to specific formats, downloading live streams, archiving content, or batch processing multiple URLs. Optimized for reliability with automatic retries, rate limiting, and error handling.
wordpress-plugin-core
This skill provides comprehensive knowledge for WordPress plugin development, covering core patterns, security best practices, database interactions, hooks/filters, Settings API, custom post types, REST API, and AJAX. This skill should be used when creating WordPress plugins, troubleshooting security issues, implementing custom post types/taxonomies, building admin interfaces, or working with the WordPress database. Use when: Creating new WordPress plugins, implementing nonces/sanitization/escaping, working with $wpdb and prepared statements, building Settings API pages, registering custom post types or taxonomies, implementing REST API endpoints, handling AJAX requests, debugging plugin activation/deactivation issues, preventing SQL injection/XSS/CSRF vulnerabilities. Keywords: wordpress plugin development, wordpress security, wordpress hooks, wordpress filters, wordpress database, wpdb prepare, sanitize_text_field, esc_html, wp_nonce, custom post type, register_post_type, settings api, rest api, admin-ajax, wordpress sql injection, wordpress xss, wordpress csrf, plugin header, activation hook, deactivation hook, wordpress coding standards, wordpress plugin architecture
webapp-testing
Test local web applications with Playwright. Use when asked to verify frontend functionality, debug UI behavior, capture browser screenshots, or inspect browser logs.
web-performance-audit
Audit web performance using Chrome DevTools MCP. Use when asked to audit, profile, debug, or optimize page load performance, Lighthouse scores, or site speed.