Vercel 部署助手 · Vercel Deployer

SkillCloud & infra

Deploy frontend projects to Vercel with automatic custom domain setup. Handles Vite, Next.js, CRA, and static sites. Auto-configures Cloudflare DNS CNAME records and Vercel domain aliases. Supports SPA routing via vercel.json. Trigger when user says "deploy to vercel", "部署到 vercel", "vercel deploy", or mentions a *.example.com / custom domain with vercel deployment.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Vercel 部署助手 · Vercel Deployer skill

What this skill tells your AI

The instructions your AI receives, as published by lovstudio/skills in skills/deploy-to-vercel/SKILL.md and read by ahel’s review.

Deploy frontend projects to Vercel with automatic custom domain and DNS setup.

When to Use

  • User says "deploy to vercel" or "部署到 xxx.example.com"
  • After building a frontend project that needs hosting
  • When setting up a custom domain on an existing Vercel deployment

Arguments

Pass via $ARGUMENTS:

ArgumentExampleDescription
<domain>sbti.example.comCustom domain to configure
--previewDeploy preview only (skip --prod)
--no-dnsSkip Cloudflare DNS auto-config
--link-onlyOnly link project, don't deploy

Workflow

Step 1: Detect Project Type

if [ -f "vite.config.ts" ] || [ -f "vite.config.js" ]; then
  FRAMEWORK="vite"
elif [ -f "next.config.js" ] || [ -f "next.config.mjs" ]; then
  FRAMEWORK="next"
elif grep -q "react-scripts" package.json 2>/dev/null; then
  FRAMEWORK="cra"
else
  FRAMEWORK="static"
fi

Step 2: Ensure vercel.json for SPA

For Vite/CRA (SPA) projects, create vercel.json if missing:

{
  "rewrites": [
    { "source": "/(.*)", "destination": "/" }
  ]
}

Skip for Next.js — it handles routing natively.

Step 3: Deploy to Vercel

Before running a production deployment, use AskUserQuestion if the target project, production/non-production mode, or custom domain is unclear. If the user already explicitly requested production deployment for this project, proceed.

# Check CLI
vercel --version || npm i -g vercel

# Deploy (use project name from package.json "name" field)
# IMPORTANT: package.json "name" must be lowercase, no special chars
PROJECT_NAME=$(node -p "require('./package.json').name" 2>/dev/null || basename "$PWD")
vercel --yes --prod

Known issue: If package.json name contains uppercase or invalid chars, vercel will error with "Project names must be lowercase". Fix the name first.

Step 4: Configure Custom Domain (if provided)

DOMAIN="<user-provided-domain>"  # e.g. sbti.example.com

# 1. Add domain to Vercel project
vercel domains add "$DOMAIN"

# 2. Set alias to point domain to latest deployment
PROD_URL=$(vercel ls --prod 2>&1 | grep -oE 'https://[^ ]+\.vercel\.app' | head -1)
vercel alias set "$PROD_URL" "$DOMAIN"

CRITICAL: vercel domains add alone is NOT enough. You MUST also run vercel alias set to actually route traffic. Without it, the domain returns ERR_CONNECTION_CLOSED.

Step 5: Auto-Configure Cloudflare DNS

Requires: CLOUDFLARE_API_KEY env var (API Token with DNS edit permission).

# Extract base domain and subdomain
# e.g. "sbti.example.com" → base="example.com", sub="sbti"
BASE_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
SUBDOMAIN=$(echo "$DOMAIN" | sed "s/\.$BASE_DOMAIN$//")

# 1. Get zone ID
ZONE_ID=$(curl -s "https://api.cloudflare.com/client/v4/zones?name=$BASE_DOMAIN" \
  -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \
  -H "Content-Type: application/json" | python3 -c "import sys,json; print(json.load(sys.stdin)['result'][0]['id'])")

# 2. Check if record already exists
EXISTING=$(curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$DOMAIN&type=CNAME" \
  -H "Authorization: Bearer $CLOUDFLARE_API_KEY" | python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(r[0]['id'] if r else '')")

# 3. Create or update CNAME → cname.vercel-dns.com
if [ -z "$EXISTING" ]; then
  curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
    -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"CNAME\",\"name\":\"$SUBDOMAIN\",\"content\":\"cname.vercel-dns.com\",\"ttl\":1,\"proxied\":false}"
else
  curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$EXISTING" \
    -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"CNAME\",\"name\":\"$SUBDOMAIN\",\"content\":\"cname.vercel-dns.com\",\"ttl\":1,\"proxied\":false}"
fi

IMPORTANT: proxied must be false (DNS only). Cloudflare proxy conflicts with Vercel's SSL certificate provisioning.

If CLOUDFLARE_API_KEY is not set, print manual DNS instructions instead:

Add DNS record:
  Type: CNAME
  Name: <subdomain>
  Target: cname.vercel-dns.com
  Proxy: OFF (DNS only)

Step 6: Verify

# Wait for DNS + SSL propagation
sleep 5
HTTP_CODE=$(curl -sI "https://$DOMAIN" -o /dev/null -w '%{http_code}')
if [ "$HTTP_CODE" = "200" ]; then
  echo "✓ $DOMAIN is live"
else
  echo "⚠ HTTP $HTTP_CODE — SSL may still be provisioning, try again in 1-2 min"
fi

Step 7: Output Summary

✓ Framework: vite
✓ Deployed: https://xxx.vercel.app
✓ Domain: https://sbti.example.com
✓ DNS: CNAME sbti → cname.vercel-dns.com (Cloudflare)
✓ Settings: https://vercel.com/<scope>/<project>/settings

Troubleshooting

ProblemCauseFix
ERR_CONNECTION_CLOSEDDomain added but no alias setRun vercel alias set <url> <domain>
"Project names must be lowercase"package.json name invalidFix name field
SSL not provisioningCloudflare proxy ONSet DNS to "DNS only" (no orange cloud)
404 on sub-routesSPA missing rewritesAdd vercel.json with rewrites
DNS resolves to 198.18.x.xLocal proxy (Clash etc.)Normal — check with dig @8.8.8.8
CLOUDFLARE_API_KEY not foundToken not in envAdd to ~/.zshrc: export CLOUDFLARE_API_KEY=...

Runtime context (shared)

运行前读取本 Skill 包的 skill.yaml,由宿主提供 skill-runtime/v1 上下文。字段解析顺序为:当前请求、项目上下文、个人 Preferences、品牌 Profile、通用默认值。

  • 只使用 Manifest 声明的字段;Profile 保存公开品牌事实,Preferences 保存个人工作偏好。
  • required: true 字段缺失时,按 Manifest 的问题配置向用户提出一个聚焦问题;用户明确同意后再保存回答。
  • 报错提供可复制的 context_id、字段路径与来源,诊断内容避开秘密、完整私人路径和原始配置。

通用反馈闭环

用户在 Skill 驱动任务中提出修改意见时,继续当前产物前必须执行:

  1. 先判断意见是 task-specific(仅本次)还是 reusable(可跨任务复用)。
  2. task-specific 只修改当前任务,不改 Skill。
  3. reusable 先确定作用域:领域规则先更新对应 canonical Skill;适用于所有 Skill 的规则先更新共享规范。
  4. 完成规则更新、版本、lint 与分发核验后,再把修改应用到当前任务。
  5. reusable 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。

Signals

GitHub stars
66
Forks
17
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
lov-deploy-to-vercel
Source
github.com/lovstudio/skills