起因
每个项目都有一堆"开发命令":
pnpm dev
docker compose up -d
uv run pytest
ruff check . && mypy .
docker compose exec api python manage.py shell
放哪?
package.jsonscripts:JS 项目 OK,但 Python / Rust 项目不自然Makefile:tab vs space / 老语法 / shell 转义恶心 / 不跨平台- README 里 copy-paste:散
- shell alias:项目特定的不该污染全局
just 是 Rust 写的命令记事本 / task runner。justfile 取代 Makefile,
专门为"跑命令" 设计(不为编译 build artifact)。
装
brew install just # macOS
cargo install just # 通用
sudo apt install just # ubuntu 22.04+
基础 justfile
# justfile(项目根)
# 默认 task:列出所有
default:
@just --list
# 装依赖
install:
uv sync
pnpm install
# 启动 dev
dev:
docker compose up -d db redis
uv run python manage.py runserver
# 跑测试
test:
uv run pytest -x
# 检查代码质量
lint:
ruff check .
mypy .
pnpm tsc --noEmit
跑:
$ just # 默认 → just --list
$ just install
$ just test
$ just lint
vs Makefile
# Makefile 等价
.PHONY: install test
install:
uv sync
pnpm install
test:
uv run pytest -x
- Makefile 要 tab 缩进(编辑器配错就崩)
- Makefile 假设是"build artifact"(filename dependency),shell 当 side effect
$(VAR)$$VAR转义恶心- 跨平台不一致(GNU make vs BSD make)
just 直接 shell 命令 / 空格缩进 / 跨平台一致 / 默认无 dependency
跟踪(这是 feature,不是 bug,跑命令不需要)。
参数
# 带参数
greet name='world':
echo "hello {{name}}"
# 多 arg
deploy env target:
./deploy.sh {{env}} {{target}}
$ just greet
hello world
$ just greet Alice
hello Alice
$ just deploy prod web
参数变量用 {{name}} 引用(Mustache 风格)。
recipe 调 recipe
build:
pnpm build
deploy: build
./deploy.sh
# 或者显式
release:
just lint
just test
just build
./release.sh
用 python / node 写 recipe
# bash(默认)
hello:
echo "hello"
# python
analyze:
#!/usr/bin/env python3
import json
with open('data.json') as f:
data = json.load(f)
print(f"items: {len(data)}")
# node
gen:
#!/usr/bin/env node
console.log('hi from node');
#! 第一行指定 shebang → 整个 recipe 当一个 script 跑(不是逐行)。
环境变量
# justfile 顶部 set
set dotenv-load # 自动加载 .env
# 默认变量
NAME := "myapp"
PORT := env_var_or_default("PORT", "8000")
run:
PORT={{PORT}} ./{{NAME}}
# Linux specific
[linux]
clean:
rm -rf build/
[macos]
clean:
rm -rf build/ .DS_Store
[linux] [macos] recipe attribute 让同 recipe 在不同平台用不同命令。
列出 + help
$ just --list
Available recipes:
default # 列出所有
install # 装依赖
test # 跑测试
# recipe 上面的注释自动当 docstring
每个 recipe 顶部加注释 → 自动是描述。新人 clone 项目 just 一下立刻
知道有什么任务。
我的常用模板
# justfile
set dotenv-load
set positional-arguments
PYTHON := "uv run"
default:
@just --list
# 初始化(一键 onboarding)
init:
uv sync
pnpm install
docker compose up -d db
{{PYTHON}} python manage.py migrate
{{PYTHON}} python manage.py createsuperuser --noinput || true
# 开发
dev:
docker compose up -d db redis
{{PYTHON}} python manage.py runserver 0.0.0.0:8000
# 测试 + 覆盖率
test *args='':
{{PYTHON}} pytest -x --cov=. {{args}}
# 代码检查(CI 同样跑)
lint:
{{PYTHON}} ruff check .
{{PYTHON}} ruff format --check .
{{PYTHON}} mypy .
# 自动 fix
fix:
{{PYTHON}} ruff check . --fix
{{PYTHON}} ruff format .
# DB migrate / shell / etc
migrate:
{{PYTHON}} python manage.py migrate
shell:
{{PYTHON}} python manage.py shell
makemigrations *args='':
{{PYTHON}} python manage.py makemigrations {{args}}
# 部署相关
deploy env:
@echo "deploying to {{env}}..."
./scripts/deploy.sh {{env}}
*args='' 收尾通过位置传给 recipe(如 just test forum/tests.py)。
与 npm scripts 对比
package.json:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"test": "vitest"
}
}
- JSON 单行字符串 → 复杂命令难看
- 跨平台 (Windows) 转义不一致
- 只能 cd 到 package.json 所在目录跑
just 更适合多 layer / 多语言项目。npm script 适合纯 JS 单项目。
很多项目我两个都用:package.json 给 JS 的 thin wrapper,justfile
给跨语言 orchestration(justfile 调 npm script)。
CI 集成
GitHub Actions:
- uses: extractions/setup-just@v2
- run: just lint
- run: just test
CI = 本地的 just,绝对一致。
与 mage / task / make 对比
| just | make | task (taskfile.dev) | mage | |
|---|---|---|---|---|
| 语言 | rust | C | go | go |
| 配置 | justfile | Makefile | Taskfile.yml | magefile.go |
| 跨平台 | ✅ | 弱 | ✅ | ✅ |
| 学习曲线 | 低 | 中 | 低 | 中 |
| 适合 | 通用任务跑 | C/C++ build | 现代替代 make | go 项目 |
just 是"现代 Make 替代品 for 命令"。如果你在做实际编译依赖跟踪(如 C/C++
build),用 make 或 cmake。
踩过的坑
-
PATH 不一致:CI 跑 just → recipe 里
npx找不到。set shell := ["bash", "-cu"]+ ensure tool 装好。 -
dotenv 自动加载敏感变量到子进程:
set dotenv-load让.env
变量进所有 recipe shell。生产 secrets 不要放项目根.env,分开。 -
recipe shell 默认 sh 不是 bash:
pipefail等 bash-only。
set shell := ["bash", "-cu"]改。 -
变量插值与 shell 冲突:
{{VAR}}是 just 模板,shell 里用
${VAR}是 shell 变量。混着用要小心。 -
递归 just 调 just:可以但易嵌套深 → 跑得乱。一般保持扁平结构。
登录后参与评论。