diff --git a/deploy/install.sh b/deploy/install.sh index 48faa84..ac8de4c 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -52,6 +52,19 @@ as_service_user() { fi } +# 安装**含 devDependencies** 的依赖。 +# 必须显式处理:脚本开头用 `set -a; . deploy/.env` 载入了 .env,其中的 +# NODE_ENV=production 会被导出到本脚本环境;npm 见到它会自动跳过 +# devDependencies,于是 tsc / vite / nest 等构建工具全部缺失 +# (用户实测报错:`sh: 1: tsc: not found`,且只装了 23 个包)。 +npm_install_with_dev() { + if [ -f package-lock.json ]; then + as_service_user env -u NODE_ENV npm ci --include=dev --no-audit --no-fund --loglevel=error + else + as_service_user env -u NODE_ENV npm install --include=dev --no-audit --no-fund --loglevel=error + fi +} + # HTTP GET,输出响应体。curl → wget → node(node 必有,且 22+ 自带 fetch) http_get() { if command -v curl >/dev/null 2>&1; then @@ -138,8 +151,11 @@ esac # 说明:在 git 检出目录直接执行时,web-server/ 里可能已有 200 MB+ 的 # node_modules(数万个小文件)。原实现用 cp -r 全量复制,会长时间无输出, # 看起来像卡死。这里统一排除,运行期依赖稍后由 npm ci 重新安装。 +# .env / .env.local 一并排除:deploy/.env 才是权威配置,源码树里的本地 .env +# 若被复制进来,dotenv 会把它当成第二配置源,造成排障困惑。 COPY_EXCLUDES=(--exclude=node_modules --exclude=.git --exclude=storage - --exclude=dist-release --exclude=coverage --exclude=.gradle) + --exclude=dist-release --exclude=coverage --exclude=.gradle + --exclude=.env --exclude=.env.local) copy_tree() { local src="$1" dst="$2" @@ -152,7 +168,7 @@ copy_tree() { # 嵌套的 "./admin/node_modules"(实测会漏掉 admin 下的 122MB 依赖)。 # 因此每个名字都要同时给出顶层与任意层级的模式。 local tar_excludes=() - for pattern in node_modules .git storage dist-release coverage .gradle; do + for pattern in node_modules .git storage dist-release coverage .gradle .env .env.local; do tar_excludes+=(--exclude="./$pattern" --exclude="*/$pattern") done ( cd "$src" && tar "${tar_excludes[@]}" -cf - . ) | ( cd "$dst" && tar -xf - ) @@ -169,22 +185,26 @@ for item in web-server contracts; do done # ---- 管理端产物:两种目录布局都要支持 ---- -# 发布包: /admin/ (已构建) -# 源码检出:/web-server/admin/dist/ (需已构建,缺失则现场构建) +# 发布包: /admin/ (已构建,直接用) +# 源码检出:/web-server/admin/dist/ (已构建,直接用) +# 否则在 $APP_DIR/web-server/admin 现场构建 +# (在安装目录内构建,不污染源码树,也不要求源码目录可写) ADMIN_SRC="" if [ -d "$SRC_DIR/admin" ]; then ADMIN_SRC="$SRC_DIR/admin" elif [ -d "$SRC_DIR/web-server/admin/dist" ]; then ADMIN_SRC="$SRC_DIR/web-server/admin/dist" -elif [ -d "$SRC_DIR/web-server/admin" ]; then - warn "未找到管理端构建产物,正在构建 web-server/admin(需要 devDependencies)" - if [ -f "$SRC_DIR/web-server/admin/package-lock.json" ]; then - ( cd "$SRC_DIR/web-server/admin" && npm ci --no-audit --no-fund --loglevel=error ) +elif [ -d "$APP_DIR/web-server/admin" ]; then + warn "未找到管理端构建产物,正在 ${APP_DIR}/web-server/admin 构建(需要 devDependencies)" + if ( cd "$APP_DIR/web-server/admin" && npm_install_with_dev \ + && as_service_user env -u NODE_ENV npm run build ); then + ADMIN_SRC="$APP_DIR/web-server/admin/dist" + # 构建完即可丢弃管理端的 node_modules,避免长期占用磁盘 + rm -rf "$APP_DIR/web-server/admin/node_modules" else - ( cd "$SRC_DIR/web-server/admin" && npm install --no-audit --no-fund --loglevel=error ) + die "管理端构建失败。可改用发布包(内含已构建的 admin/): + ./scripts/package-release.sh 然后在目标机解压部署" fi - ( cd "$SRC_DIR/web-server/admin" && npm run build ) - ADMIN_SRC="$SRC_DIR/web-server/admin/dist" fi [ -n "$ADMIN_SRC" ] || die "找不到管理端:既没有 admin/ 目录,也没有 web-server/admin/" @@ -215,8 +235,8 @@ fi if [ ! -f dist/main.js ]; then warn "未找到构建产物 dist/main.js,改为在服务器上构建(需要 devDependencies)" - as_service_user npm install --no-audit --no-fund - as_service_user npm run build + npm_install_with_dev + as_service_user env -u NODE_ENV npm run build fi [ -f dist/main.js ] || die "构建产物缺失:$APP_DIR/web-server/dist/main.js" [ -f "$APP_DIR/admin/index.html" ] || die "管理端构建产物缺失:$APP_DIR/admin/index.html"