@denny-il/devenv

中文文档
0.7.0发布于 2026/10/31MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 2578

每个工作树都有一个孤立的本地开发堆栈:编译服务、主机应用程序和Tailscale上的HTTPS

中文使用文档
文档目录13 节
  1. 安装
  2. 更新
  3. 代理技能
  4. 图标
  5. 装一台机器
  6. 一个项目提供什么
  7. 只有主机的应用程序
  8. 配置
  9. 堆栈的表现
  10. 分级
  11. 机器上的每一个堆
  12. 沙盒下边
  13. 制定这套计划

守护者

一个项目本地堆栈的命令: Docker 编译服务, apps 运行在主机上, 当被问及时, HTTPS 访问 a 上的每个设备 分级网.

每一次退票都有自己的堆积 所以项目运行的几棵工作树 并肩而来. 除了这台机器,什么也听不到.

Linux和macOS,节点22.18或更新. 配有编译服务的堆栈也需要 Docker Confose 2.24.4 或更新鲜.

安装

pnpm add -D @denny-il/devenv
// package.json
{ "scripts": { "local": "devenv" } }

更新

pnpm update @denny-il/devenv

此移动到最新版本中 package.json 允许。 在此之前 1.0 范围,例如 ^0.2.0 仅覆盖补丁发布; --latest 过去了 这个.

pnpm更喜欢已经出去一天的版本,所以更新可以保持 旧版本在那之前。 要立即发布, 豁免包在 项目的 pnpm-workspace.yaml数字 :

minimumReleaseAgeExclude:
  - "@denny-il/devenv"

代理技能

软件包包含在项目中使用的编码代理技术 发射装置:命令及其规则、配置以及如何移动一个 上线 从已安装的软件包中安装,然后再次安装 更新 :

npx skills add ./node_modules/@denny-il/devenv

图标

命令它会做什么
devenv up启动任何服务, 运行 compose.init,指定应用程序端口,并运行 setup。 。 。 .
devenv start运行一个堆起的每个应用程序,直到一站.
devenv start --tailscale同样的,随着应用 服务在这个机器的尾网 通过HTTPS.
devenv stop停止这个工作树的运行 start如果有的话,并等待 直到它的应用停止.
devenv status显示服务、应用程序 URL,以及是否 start 正在运行.
devenv run -- <command>运行带有堆栈环境的命令.
devenv test [-- <args>]在他们自己的新堆上进行测试,之后总是被移除.
devenv down停止应用程序和服务; 保留服务的名称卷.
devenv reset停止应用并删除此工作树的容器,卷,图像,状态.
devenv list显示此机上的每个堆栈 .
devenv prune删除已退出的堆栈及其数据.
devenv setup [docker] [tailscale]在此机上安装多克和分级,并设置.
devenv tailnet info显示这台机器的尾网名称 以及它无法服役的原因 如果有的话.
devenv tailnet serve服务于给定的本地端口到尾网,直到停止,没有任何项目.

堆栈有两部分,各有生平. up 编写报告: 服务,它一直运行在 Docker 下直到 down,以及 setup。 。 。 . start ctrl-C,一个信号, 或者说 devenv stop。要在更改后重新启动应用程序,它们无法接收 他们自己的,跑 devenv stop,则 devenv start运行 devenv up 再来一次 服务变更后, compose.init 或者说 setup,例如拉动 迁移,再起后.

devenv restart 于 0.7. 0 中被删除,但失败时有信件命名它 替换。 在此之前, start 也开始服务并运行 setup。 。 。 .

装一台机器

devenv setup 检查这台机器上的堆栈需要什么并安装什么 失踪. devenv setup docker 财务报告和审定财务报表 devenv setup tailscale 做两个之一. 它在Linux上安装了自有安装器的Docker和Tailscale 马科斯的土生土长 安装者要密码 .

在 Linux 上,它也同时开始两种, 标记到 Tailscale, 让用户运行 多克和在Tailscale服务。 只有一个人能做的是打印: macOS 打开两个应用程序并签名, 并在任何启用 HTTPS 的机器上 尾网证书.

