正在加载,请稍候…

Makefile for Modern Development: Task Automation and Project Management

Master Makefile for project automation. Learn variables, patterns, phony targets, parallel execution, and organize development workflows with make commands.

Makefile for Modern Development

Project Structure 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: ## Install dependencies
    npm ci

dev: ## Start development server
    npm run dev

build: ## Build for production
    npm run build

type-check: ## Run TypeScript type check
    npx tsc --noEmit

##@ Testing

test: ## Run tests
    npm test

test-watch: ## Run tests in watch mode
    npm test -- --watch

test-coverage: ## Run tests with coverage
    npm test -- --coverage

lint: ## Run linting
    npm run lint

lint-fix: ## Fix linting errors
    npm run lint -- --fix

##@ Docker

docker-build: ## Build Docker image
    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 ## Build and push Docker image
    docker push $(IMAGE):$(VERSION)
    docker push $(IMAGE):latest

docker-run: ## Run Docker container locally
    docker run --rm -p 3000:3000 --env-file .env $(IMAGE):latest

##@ Deployment

deploy-staging: docker-push ## Deploy to staging
    kubectl set image deployment/$(APP_NAME) $(APP_NAME)=$(IMAGE):$(VERSION) -n staging
    kubectl rollout status deployment/$(APP_NAME) -n staging

deploy-prod: docker-push ## Deploy to production (requires confirmation)
    @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: ## Clean build artifacts
    rm -rf dist build .next coverage node_modules/.cache

setup: install ## Full project setup
    cp -n .env.example .env || true
    @echo "$(GREEN)Setup complete! Edit .env with your credentials.$(NC)"

db-migrate: ## Run database migrations
    npx prisma migrate deploy

db-reset: ## Reset development database
    npx prisma migrate reset --force

##@ Help

help: ## Show this help message
    @awk 'BEGIN {FS = ":.*##"; printf "
Usage:
  make \033[36m<target>\033[0m
"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-20s\033[0m %s
", $1, $2 } /^##@/ { printf "
\033[1m%s\033[0m
", substr($0, 5) }' $(MAKEFILE_LIST)

Pattern Rules and Functions

# 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))

Parallel Execution

# 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

Conditional Logic

# 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 Best Practices

Practice Why
.PHONY targets Don't conflict with files
## comments Show in make help
Default goal Clear entry point
Check dependencies Fail early if missing
Parallel flags Faster builds