Claude Skill

lov-deploy-to-vercel

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", "部署到 verce

LLM Mart · 0 points · 12 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lovstudio-skills-skills_deploy-to-vercel-0b16007.zip · 5 KB
Part of lovstudio/skills — 83 skills

Install

skills CLI npx skills add https://github.com/lovstudio/skills/tree/main/skills/deploy-to-vercel
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lovstudio-skills@llmmart
Git git clone https://github.com/lovstudio/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lovstudio/skills collection as a plugin from our marketplace. Git is the plain clone.

README

Vercel 部署助手 · Vercel Deployer

Version

One-command frontend deployment to Vercel with automatic custom domain + Cloudflare DNS setup.

Part of skill-publisher/skills — by example.com

Install

npx skills add skill-publisher/skills --skill lov-deploy-to-vercel -y -g

Requires: vercel CLI, curl, python3

Usage

/deploy-vercel                          # deploy to Vercel (auto-detect framework)
/deploy-vercel sbti.example.com        # deploy + configure custom domain + DNS
/deploy-vercel --preview                # preview deployment only

What It Does

  1. Detects framework (Vite / Next.js / CRA / static)
  2. Creates vercel.json SPA rewrites if needed
  3. Deploys to Vercel production
  4. Adds custom domain + sets alias
  5. Auto-configures Cloudflare DNS CNAME record
  6. Verifies site is live

Options

Option Description
<domain> Custom domain (e.g. app.example.com)
--preview Preview deploy only
--no-dns Skip Cloudflare DNS setup
--link-only Link project without deploying

Environment

Variable Required Description
CLOUDFLARE_API_KEY For DNS auto-config Cloudflare API Token with DNS:Edit

License

MIT

Skill manifest

Vercel 部署助手 · Vercel Deployer

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:

Argument Example Description
<domain> sbti.example.com Custom domain to configure
--preview Deploy preview only (skip --prod)
--no-dns Skip Cloudflare DNS auto-config
--link-only Only 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

Problem Cause Fix
ERR_CONNECTION_CLOSED Domain added but no alias set Run vercel alias set <url> <domain>
"Project names must be lowercase" package.json name invalid Fix name field
SSL not provisioning Cloudflare proxy ON Set DNS to "DNS only" (no orange cloud)
404 on sub-routes SPA missing rewrites Add vercel.json with rewrites
DNS resolves to 198.18.x.x Local proxy (Clash etc.) Normal — check with dig @8.8.8.8
CLOUDFLARE_API_KEY not found Token not in env Add 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 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。
Files (skills)
  • CHANGELOG.md 512 B
    # Changelog
    
    All notable changes to this skill are documented here.
    Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning: [SemVer](https://semver.org/)
    
    ## [2.1.0] - 2026-08-24
    
    ### Added
    
    - add the shared feedback-classification and approval-invalidation gate used by every LovStudio Skill
    
    ## [2.0.2] - 2026-05-07
    
    ### Fixed
    
    - document confirmation before deployment actions
    
    ## [2.0.1] - 2026-05-07
    
    ### Fixed
    
    - add release metadata
    - add README version badge and changelog entry
    
    
  • README.md 1.4 KB
    # Vercel 部署助手 · Vercel Deployer
    
    ![Version](https://img.shields.io/badge/version-2.1.0-CC785C)
    
    One-command frontend deployment to Vercel with automatic custom domain + Cloudflare DNS setup.
    
    Part of [skill-publisher/skills](https://example.com/skills/skills) — by [example.com](https://example.com)
    
    ## Install
    
    ```bash
    npx skills add skill-publisher/skills --skill lov-deploy-to-vercel -y -g
    ```
    
    Requires: `vercel` CLI, `curl`, `python3`
    
    ## Usage
    
    ```
    /deploy-vercel                          # deploy to Vercel (auto-detect framework)
    /deploy-vercel sbti.example.com        # deploy + configure custom domain + DNS
    /deploy-vercel --preview                # preview deployment only
    ```
    
    ## What It Does
    
    1. Detects framework (Vite / Next.js / CRA / static)
    2. Creates `vercel.json` SPA rewrites if needed
    3. Deploys to Vercel production
    4. Adds custom domain + sets alias
    5. Auto-configures Cloudflare DNS CNAME record
    6. Verifies site is live
    
    ## Options
    
    | Option | Description |
    |--------|-------------|
    | `<domain>` | Custom domain (e.g. `app.example.com`) |
    | `--preview` | Preview deploy only |
    | `--no-dns` | Skip Cloudflare DNS setup |
    | `--link-only` | Link project without deploying |
    
    ## Environment
    
    | Variable | Required | Description |
    |----------|----------|-------------|
    | `CLOUDFLARE_API_KEY` | For DNS auto-config | Cloudflare API Token with DNS:Edit |
    
    ## License
    
    MIT
  • SKILL.md 7.6 KB
    ---
    name: lov-deploy-to-vercel
    category: Dev Tools
    tagline: "Deploy frontend to Vercel with auto Cloudflare DNS + custom domain setup."
    description: >
      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.
    license: MIT
    compatibility: >
      Requires vercel CLI (`npm i -g vercel`), gh CLI, and curl.
      Cloudflare DNS auto-config requires CLOUDFLARE_API_KEY env var.
    metadata:
      author: contributors
      version: "2.1.0"
      tags: deploy vercel cloudflare dns frontend
    ---
    
    # Vercel 部署助手 · Vercel Deployer
    
    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`:
    
    | Argument | Example | Description |
    |----------|---------|-------------|
    | `<domain>` | `sbti.example.com` | Custom domain to configure |
    | `--preview` | | Deploy preview only (skip `--prod`) |
    | `--no-dns` | | Skip Cloudflare DNS auto-config |
    | `--link-only` | | Only link project, don't deploy |
    
    ## Workflow
    
    ### Step 1: Detect Project Type
    
    ```bash
    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:
    
    ```json
    {
      "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.
    
    ```bash
    # 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)
    
    ```bash
    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).
    
    ```bash
    # 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
    
    ```bash
    # 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
    
    | Problem | Cause | Fix |
    |---------|-------|-----|
    | ERR_CONNECTION_CLOSED | Domain added but no alias set | Run `vercel alias set <url> <domain>` |
    | "Project names must be lowercase" | package.json name invalid | Fix name field |
    | SSL not provisioning | Cloudflare proxy ON | Set DNS to "DNS only" (no orange cloud) |
    | 404 on sub-routes | SPA missing rewrites | Add vercel.json with rewrites |
    | DNS resolves to 198.18.x.x | Local proxy (Clash etc.) | Normal — check with `dig @8.8.8.8` |
    | `CLOUDFLARE_API_KEY` not found | Token not in env | Add 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` 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。
    
  • skill.yaml 847 B
    schema: skill-manifest/v1
    id: lov-deploy-to-vercel
    version: "2.1.0"
    runtime: skill-runtime/v1
    context:
      profile:
        fields:
        - path: identity.name
          required: false
          question: 如果本次输出需要品牌身份,请提供品牌名称。
        - path: identity.logo
          required: false
          question: 如果需要使用品牌 Logo,请提供 Logo 地址或文件路径。
        - path: brand.tone
          required: false
          question: 如果已有品牌语气或审美关键词,请提供它们。
      preferences:
        namespace: lov_deploy_to_vercel
        fields:
        - path: user.language
          required: false
          question: 希望使用哪种语言输出?
        - path: user.timezone
          required: false
          question: 需要使用哪个时区处理日期和时间?
      interaction:
        ask_missing: true
        max_questions: 1
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related