
现代开发的 Makefile
项目结构 Makefile
# Makefile
.PHONY: all install dev build test lint clean deploy help
# Default target
.DEFAULT_GOAL := help
# Variables
APP_NAME := myapp
VERSION := $(shell git describe --tags --abbrev=0 2>/dev/null || echo "v0.1.0")
COMMIT := $(shell git rev-parse --short HEAD)
BUILD_TIME := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
# Docker
IMAGE := ghcr.io/myorg/$(APP_NAME)
REGISTRY := ghcr.io
# Colors
GREEN := \033[0;32m
NC := \033[0m
##@ Development
install: ## 安装依赖
npm ci
dev: ## 启动开发服务器
npm run dev
build: ## 构建生产版本
npm run build
type-check: ## 运行 TypeScript 类型检查
npx tsc --noEmit
##@ Testing
test: ## 运行测试
npm test
test-watch: ## 以监视模式运行测试
npm test -- --watch
test-coverage: ## 运行测试并生成覆盖率
npm test -- --coverage
lint: ## 运行代码检查
npm run lint
lint-fix: ## 修复代码检查错误
npm run lint -- --fix
##@ Docker
docker-build: ## 构建 Docker 镜像
docker build \
--build-arg VERSION=$(VERSION) \
--build-arg COMMIT=$(COMMIT) \
--build-arg BUILD_TIME=$(BUILD_TIME) \
-t $(IMAGE):$(VERSION) \
-t $(IMAGE):latest \
.
docker-push: docker-build ## 构建并推送 Docker 镜像
docker push $(IMAGE):$(VERSION)
docker push $(IMAGE):latest
docker-run: ## 本地运行 Docker 容器
docker run --rm -p 3000:3000 --env-file .env $(IMAGE):latest
##@ Deployment
deploy-staging: docker-push ## 部署到预发布环境
kubectl set image deployment/$(APP_NAME) $(APP_NAME)=$(IMAGE):$(VERSION) -n staging
kubectl rollout status deployment/$(APP_NAME) -n staging
deploy-prod: docker-push ## 部署到生产环境(需要确认)
@echo "Deploying $(VERSION) to production..."
@read -p "Are you sure? [y/N] " confirm && [ "$confirm" = "y" ]
kubectl set image deployment/$(APP_NAME) $(APP_NAME)=$(IMAGE):$(VERSION) -n production
##@ Utilities
clean: ## 清理构建产物
rm -rf dist build .next coverage node_modules/.cache
setup: install ## 完整项目设置
cp -n .env.example .env || true
@echo "$(GREEN)Setup complete! Edit .env with your credentials.$(NC)"
db-migrate: ## 运行数据库迁移
npx prisma migrate deploy
db-reset: ## 重置开发数据库
npx prisma migrate reset --force
##@ Help
help: ## 显示此帮助信息
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \\033[36m<target>\\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \\033[36m%-20s\\033[0m %s\n", $1, $2 } /^##@/ { printf "\n\\033[1m%s\\033[0m\n", substr($0, 5) }' $(MAKEFILE_LIST)

模式规则与函数
# Pattern rule - compile all .ts files
BUILD_DIR := dist
SRC_DIR := src
TS_FILES := $(shell find $(SRC_DIR) -name '*.ts')
JS_FILES := $(TS_FILES:$(SRC_DIR)/%.ts=$(BUILD_DIR)/%.js)
$(BUILD_DIR)/%.js: $(SRC_DIR)/%.ts
npx tsc --outDir $(BUILD_DIR) lt;
# Use functions
FILES := $(wildcard src/**/*.ts)
BASENAME := $(notdir $(FILES))
DIRS := $(sort $(dir $(FILES)))
# String functions
UPPER_NAME := $(shell echo $(APP_NAME) | tr a-z A-Z)
TRIMMED := $(strip $(FILES))

并行执行
# Run tests and linting in parallel
ci:
$(MAKE) -j2 test lint
# Parallel builds
build-all:
$(MAKE) -j4 \
build-frontend \
build-backend \
build-worker \
build-scheduler

条件逻辑
# Platform detection
UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
OPEN := open
SED := gsed
else
OPEN := xdg-open
SED := sed
endif
# Environment-based config
ENV ?= development
ifeq ($(ENV), production)
DOCKER_FLAGS := --no-cache
NODE_FLAGS := --max-old-space-size=4096
else
DOCKER_FLAGS :=
NODE_FLAGS :=
endif
# Check for required tools
check-tools:
@which docker > /dev/null || (echo "Docker not found" && exit 1)
@which kubectl > /dev/null || (echo "kubectl not found" && exit 1)
@which node > /dev/null || (echo "Node.js not found" && exit 1)
@echo "All required tools found"
Makefile 最佳实践
| 实践 |
原因 |
.PHONY 目标 |
不与文件冲突 |
## 注释 |
在 make help 中显示 |
| 默认目标 |
清晰的入口点 |
| 检查依赖 |
缺失时尽早失败 |
| 并行标志 |
更快的构建 |