再运行到检查每行; 它不会改变任何已经存在的 已经就位.

一个项目提供什么

一个项目适应发射装置,而不是相反.

  • 编写文件( 可选) . 基本文件和每个模式的叠加。 服务出版 它们在 Docker 指定的回路端口上的端口 (单位:千美元)ports: [{ target: 5432, host_ip: 127.0.0.1 }]永远不要在固定的. 准备状态是 healthcheck服务一旦开通,就准备好. 启动器命名了“ 编译” 项目, 只开始服务 在剖面图之外.
  • 应用软件. 每一个都从环境中夺去其港口 监听 127.0.0.1: dev 服务器,或构建然后构建的命令 服务建筑。 每个应用程序自行选取;一叠可以混合两种.
  • 环境. 从堆栈到变量的函数 命令获取, 在根上方 .env一棵没有 .env 得到主检查.

只有主机的应用程序

没有容器依赖性的项目省略 compose (或设定) compose: { files: [] } (没有上下文) 普通命令从不探测或启动 Docker 这些堆栈,包括 status, (中文(简体) ), down, (中文(简体) ), reset 财务报告和审定财务报表 test。 。 。 .

import { defineConfig } from "@denny-il/devenv";

export default defineConfig({
  name: "app",
  apps: {
    server: {
      command: "pnpm server dev",
      ports: { http: {}, worker: { internal: true } },
      env: (ports) => ({
        HOST: "127.0.0.1",
        PORT: ports.http,
        WORKER_PORT: ports.worker,
      }),
    },
    web: {
      command: "pnpm web dev",
      env: (ports) => ({ HOST: "127.0.0.1", PORT: ports.http }),
    },
  },
  env: ({ root, port, url }) => ({
    APP_CONFIG: `${root}/config.ts`,
    API_ORIGIN: `http://127.0.0.1:${port("server.http")}`,
    WEB_URL: url("web"),
  }),
});

up 运行设置和指定并记住端口,所以 run 可以使用 环境; start 像往常一样运行应用程序 start --tailscale 服务于 公共应用端口 并保持内部的隐私. status 报告这些 URL 是否为 start 正在运行,不是每个应用程序都回答. down 暂停 a 运行 start标记堆栈停止并保持其港口; reset 暂停 a 运行 start 并去去州. 主机文件中的 App 数据留给 管理项目.

test 运行 test.setup 财务报告和审定财务报表 test.command 带有新应用程序端口和 a 单独上下文,不启动应用程序. list 呼叫准备 只有主机堆栈 ready,而只有东道主的孤儿可以在没有多克的情况下被挤出. list 需求 仅用于装有容器的Dev堆栈; prune 需求 它的堆栈,其测试可能 离开了多克资源.

在转换已存在的 Compose 堆栈之前, 运行 reset 删除其 资源。 旧的状态文件仍为状态; 删除 compose 从 配置不会绕过他们的清理,和 reset 能取名清净. 如果状态无法读取,则其模式未知: reset 尝试 由名清净. 当 Docker 不可用时, 它会重新发送本地状态并警告 指定项目可能仍有容器或体积需要取出.

仅包含一个配置 compose.test 文件保存 start, (中文(简体) ), up, (中文(简体) ), status, (中文(简体) ), list 财务报告和审定财务报表 down 独立于多克. test, (中文(简体) ), reset 和孤苦 需要多克来管理它的测试堆栈. 删除测试文件不 块主机应用程序:保存的清理元数据保存到 reset被抛弃了 测试资源仍然可以稍后删除。 编译变量被刷新 ; 当 Dev 编译服务可以创建时冻结 数量.

配置

