deploy.sh 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #!/usr/bin/env bash
  2. # deploy.sh —— 零构建发布:生成前缀 → 静态体检 → 模块图爬取(本地)→ 上传 OBS → 线上复验。
  3. #
  4. # 前缀只有一个来源:deploy/prefix/<env>.txt(由 scripts/config.mjs 写出);
  5. # <base href> / importmap / 上传前缀 三处全部由它派生(pitfalls.md 第五条)。
  6. #
  7. # 用法:
  8. # ./deploy/prefix.sh prod # 只生成 prod 的 index.html + 前缀文件
  9. # OBS_BUCKET=xxx ./scripts/deploy.sh prod # 体检 + 上传 + 复验(需 obsutil 已配置)
  10. # ./scripts/deploy.sh prod --check-only # 只做静态体检与本地模块图爬取
  11. #
  12. # 环境变量:
  13. # OBS_BUCKET 桶名(必填,除非 --check-only)
  14. # OBS_ENDPOINT OBS 端点(默认 obs.cn-north-4.myhuaweicloud.com,按实际改)
  15. # CDN_BASE 线上地址根,如 https://kangshifu.fmode.cn(用于发布后复验)
  16. set -euo pipefail
  17. REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
  18. cd "$REPO_ROOT"
  19. ENV_NAME="${1:-}"
  20. CHECK_ONLY="${2:-}"
  21. if [[ -z "$ENV_NAME" ]]; then echo "用法:scripts/deploy.sh <local|local-sub|dev|prod> [--check-only]" >&2; exit 2; fi
  22. echo "== 1/5 生成前缀(唯一来源)"
  23. node scripts/config.mjs "$ENV_NAME"
  24. PREFIX="$(cat "deploy/prefix/${ENV_NAME}.txt")"
  25. echo " PREFIX=$PREFIX"
  26. echo "== 2/5 静态体检(A 组 1–9 + 凭据)"
  27. node scripts/check.mjs --env "$ENV_NAME"
  28. node --test 'test/*.test.js' >/dev/null && echo " core 单测 OK"
  29. echo "== 3/5 本地模块图爬取"
  30. node scripts/verify-modules.mjs --serve >/tmp/deploy-modules.log 2>&1 || { cat /tmp/deploy-modules.log; exit 1; }
  31. tail -1 /tmp/deploy-modules.log
  32. if [[ "$CHECK_ONLY" == "--check-only" ]]; then echo "== 仅体检,未上传"; exit 0; fi
  33. : "${OBS_BUCKET:?OBS_BUCKET 未设置}"
  34. OBS_ENDPOINT="${OBS_ENDPOINT:-obs.cn-north-4.myhuaweicloud.com}"
  35. KEY_PREFIX="${PREFIX#/}"; KEY_PREFIX="${KEY_PREFIX%/}"
  36. echo "== 4/5 上传 OBS(前缀 ${KEY_PREFIX}/)"
  37. upload() { # upload <本地文件> <key> <content-type>
  38. obsutil cp "$1" "obs://${OBS_BUCKET}/${2}" -e "$OBS_ENDPOINT" -f -meta="Content-Type:$3#Cache-Control:public,max-age=3600" >/dev/null
  39. }
  40. # 先删后传 index.html(sync 按 size+mtime 会跳过它,见坑 6)
  41. obsutil rm "obs://${OBS_BUCKET}/${KEY_PREFIX}/index.html" -e "$OBS_ENDPOINT" -f >/dev/null 2>&1 || true
  42. upload index.html "${KEY_PREFIX}/index.html" "text/html; charset=utf-8"
  43. while IFS= read -r -d '' f; do
  44. rel="${f#./}"
  45. case "$rel" in
  46. *.js) ct="text/javascript; charset=utf-8" ;;
  47. *.json) ct="application/json; charset=utf-8" ;;
  48. *.css) ct="text/css; charset=utf-8" ;;
  49. *.woff2) ct="font/woff2" ;;
  50. *) ct="application/octet-stream" ;;
  51. esac
  52. upload "$f" "${KEY_PREFIX}/${rel}" "$ct"
  53. done < <(find src lib/vendor -type f \( -name '*.js' -o -name '*.json' -o -name '*.css' -o -name '*.woff2' \) -print0)
  54. # index.html 单独设为 no-cache(CDN 回退拿到的永远是新壳)
  55. obsutil setmeta "obs://${OBS_BUCKET}/${KEY_PREFIX}/index.html" -e "$OBS_ENDPOINT" \
  56. -meta="Content-Type:text/html; charset=utf-8#Cache-Control:no-cache, no-store, must-revalidate" >/dev/null
  57. if [[ -n "${CDN_BASE:-}" ]]; then
  58. echo "== 5/5 线上复验(模块图 + 深链接)"
  59. node scripts/verify-modules.mjs "${CDN_BASE%/}${PREFIX}"
  60. else
  61. echo "== 5/5 跳过线上复验(未设置 CDN_BASE)"
  62. echo " 上传完成后请:node scripts/verify-modules.mjs https://<cdn>${PREFIX}"
  63. echo " 并确认 CDN 回退规则:命中真实资源直返;其余路径 200 返回 index.html(禁 301/302)"
  64. fi