-
创建项目
请先安装 Node.js 24.15 或更高版本。
命令会将
ship作为项目名传给创建器。创建器会建立同名目录,并把 TypeScript 模板复制进去。它不会覆盖已有目录。如果你使用 Agent 自动创建,请参考 Agent 创建指引。npm init func@latest ship终端npm init func@latest shipnpm init func@latest shipyarn create func shippnpm create func shipbun create func ship -
安装并检查生成的 CLI
进入新目录、安装依赖,然后运行模板自带的帮助处理器。
cd ship npm install npm run dev -- --help终端cd ship npm install npm run dev -- --helpcd ship npm install npm run dev -- --helpcd ship yarn install yarn dev --helpcd ship pnpm install pnpm dev --helpcd ship bun install bun run dev -- --help
认识生成的项目
在默认模板中,src 文件夹用于存放所有业务代码,tests 用于存放测试用例,如果你后续运行 build 命令则还会出现 dist 文件夹。通常在最后发布时,只有 dist 文件夹的内容会被发布。
.
|-- src
| |-- app.module.ts 根模块
| |-- commands
| | |-- deploy
| | | |-- deploy.command.ts 部署命令示例
| | | |-- deploy.module.ts 部署功能模块
| | | +-- deploy.service.ts 部署业务服务
| | +-- greet
| | |-- greet.command.ts 问候命令示例
| | |-- greet.module.ts 问候功能模块
| | +-- greet.service.ts 问候业务服务
| |-- decorators
| | +-- url.decorator.ts 自定义 URL 值装饰器
| |-- shared
| | |-- services
| | | +-- output.service.ts 共享输出服务
| | +-- shared.module.ts 共享功能模块
| +-- index.ts 可执行入口
|-- tests
| |-- cli
| | +-- smoke.test.ts 构建产物冒烟测试
| |-- commands
| | |-- catch.test.ts 错误过滤测试
| | |-- deploy.test.ts 部署命令测试
| | |-- greet.test.ts 问候命令测试
| | +-- help.test.ts 帮助输出测试
| +-- utils
| +-- cli.ts CLI 测试工具
|-- .gitignore Git 忽略规则
|-- LICENSE 开源许可证
|-- README.md 项目说明
|-- package.json
|-- tsconfig.json
|-- vitest.cli.config.mts
+-- vitest.config.mts安装依赖后,项目根目录还会出现当前包管理器对应的 lockfile;运行 build 后会生成 dist。这些生成文件没有列在上面的初始结构中。
根模块 (app.module.ts) 会收集并注册 func 可调用的命令和选项以及其他依赖。为了聚焦核心结构,下面省略了模板已经启用的可选能力配置:
import { Module } from 'func'
import { DeployModule } from './commands/deploy/deploy.module'
import { GreetModule } from './commands/greet/greet.module'
@Module({
imports: [GreetModule, DeployModule],
})
export class AppModule {}开发时运行命令
模板通过普通 npm scripts 暴露 funcgo:
{
"scripts": {
"dev": "funcgo dev --",
"build": "funcgo build"
}
}npm 标签中的 npm run dev -- <参数> 使用的是 npm 参数透传规范。第一个 -- 告诉 npm 停止解析自己的选项,把后续内容追加到 script;script 末尾 的 -- 用于区分 funcgo dev 和你的 CLI 参数。位于它后面的 token 不属于 funcgo。应用代码不需要自行解析或移除这两个分隔符。
npm run dev -- greet
npm run dev -- greet --name Ada
npm run dev -- greet shout --name Adanpm run dev -- greet
npm run dev -- greet --name Ada
npm run dev -- greet shout --name Ada yarn dev greet
yarn dev greet --name Ada
yarn dev greet shout --name Ada pnpm dev greet
pnpm dev greet --name Ada
pnpm dev greet shout --name Ada bun run dev -- greet
bun run dev -- greet --name Ada
bun run dev -- greet shout --name Ada 每次调用只执行一次 TypeScript 入口,无需生成生产 bundle,适合在编辑命令时快速验证。 其他包管理器的等价写法可以通过终端右上角切换。
添加第一个命令
创建一个带有固定命令路径和默认处理器的类。类名只在 TypeScript 代码中使用;用户实际输入的是 @Command 中的 path。
import { Command, Handler } from 'func'
@Command({
path: 'status',
description: 'Print service status',
})
export class StatusCommand {
@Handler()
run() {
console.log('All systems operational')
}
}将它加入命令列表,由 AppModule 注册后运行 npm run dev -- status。
如果要添加别名或多个动作,请阅读命令 ;如果要接收标志和值,请阅读 字段选项。
可选:把命令映射到全局
这一步不是使用 funcgo 的必要条件。只有希望在开发期间直接输入最终命令名进行调试(例如 ship)时才需要创建全局链接;否则继续使用 npm run dev -- <命令> 即可。
开发期间,包管理器可以把当前包映射到全局命令目录。由于 package.json#bin 指向 生成的 dist/bin.js ,请在项目根目录构建并创建链接:
npm run build
npm link
# 使用 package.json#bin 中的键名
ship --helpnpm run build
npm link
# 使用 package.json#bin 中的键名
ship --help yarn build
yarn global add file:.
# 使用 package.json#bin 中的键名
ship --help pnpm build
pnpm add --global .
# 使用 package.json#bin 中的键名
ship --help bun run build
bun link --global
# 使用 package.json#bin 中的键名
ship --help 这里的命令名是 ship,因此可以运行上面的 ship --help 。映射使用当前项目的构建产物;源码变化后请重新生成 bundle,必要时重新执行映射命令。
取消映射时,使用当前包管理器对应的解除映射命令:
npm uninstall --global shipnpm uninstall --global ship yarn global remove ship pnpm remove --global ship bun unlink 监听文件并持续构建
funcgo build --watch 启动时会执行一次构建,之后默认监听 src/**/*.ts ,匹配文件变化后自动重新构建。可以在一个终端保持监听,在另一个终端调用已经全局链接的命令。按 Ctrl+C 停止监听。
npm run build -- --watch
# 监听额外文件或自定义 glob
npm run build -- --watch --watch-path 'src/**/*.ts' --watch-path config.jsonnpm run build -- --watch
# 监听额外文件或自定义 glob
npm run build -- --watch --watch-path 'src/**/*.ts' --watch-path config.json yarn build --watch
# 监听额外文件或自定义 glob
yarn build --watch --watch-path 'src/**/*.ts' --watch-path config.json pnpm build --watch
# 监听额外文件或自定义 glob
pnpm build --watch --watch-path 'src/**/*.ts' --watch-path config.json bun run build -- --watch
# 监听额外文件或自定义 glob
bun run build -- --watch --watch-path 'src/**/*.ts' --watch-path config.json 每个 --watch-path 都可以是文件、目录或正向 glob。配置文件位于 src 之外时,可以用它补充监听范围。生成目录、node_modules 和.git 会被忽略。
首次运行的常见问题
终端找不到全局命令
确认构建已经生成 dist/bin.js,在包根目录执行 npm link ,并使用 package.json#bin 中的键名,而不是包名调用命令。
Func 提示未知命令
请从已注册的命令列表导出命令类。仅创建文件和添加 @Command() 并不会自动注册该类。
npm 吞掉了本应传给 CLI 的选项
保留参数透传分隔符:使用 npm run dev -- status --json。只有 -- 后面的 token 才属于你的 CLI。
打包并准备发布
build script 会把配置的 TypeScript 入口打包到 func.outDir(模板默认 为 dist),并创建可执行的 bin.js。包内的 bin 字段决定用户安装后可以调用的命令名。
构建打包
funcgo build 默认使用 n24,生成面向 Node.js 24.15 及以上版本的产物。需要兼容较低版本时,可以通过 --target 选择 n22 或 n20。Node.js 20 已停止维护,选择 n20 时每次构建都会显示 EOL 警告。
npm run build
npm run build -- --target n22
npm run build -- --target n20构建只检查 package.json#engines.node 是否与目标版本一致并给出警告,不会主动改写 package 信息。准备发布前,请确保 n20、n22、n24 分别对应最低版本 20.19.0、22.12.0、24.15.0。
npm run build
npm pack --dry-runnpm run build
npm pack --dry-run yarn build
yarn pack --dry-run pnpm build
pnpm pack --dry-run bun run build
bun pm pack --dry-run 终端中的 dry-run pack 命令只展示即将发布的文件,不会真正发布。请确认列表中包含 bundle、 包信息、README 和 license;确认无误后,运行 npm publish 才会真正发布到 npm。自定义入口、输出、 外部依赖和监听范围见工具链。