惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
有赞技术团队
有赞技术团队
博客园 - 司徒正美
量子位
N
News and Events Feed by Topic
T
Threatpost
Last Week in AI
Last Week in AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
酷 壳 – CoolShell
酷 壳 – CoolShell
C
CERT Recently Published Vulnerability Notes
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
Intezer
人人都是产品经理
人人都是产品经理
T
Tenable Blog
IT之家
IT之家
雷峰网
雷峰网
腾讯CDC
博客园 - 聂微东
V
Visual Studio Blog
S
SegmentFault 最新的问题
Scott Helme
Scott Helme
Spread Privacy
Spread Privacy
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
N
Netflix TechBlog - Medium
J
Java Code Geeks
宝玉的分享
宝玉的分享
F
Full Disclosure
WordPress大学
WordPress大学
A
Arctic Wolf
小众软件
小众软件
AWS News Blog
AWS News Blog
Attack and Defense Labs
Attack and Defense Labs
NISL@THU
NISL@THU
AI
AI
Hugging Face - Blog
Hugging Face - Blog
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
N
News | PayPal Newsroom
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org

博客园 - 丁少华

Neon白嫖免费pgsql 域名利用cloudflare免费图床 nginx反代CloudflarePages提示502 vite使用shadcn vite使用biome Window下Nginx winserver2022安装不上软件 mac已损坏无法打开 代码高亮 命令运行器之just windows开启wsl 白嫖Redis 白嫖MongoDB vercel无服务函数 无服务器函数完全指南 在线 mock 方案 解释型语言和编译型语言 何时该使用monorepo monorepo前端专属吗 Cursor锁区问题 CentOS9上Let’s Encrypt自动续签 Windows给文件夹别名 ai 常识 nestjs逆向工程Prisma与DTO nestjs的orm之Prisma
命令运行器之task
丁少华 · 2026-03-12 · via 博客园 - 丁少华

前言

Makefile/Just/Task 哪个更现代,是未来趋势?

Make/Just: 它们本质上是 Shell 转发器。在 Windows 上它们调 powershell,在 Linux 上调 bash。如果你写了 rm -rf,在没有配置好的 Windows 环境下就会直接报错。

Task: 它内置了一个 Go 语言编写的 Shell 解释器。这意味着你在 Taskfile 里写的脚本逻辑,在所有操作系统上运行结果几乎完全一致,不再需要像你之前在 justfile 里那样痛苦地写 if os() == "windows"。

就连 GitHub Actions 官方文档都推荐 Task(虽然和Just的star相差一倍)!

Task两者Just都宣称自己是Make专门用于任务运行的替代方案。

这里介绍的是Task(file)

安装

windows

推荐使用 scope(类似于mac下的brew)来安装它,那我们先安装scope

# 普通用户
irm get.scoop.sh | iex
# admin用户
iex "& {$(irm get.scoop.sh)} -RunAsAdmin"

使用scope来安装just

scoop install task

macos

brew install go-task

最后确认下

task --version

使用

以下是一个 同时启动前后端的配置!

version: '3'
output: prefixed
vars:
  VENV_BIN: '{{if eq OS "windows"}}.venv/Scripts{{else}}.venv/bin{{end}}'
  PYTHON: '{{.VENV_BIN}}/python'
tasks:
  default:
    desc: "启动"
    cmds:
      - task: dev
  dev:
      desc: "启动开发环境"
      cmds:
        - "echo ✈ 启动开发环境..."
      deps: [backend, frontend]
  install-web:
    desc: "安装前端依赖"
    dir: web
    cmds:
      - pnpm install
  install-server:
    desc: "安装后端依赖"
    dir: server
    cmds:
      - uv sync
  install:
    desc: "安装依赖"
    cmds:
      - task: install-web
      - task: install-server
  frontend:
    desc: "启动前端"
    dir: web
    cmds:
      - "echo 🚀 启动前端"
      - pnpm run dev
  backend:
    desc: "启动后端"
    dir: server
    cmds:
      - "echo 🚀 启动后端"
      - "{{.PYTHON}} -m uvicorn server.app:server --reload --host 0.0.0.0"
  stop:
    desc: "停止后端服务 (强杀端口)"
    cmds:
      - "{{if eq OS \"windows\"}}stop-process -Id (Get-NetTCPConnection -LocalPort 8000).OwningProcess -Force{{else}}lsof -t -i:8000 | xargs kill -9{{end}}"
    ignore_error: true
  restart:
    desc: "重启后端服务"
    cmds:
      - task: stop
      - task: backend
  build-web:
    desc: "构建前端静态文件"
    dir: web
    cmds:
      - pnpm build
  # 其实这个意义不大,相当于本地preview,因为部署服务器如果走cd/ci的话(比如 github action),就无法利用task
  start:
    desc: "启动服务"
    cmds:
      - "echo 🚀 启动服务: 将前端打包到后端静态目录中,并启动后端服务"
      - task: build-web
      - "rm -rf server/server/static/* && mkdir -p server/server/static"
      - "cp -r web/dist/* server/server/static/"
      - task: backend

其它

拆分任务

比如

tasks:
  install:
    desc: "安装依赖"
    cmds:
      - "cd web && pnpm install"
      - "cd server && uv sync"

