mcpField
E
edgeone-makers-recipes

edgeone-makers-recipes

github.com/tencentedgeone开发1.8k249 次安装3 周前更新
代码仓库

关于 edgeone-makers-recipes

EdgeOne Makers 的应用配方与项目模板集合,涵盖静态及全栈应用。内容包括 API 函数、Blob 与 KV 持久化、多语言目录结构和开发预览要求。

主要功能

  1. 01全栈项目模板
  2. 02基于 Blob 的持久化模式
  3. 03使用 KV 的 Edge Functions 示例
  4. 04Node.js、Python 和 Go 目录结构
  5. 05开发预览与文件命名指南

适用场景

  1. 01搭建带 API 路由的网站
  2. 02为动态网站添加 Blob 持久化
  3. 03创建基于 KV 的计数器
  4. 04为不同语言选择函数目录结构

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tencentedgeone/edgeone-makers-tools --skill edgeone-makers-recipes

安装后在 Claude Code 中输入/edgeone-makers-recipes确认已加载。

附带文件references/youth-site-scenarios.md

详细介绍

常见方案

⛔ 预览禁令:开发完成后,必须通过 edgeone makers dev 启动开发服务器,然后使用 present_files 打开 http://127.0.0.1:8088/ 进行预览。切勿通过 file:// 协议打开 HTML 文件(即使 IDE 自动打开,也请忽略),也不要使用 python -m http.server 或 npx serve 等自托管服务器。Next.js 项目还必须在 next.config 中设置 allowedDevOrigins: ["127.0.0.1"]。如果项目使用 Blob/KV,请传入 -n <project-name> — edgeone makers dev -n <project-name> — 必须提供名称才能自动配置资源;在沙盒中,直接运行 dev 会卡在交互式选择器。

⚠️ .env.example 是必需文件:每个使用 AI Gateway 的项目(Agent 项目、调用大模型的 Cloud Functions)都必须在项目根目录创建 .env.example,并声明 AI_GATEWAY_API_KEY= 和 AI_GATEWAY_BASE_URL=。CLI 会在部署时根据此文件自动注入环境变量;如果缺少该文件,就不会注入这些变量,运行时会报错。

📝 始终最后编写 index.html:编写 index.html 会立即触发 IDE 的 file:// 预览,在 WorkBuddy 中无法避免。应先写好所有依赖项,以缩短预览显示异常的时间:style.css、script.js、Cloud Functions(functions/ 文件)、静态资源,以及页面加载的所有内容。然后最后编写 index.html — 此时 file:// 预览打开时所有资源都已就位,并且这种状态只会保持到 edgeone makers dev 接管为止(见上文“预览禁令”)。此外,每个 index.html 都应一次写完;不要先搭建一个空壳,再反复修改填充(每次保存都会重新渲染并闪烁)。对于简单的单页工具,只需将 CSS 和 JS 内联到一个 index.html 中。

