使用 grunt 一键发布到 Vercel、Netlify、Cloudflare

解读

面试官抛出“一键发布”话题,表面看是问“能不能”,实质在考察候选人是否理解国内网络环境、CI/CD 流程与 Grunt 插件生态的边界
国内团队普遍把 Grunt 当“本地构建机”,而 Vercel、Netlify、Cloudflare Pages 的入口都是 Git 推送触发或 CLI 调用;如何把 Grunt 的构建产物准确、快速、可回滚地送到三家境外托管,并兼顾备案、域名解析、环境变量、缓存策略,才是得分点
回答时切忌只说“装个 grunt-shell 调 vercel deploy”,而要给出“本地构建 → 产物校验 → 多目标上传 → 回滚钩子”的完整闭环,并指出 Grunt 在 2025 年国内项目中的定位:负责构建层发布层交给平台 CLI 或 GitHub Action,但用 Grunt 做门禁与编排。

知识点

  1. Grunt 运行模型:任务链、并发控制、文件映射、时间戳指纹。
  2. 三家平台国内可用性
    • Vercel:边缘节点被墙概率高,需自定义 CDN 回源;CLI 支持 --prod--token
    • Netlify:备案域名可接入,但自动 HTTPS 证书签发偶发超时;CLI 支持 --dir 指定目录。
    • Cloudflare Pages:绑定 CNAME 需先完成工信部备案,且 Pages 函数(Functions)与大陆访问延迟大。
  3. 产物合规:HTML 中不能出现“NEXT_DATA 含敏感词”、JS 文件名不能带 ad 等关键字,否则触发平台自动拦截。
  4. 鉴权方式
    • 环境变量 VERCEL_TOKENNETLIFY_AUTH_TOKENCLOUDFLARE_API_TOKEN 必须走 .env.grunt 加载,不能硬编码进 Gruntfile
  5. 缓存与回滚
    • 利用 Grunt 的 grunt-contrib-rename 给产物目录加 {gitHash} 前缀,上传后通过平台 API 设置 alias,实现秒级回滚。
  6. 国内加速
    • 构建结束后把产物同时推到「阿里云 OSS + 镜像回源」作为备案主站,Vercel 仅作海外流量入口,Grunt 任务里用 grunt-aliyun-oss 插件并行上传

答案

“我会把发布拆成三段,全部收进一个 grunt publish 主任务,确保任何同事在仓库根目录执行 npx grunt publish 就能一键上线。

第一段,本地构建与产物校验

  • grunt-contrib-clean 清掉 dist。
  • webpack:client 把 TSX 打到 dist/static,输出带 hash 的 JS/CSS。
  • grunt-contrib-htmlmin 压缩 HTML,随后 grunt-inline-assets 把小图片转 base64,减少请求数。
  • 自定义子任务 grunt lint-dist,遍历 dist 下所有 .js 文件,走国内云函数做敏感词扫描,失败直接中断,防止境外平台因合规下架整个站点

第二段,多目标上传

  • 通过 grunt-env.env.grunt 加载到 process.env确保 token 不落源码
  • 注册三个子任务:
    1. vercel-deploy:用 grunt-shell 执行 npx vercel deploy dist --prod --token=$VERCEL_TOKEN --meta commit=$GIT_HASH,返回的 URL 写入 vercel.json
    2. netlify-deploy:先 npx netlify deploy --dir=dist --prod --auth=$NETLIFY_AUTH_TOKEN,拿到 deploy_id 后调 netlify api updateSiteproduction_branch 指向本次 commit,保证国内备案域名立刻生效
    3. cloudflare-deploy:调用 npx wrangler pages publish dist --project-name=xxx,成功后把 CF_PAGES_URL 回写 grunt.config('cf.url'),供后续钉钉通知。
  • 三个子任务用 grunt-concurrent 限流 2 并发,防止本地出口带宽被打满导致 CI 超时

第三段,门禁与回滚

  • 上传完成后触发 grunt http 任务,分别请求三家的 API 获取 status=READY 并断言 HTTP 200,任何一家失败即调用对应平台的 rollback API 并退出码 1,让 GitHub Action 显示红叉。
  • 最后 grunt-contrib-rename 把 dist 重命名为 dist-${GIT_HASH} 归档到 releases/ 目录,本地留痕,方便秒级回滚

整个 Gruntfile 约 180 行,无敏感信息,全部参数走环境变量,已在公司 GitLab CI 与开发者本机 macOS/Windows 双验证,平均构建+发布 90 秒,符合国内团队“下班前一键上线”的节奏。”

拓展思考

  1. 如果公司强制要求“源码不出内网”,可把 Grunt 构建产物推到内网 Nexus 的 raw 仓库,再通过「云效+自定义节点」把产物同步到境外平台,Grunt 侧只负责生成 checksum 与签名文件,实现“构建在内、发布在外”。
  2. 当项目转向 monorepo,Grunt 的 grunt-multi-dest 插件可以按 package 维度并行发布到三家平台的不同子目录,利用 Vercel 的“monorepo detector”自动识别根目录下 vercel.json,无需每个子包写配置。
  3. 国内备案域名与海外托管的 SEO 冲突,可在 Grunt 任务里插入 grunt-sitemap 生成两套 sitemap:一套指向备案主域,一套指向 Vercel 提供的边缘域名,通过 Search Console 的国际化定位把权重收拢到主域,既享受边缘加速又避免重复收录。