#!/bin/bash # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 设置并发数(CPU核心数,避免过载) PARALLEL_JOBS=$(sysctl -n hw.ncpu 2>/dev/null || echo 4) echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}并发打包脚本${NC}" echo -e "${BLUE}使用 $PARALLEL_JOBS 个并发任务${NC}" echo -e "${BLUE}========================================${NC}" echo "" # 临时目录用于存储结果 TEMP_DIR=$(mktemp -d) trap "rm -rf $TEMP_DIR" EXIT # 统计项目总数 total_projects=0 for dir in */; do if [ -d "$dir" ] && [ -f "${dir}package.json" ]; then total_projects=$((total_projects + 1)) fi done echo -e "${GREEN}找到 $total_projects 个项目需要打包${NC}" echo "" # 处理单个项目的函数 process_project() { local dir="$1" local temp_dir="$2" local project_name="${dir%/}" local result_file="$temp_dir/${project_name}.result" echo -e "${BLUE}[开始] 打包项目: $project_name${NC}" # 进入子目录 cd "$dir" || { echo "FAILED:$project_name:无法进入目录" > "$result_file" echo -e "${RED}[失败] $project_name - 无法进入目录${NC}" return 1 } # 如果缺少 node_modules,先安装依赖 if [ ! -d "node_modules" ]; then echo -e "${YELLOW}[依赖] $project_name 缺少 node_modules,执行 pnpm install...${NC}" if ! pnpm install > "/tmp/${project_name}_install.log" 2>&1; then local error_log="$temp_dir/${project_name}.error" cat "/tmp/${project_name}_install.log" > "$error_log" echo "FAILED:$project_name:安装依赖失败:$error_log" > "$result_file" echo -e "${RED}[失败] $project_name - 安装依赖失败${NC}" cd - > /dev/null return 1 fi fi # 执行打包 local start_time=$(date +%s) if pnpm run prod > "/tmp/${project_name}_build.log" 2>&1; then local end_time=$(date +%s) local duration=$((end_time - start_time)) echo "SUCCESS:$project_name:${duration}秒" > "$result_file" echo -e "${GREEN}[成功] $project_name (耗时: ${duration}秒)${NC}" else local end_time=$(date +%s) local duration=$((end_time - start_time)) # 保存错误日志到临时文件 local error_log="$temp_dir/${project_name}.error" cat "/tmp/${project_name}_build.log" > "$error_log" echo "FAILED:$project_name:打包失败:$error_log" > "$result_file" echo -e "${RED}[失败] $project_name (耗时: ${duration}秒)${NC}" fi cd - > /dev/null } export -f process_project export TEMP_DIR RED GREEN YELLOW BLUE NC # 收集所有需要打包的项目 projects_to_build="" for dir in */; do if [ -d "$dir" ] && [ -f "${dir}package.json" ]; then projects_to_build="${projects_to_build}${dir}"$'\n' fi done # 使用 xargs 并发处理项目 echo -e "${YELLOW}开始并发打包...${NC}" echo "" echo "$projects_to_build" | grep -v '^$' | \ xargs -P "$PARALLEL_JOBS" -I {} bash -c 'process_project "$@"' _ {} "$TEMP_DIR" # 统计结果 echo "" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}打包结果统计${NC}" echo -e "${BLUE}========================================${NC}" success_count=$(grep -l "^SUCCESS:" "$TEMP_DIR"/*.result 2>/dev/null | wc -l | tr -d ' ') failed_count=$(grep -l "^FAILED:" "$TEMP_DIR"/*.result 2>/dev/null | wc -l | tr -d ' ') echo -e "总项目数: ${BLUE}$total_projects${NC}" echo -e "成功: ${GREEN}$success_count${NC}" echo -e "失败: ${RED}$failed_count${NC}" echo "" if [ "$failed_count" -gt 0 ]; then echo -e "${RED}失败的项目:${NC}" grep "^FAILED:" "$TEMP_DIR"/*.result 2>/dev/null | while IFS=: read -r file status project reason error_log; do echo -e " ${RED}✗${NC} $project" if [ -f "$error_log" ]; then echo -e "${YELLOW} 错误详情:${NC}" head -20 "$error_log" | sed 's/^/ /' local line_count=$(wc -l < "$error_log" | tr -d ' ') if [ "$line_count" -gt 20 ]; then echo -e " ${YELLOW}... (共 $line_count 行,仅显示前 20 行)${NC}" fi echo "" fi done fi if [ "$success_count" -gt 0 ]; then echo "" echo -e "${GREEN}成功的项目:${NC}" grep "^SUCCESS:" "$TEMP_DIR"/*.result 2>/dev/null | while IFS=: read -r file status project duration; do echo -e " ${GREEN}✓${NC} $project - $duration" done fi echo "" echo -e "${GREEN}打包完成!${NC}"