⛔ 严格照抄方案中的文件命名 — 两个会静默失败的陷阱:编写任何 Cloud Function 之前,先找到下方对应的场景,并使用其中的确切文件名。文件名错误通常不会报出明确错误 — 而是静默回退:

  1. 每个函数文件都必须带有语言扩展名 — .js(Node)、.py(Python)、.go(Go)。没有扩展名的文件(例如 api/upload-url、api/file)不会被识别为函数;平台会静默提供静态 index.html 回退页面,因此 /api/* 会“莫名其妙”地返回 HTML,而不是 JSON。文件应命名为 api/upload-url.js、api/file.js。
  2. [[default]].js 是其所在目录的兜底路由(api/[[default]].js → /api/*),两种导出方式都可用 — 框架实例(export default app、Express/Koa)或普通的 onRequest/onRequestGet/… 处理器。已使用 edgeone makers dev 在本地验证:[[default]].js 中只有一个 onRequest、没有 export default app,也能正常让 /foo/anything 返回 200 application/json。文档中的 “The builder identifies the file as a function only when export default app is present” 一句位于 Express/Koa 框架章节 — 它描述的是构建器如何识别框架实例;不要将其理解为“兜底路由必须包含 export default app”。⚠️ 注意:这句话说的是部署时的构建器,而上述检查是在本地开发服务器上完成的,后者的限制更宽松 — 因此,如果发布使用兜底路由和 onRequest 的代码,部署后应重新验证一次路由(“本地可用” ≠ “构建时能识别”)。如果实际上不需要兜底路由,最稳妥的结构是每个路由对应一个具体文件(api/messages.js、api/artworks/[id]/like.js),通过 [id] 文件夹/文件传递参数,通过查询字符串传递额外参数(/api/file?key=...)。

典型 EdgeOne Makers 应用的项目结构模板。

全栈应用 — Node.js(静态内容 + API)

my-app/
├── index.html              # Frontend
├── style.css
├── script.js
├── cloud-functions/
│   └── api/
│       ├── users.js        # GET/POST /api/users
│       └── users/[id].js   # GET/PUT/DELETE /api/users/:id
└── package.json

前端调用 API:

const res = await fetch('/api/users');
const users = await res.json();

💾 数据存储在哪里? 此平台没有数据库。上面的 API 框架会返回空数据 — 要真正持久化记录、上传文件、投票结果或每位用户的状态,请使用 Blob。参阅下面的示例,以及 makers-storage → 将 Blob 用作后端。

使用 Blob 持久化的动态网站(留言簿 / 图库 / 投票 / 保存状态)

适用于任何需要真正后端但不需要关系型数据的生成式网站。前端 → Cloud Function → Blob。无需数据库,也无需在控制台中进行设置。

my-app/
├── index.html              # Frontend (form + list)
├── script.js
├── cloud-functions/
│   └── api/
│       └── messages.js     # GET lists entries, POST appends one
├── package.json            # depends on @edgeone/pages-blob

cloud-functions/api/messages.js — 每条记录使用一个文件(模式 1):

import { getStore } from "@edgeone/pages-blob";

export async function onRequest({ request }) {
  const store = getStore("guestbook");

  if (request.method === "POST") {
    const { name, text } = await request.json();
    const id = `${Date.now()}-${Math.round(Math.random() * 1e6)}`;
    await store.setJSON(`entries/${id}.json`, { id, name, text, ts: Date.now() });
    return Response.json({ ok: true, id });
  }

  const { blobs } = await store.list({ prefix: "entries/" });
  const items = await Promise.all(blobs.map((b) => store.get(b.key, { type: "json" })));
  items.sort((a, b) => b.ts - a.ts);
  return Response.json({ items });
}

index.html 前端像调用任何 API 一样调用它:

await fetch('/api/messages', {                     // post
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name, text }),
});
const { items } = await fetch('/api/messages').then((r) => r.json());  // list

如需采用其他数据形式,可替换键名方案:保存状态可用 users/<uid>.json,投票可用 counts/<option>.json(强一致性),文件上传可用 uploads/<id>.jpg + items/<id>.json。完整模式请参阅:makers-storage → 将 Blob 用作后端。

全栈应用 — Go(Gin 框架)

my-app/
├── index.html              # Frontend
├── style.css
├── script.js
├── cloud-functions/
│   └── api.go              # Gin app — all /api/* routes
├── go.mod
└── package.json

cloud-functions/api.go:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/users", listUsersHandler)
    r.POST("/users", createUserHandler)
    r.GET("/users/:id", getUserHandler)
    r.Run(":9000")
}

全栈应用 — Python(Flask)

my-app/
├── index.html              # Frontend
├── style.css
├── script.js
├── cloud-functions/
│   └── api/
│       └── index.py        # Flask app — all /api/* routes
├── cloud-functions/requirements.txt
└── package.json

cloud-functions/api/index.py:

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/users', methods=['GET'])
def get_users():
    return jsonify({'users': []})

@app.route('/users', methods=['POST'])
def create_user():
    data = request.get_json()
    return jsonify({'message': 'Created', 'user': data}), 201

全栈应用 — Python(FastAPI)

my-app/
├── index.html
├── cloud-functions/
│   └── api/
│       └── index.py        # FastAPI app — all /api/* routes
├── cloud-functions/requirements.txt
└── package.json

cloud-functions/api/index.py:

from fastapi import FastAPI

app = FastAPI()

@app.get('/items')
async def list_items():
    return {'items': []}

@app.get('/items/{item_id}')
async def get_item(item_id: int):
    return {'item_id': item_id}

全栈应用 — Go(Handler 模式)

my-app/
├── index.html
├── cloud-functions/
│   └── api/
│       ├── users/
│       │   ├── list.go     # GET /api/users/list
│       │   └── [id].go     # GET /api/users/:id
│       └── hello.go        # GET /api/hello
├── go.mod
└── package.json

Edge API + KV 计数器

⚠️ 前置条件:必须先在控制台中启用 KV Storage 并绑定一个命名空间。参阅 ../makers-storage/references/kv.md

my-app/
├── index.html
├── edge-functions/
│   └── api/
│       └── visit.js        # Edge function with KV
└── package.json

edge-functions/api/visit.js:

export async function onRequest() {
  // ⚠️ my_kv is a global variable (name set when binding namespace in console)
  let count = await my_kv.get('visits') || '0';
  count = String(Number(count) + 1);
  await my_kv.put('visits', count);
  
  return new Response(JSON.stringify({ visits: count }), {
    headers: { 'Content-Type': 'application/json' },
  });
}

设置步骤:

  1. 登录 EdgeOne Makers 控制台
  2. 前往“KV Storage”→ 点击“Apply Now”
  3. 创建一个命名空间(例如 my-kv-store)
  4. 绑定到项目,并将变量名设为 my_kv
  5. 部署或运行 edgeone makers dev 进行测试

Express 全栈应用

my-app/
├── index.html
├── cloud-functions/
│   └── api/
│       └── [[default]].js  # Express app handles all /api/*
└── package.json

中间件 + API 组合

my-app/
├── middleware.js            # Auth guard for /api/*
├── cloud-functions/
│   └── api/
│       ├── public.js       # No auth needed (matcher excludes it)
│       └── data.js         # Protected by middleware
└── package.json

多语言 Cloud Functions

你可以在同一个 cloud-functions/ 目录中使用不同的语言:

my-app/
├── index.html
├── cloud-functions/
│   ├── api/
│   │   ├── users.js        # Node.js — /api/users
│   │   └── hello.py        # Python — /api/hello
│   └── service.go          # Go — /service
├── go.mod
├── cloud-functions/requirements.txt
└── package.json

注意: 每个文件都会作为独立函数构建和部署,并使用各自的运行时。平台会根据文件扩展名检测语言。

评论

支持 Markdown