devenv.config.ts (或 .js在项目根中,从 它下面的任何目录 :

import { defineConfig } from "@denny-il/devenv";

export default defineConfig({
  // Names the Compose projects: `shop-local-<worktree>`, `shop-test-<worktree>-<run>`.
  name: "shop",

  compose: {
    files: [".infra/compose.yml"],
    dev: [".infra/compose.local.yml"],
    test: [".infra/compose.test.yml"],
    // Services that do a job and exit. Each runs once the others are ready.
    init: ["create-bucket"],
    // Variables for the Compose files. A stack keeps the values its volumes
    // were created with until `reset`.
    env: {
      POSTGRES_USER: process.env.POSTGRES_USER || "shop",
      POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD || "shop",
    },
  },

  // Started by `start` in this order, without waiting for one another.
  apps: {
    api: {
      command: "pnpm --filter api dev",
      // `internal` ports are reserved, but neither listed nor served.
      ports: { proxy: {}, worker: { internal: true } },
      env: (ports) => ({
        API_HOST: "127.0.0.1",
        API_PORT: ports.proxy,
        WORKER_PORT: ports.worker,
      }),
    },
    // Without `ports`, an app has one port named `http`.
    web: {
      command: "pnpm --filter web dev",
      env: (ports) => ({ HOST: "127.0.0.1", PORT: ports.http }),
      // Optional: `start` reports the stack ready once this answers.
      ready: { path: "/" },
    },
  },

  env: ({ service, vars, url, project }) => ({
    DATABASE_URL: `postgresql://${vars.POSTGRES_USER}:${vars.POSTGRES_PASSWORD}@127.0.0.1:${service("postgres").port(5432)}/shop`,
    API_URL: `${url("api.proxy")}/api`,
    WEB_URL: url("web"),
    // Browsers share cookies across ports: a name per worktree keeps their
    // sessions apart.
    COOKIE_PREFIX: project,
  }),

  // Run by `up` once the services are up.
  setup: ["pnpm database migrate", "pnpm database seed"],

  test: {
    setup: ["pnpm database migrate"],
    // Arguments after `devenv test --` are added; a function decides itself.
    command: "vitest --run",
    env: { DATABASE_TESTS: "true" },
    // Compose variables of the test stack alone, over `compose.env`.
    compose: { env: { POSTGRES_PASSWORD: "test" } },
  },

  // Printed under the URLs by `start` and `status`.
  info: () => ({ "Sign-in": "[email protected] / admin" }),
});

命令是 shell 的行,或者是程序及其参数的列表.

函数将堆栈作为上下文 :

成员这是什么
service(name).port(target)环回端口多克发布服务端口开启.
port(ref)应用程序端口 : 'api.proxy',或 'web' 一个端口的应用程序.
url(ref)端口的源头.
vars堆栈使用时的 Confose 变量 .
project堆栈"作曲"项目名称.
root项目根.
tailnet这机器的尾网名称,下方 start --tailscale。 。 。 .

堆栈的表现

  • 开口. Docker 指定服务端口; 启动器选择免费 应用程序的端口,并在下次运行时使用相同的端口 免费, 所以 URL 打开其他地方继续工作 .
  • 州会. 每个堆栈的端口和作曲变量都保存在 ~/.local/state/devenv/stacks/<project>.json (单位:千美元) $XDG_STATE_HOME 何时 ),而不是在离职时。 所以证书没有工作空间, 并仍然可以找到一个堆栈 在其退货之后.
  • 准备. 应用开始顺序不相等. 一个应用 ready 一旦它的端口接受连接, 计数就绪, 或,带有 path,通过HTTP回答,状态低于400. start 一旦每个这样的应用程序都准备好了就打印 URL, 在此之前只打印 它在等着呢 一个应用没有 ready 报告为开始,其中 还没回答呢 在它之前退出的应用程序 已准备好,或尚未准备好 timeout (300秒,除非 ),启动失败并停止堆栈.
  • 停下来. 每个应用程序的流程组都得到一个SIGINT,无论停止什么 start,以及 start 结尾 Stopped (<signal>): <apps>。 。 。 . devenv stop 停止工作树的运行 start 从任何地方,和 devenv start 再次运行应用程序 各种服务一直持续。 十个 数秒后,一个应用程序的流程组中仍然运行的是 kill, 即使应用程序的命令本身已经退出: 服务器 也就是停止建设 它开始得到整个10秒。 任何应用程序 停止停止堆叠.
  • 考证. 每次运行都有自己的编曲项目,在运行时删除 结束,Ctrl-C上也有,为它所建的图像. 被杀死的一跑 直接清理 下一个,或 reset,连同任何 compose.init 工作它运行.
  • .env 在工作树上. .env 不被检查,所以一个工作树 开始没有。 直到它拥有它自己的, 主要的退票已经加载, 一条线说。 一个空的 .env 在工作树上关闭它.