Task 提供了一个 dir 参数,专门用来指定该任务执行的工作目录。这样你的命令会变得非常干净。而且把你原来的两行拆成 install-web 和 install-server 有一个巨大的好处-并发执行(Speed!)。

tasks:
  install-web:
    desc: "安装前端依赖"
    dir: web
    cmds:
      - pnpm install

  install-server:
    desc: "安装后端依赖"
    dir: server
    cmds:
      - uv sync

  # 组合任务
  install:
    desc: "一键安装所有依赖"
    cmds:
      - task: install-web
      - task: install-server

变量和使用变量

在 Task (Taskfile) 的语法中,{{.PYTHON}} 是一个变量引用。
你可以把它理解为 Python 里的 f"{PYTHON}" 或者 JS 里的 ${PYTHON}。它的作用是把你在顶部 vars 模块里定义的内容,“填”到你的命令里。

vars:
  PYTHON: ".venv/bin/python" # 1. 在这里定义

tasks:
  backend:
    cmds:
      - "{{.PYTHON}} --version" # 2. 在这里引用

并发

deps (Dependencies) 是 Taskfile 中处理并发启动的最佳方式。当你把任务放在 deps 里时,它们会同时启动。

dev:
  cmds:
    - task: backend   # 1. 启动后端,进程在这里被阻塞(因为 uvicorn 会一直运行)
    - task: frontend  # 2. 只有当前面的后端关闭了,才会运行前端

因为 uvicorn 和 pnpm dev 都是常驻进程(Long-running processes),它们不主动结束,下一行命令就永远不会开始。

# 建议在顶部加上这个,让并发运行的日志带有前缀颜色,方便分辨
output: prefixed

tasks:
  dev:
      desc: "一键启动前后端"
      # deps 里的任务会并行(parallel)执行
      deps: [backend, frontend]

为什么方案 A (deps) 更好?
日志交织处理:当你同时启动前后端时,屏幕上会瞬间涌出大量日志。配合 output: prefixed,Task 会在每行日志前加上 [WEB] 或 [API],否则你根本分不清谁是谁。

生命周期管理:当你按 Ctrl + C 时,Task 会作为“父进程”捕捉到信号,然后同时关闭它启动的所有子进程(前端和后端)。

真正的跨平台:不需要去考虑 Shell 的后台运行符(如 &),因为 & 在 Windows 的 PowerShell 下行为很怪异,而 deps 是 Task 内部实现的,全平台表现一致。

vscode

image

关于taskfile支持的vscode插件,一共两个,只用第一个就够了:

  • 在侧边栏查看任务。
  • 从侧边栏和命令面板运行任务。
  • 从侧边栏和命令面板转到定义。
  • 运行最后一个任务命令。
  • 支持多根工作区。
  • 在当前工作区中初始化任务文件。

image

github aciton

当前项目如何利用GitHub action自动部署呢?

参考 .github\workflows\deploy.yml

name: Build & Deploy

on:
  push:
    branches: [main]
  workflow_dispatch:

env:
  DEPLOY_DIR: /home/apps/lark-monitor-server
  REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
  REMOTE_PORT: ${{ secrets.REMOTE_PORT || 22 }}
  SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # ---------- 前端构建 ----------
      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
          cache-dependency-path: web/pnpm-lock.yaml

      - name: Install frontend dependencies
        run: pnpm install
        working-directory: web

      - name: Build frontend
        run: pnpm build
        working-directory: web

      # ---------- 打包产物 ----------
      - name: Prepare artifact
        run: |
          rm -rf server/server/static/*
          mkdir -p server/server/static
          cp -r web/dist/* server/server/static/
          tar -czf release.tar.gz -C server .

      # ---------- 部署到服务器 ----------
      - name: Deploy to server
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ env.REMOTE_HOST }}
          port: ${{ env.REMOTE_PORT }}
          username: root
          key: ${{ env.SSH_PRIVATE_KEY }}
          source: release.tar.gz
          target: /tmp

      - name: Deploy and restart
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ env.REMOTE_HOST }}
          port: ${{ env.REMOTE_PORT }}
          username: root
          key: ${{ env.SSH_PRIVATE_KEY }}
          script: |
            mkdir -p ${{ env.DEPLOY_DIR }}
            tar -xzf /tmp/release.tar.gz -C ${{ env.DEPLOY_DIR }}
            rm /tmp/release.tar.gz
            cd ${{ env.DEPLOY_DIR }} && uv sync
            # 杀掉旧进程,重新启动
            lsof -t -i:8000 | xargs -r kill -9 || true
            nohup .venv/bin/uvicorn server.app:server --host 0.0.0.0 --port 8000 > uvicorn.log 2>&1 &

nginx代理

非必看,和本教程无关。
如上的项目我部署的服务器和nginx服务不是同一台,怎么代理过去呢?

# xx.dingshaohua.com
server {
    listen       80;
    server_name  lark.dingshaohua.com;
    rewrite ^(.*)$ https://$host$1 permanent;
}
server {
    listen       443 ssl;
    server_name  xx.dingshaohua.com;
    include conf.d/common.conf;

     location / {
        proxy_pass http://xx.xx.xx.xx:8000;
    }
}

参考

https://blog.csdn.net/gitblog_00247/article/details/151125318