分级

devenv start --tailscale 为每个非应用程序端口服务 internal 作为 https://<machine>.<tailnet>.ts.net:<port>的应用程序 URL 运行,在这个机器上也.

每个尾网和机器一次:

  • 在尾网启用 HTTPS 证书 DNS 页面。 。 。 .
  • 在Linux上,允许您的用户服务: sudo tailscale set --operator=$USER。 。 。 .

给新名字的第一个请求需要半分钟的证明 已印发。 当发射机停止时, 条目会消失; 这里从未运行过 tailscale serve reset,可以抹去每个项目的条目.

所有能在尾网上到达这台机器的人都到达了堆栈. 对a Vite dev 服务器 发射器集 __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS这样 它接受尾网名称而不改变配置.

机器上的每一个堆

devenv list 显示每个堆栈的取出和是否运行, 被拦截或成为孤儿。 一叠就成了孤儿,一旦它退出了 当一个工作树被删除时会发生 devenv reset:其容器和 卷会留在多克 没有任何东西可以管理它们.

devenv prune 列出孤儿名单,并在 " 是 " 之后,将孤儿连同他们的 数据与已建图像。 被移动或坐落在没有挂载的磁盘上的检出,外观 与被删除的相同,在达成一致之前阅读清单。 没有 除非给定,否则它不会删除任何东西 --yes。 。 。 .

沙盒下边

在沙盒中运行命令的代理需要写入 ~/.local/state/devenv,加上用于堆栈的多克套接字。 无 第二,命令在启动任何事项并命名目录之前停止.

制定这套计划

pnpm check && pnpm test

skills/use-devenv 描述发射装置在项目中使用的剂 这个 用它描述的行为来改变它.

出版物由 Publish 工作流程,手动发送 main,与 npm 信任的出版。 发行的PR先会打出版本; 工作流程检查其输入匹配 package.json检查 和试验,建造 dist/ (未执行),出版,然后标记 承诺并创建其 GitHub 释放。 重播完成一个发布 并且再也不会出版另一本书:

pnpm version patch --no-git-tag-version   # or minor; merged in a PR
gh workflow run publish.yml --ref main -f version=<version>

.agents/skills/release 给代理人同样的步骤, 检查什么 首先,当一个失败.

版本与发布记录

@denny-il/devenv 共发布 8 个版本,首次发布于 2026/10/11;过去 12 个月发布了 8 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.7.0latest2026/10/3112 天前
0.6.12026/10/2121 天前
0.6.02026/10/2121 天前
0.5.02026/10/2121 天前
0.4.02026/10/1824 天前
0.3.02026/10/1329 天前

关于 @denny-il/devenv 的常见问题

@denny-il/devenv 是什么?

每个工作树都有一个孤立的本地开发堆栈:编译服务、主机应用程序和Tailscale上的HTTPS

如何安装 @denny-il/devenv?

在项目目录运行 npm install @denny-il/devenv,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 devenv,可以用 npx devenv 直接运行。

@denny-il/devenv 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@denny-il/devenv 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@denny-il/devenv 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.18.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@denny-il/devenv 可以商用吗?

@denny-il/devenv 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@denny-il/devenv 的下载量有多少?

根据 npm 官方下载统计,@denny-il/devenv 在 2026/10/12 – 2026/11/10 这 30 天内被下载 2,578 次,日均约 86 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@denny-il/devenv 还在维护吗?

最新版本 0.7.0 发布于 2026/10/31(12 天前);至今共发布 8 个版本,其中过去 12 个月发布了 8 个;首次发布于 2026/10/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。