@kaiyan/init
v0.8.1
Published
Kaiyan 全自动初始化 CLI(拉取模板、创建云资源、生成 env、push 触发流水线)
Downloads
7,132
Readme
@kaiyan/init
Kaiyan 全自动初始化 CLI,实现从零到生产环境的一键部署。
当前版本: 0.7.3
目录
概述
@kaiyan/init 是一个自动化 CLI 工具,用于快速初始化基于 ky-framework 模板的全栈项目。它会自动完成以下工作:
- 克隆模板仓库并初始化 git
- 安装依赖并配置 pnpm
- 创建阿里云 OSS Bucket(生产环境)
- 构建并部署后端到阿里云函数计算 (FC3)
- 生成前后端环境变量文件
- 创建 GitHub 仓库并同步 Secrets
- 推送代码触发 CI/CD 流水线
简化架构:只部署生产环境(FC + OSS),本地开发使用 pnpm dev:frontend/backend 连接 dev RDS。详见 架构简化方案。
技术架构
FC3 自定义运行时
项目使用阿里云 FC3 的自定义运行时(custom.debian12),而非内置的 nodejs20 运行时:
| 特性 | 说明 |
|------|------|
| 运行时 | custom.debian12 |
| Node.js | /var/fc/lang/nodejs22/bin/node |
| 启动方式 | NestJS 直接监听端口,FC 作为反向代理 |
| 端口 | 9000(通过 FC_SERVER_PORT 环境变量) |
优势:
- 代码简洁:无需 FC Handler 适配代码
- 本地与线上一致:同一份代码在本地和 FC 上运行行为相同
- 无需适配库:FC 只做流量转发,不涉及 request/response 对象转换
- 更好的可移植性:代码不依赖 FC 特定 API
技术栈
| 组件 | 技术 | 版本要求 | |------|------|----------| | 运行时 | Node.js | >= 22.0.0 | | 包管理 | pnpm | >= 10.0.0 | | 后端框架 | NestJS | 最新 | | 数据库 ORM | Prisma | 最新 | | 前端框架 | React + Vite | 最新 | | 部署工具 | Serverless Devs 3.x | FC3 组件 |
完整工作流程
脚本执行的详细步骤如下:
1. 环境检查
ensureNodeAndPnpm() → 检查 Node.js >= 22, pnpm >= 10
ensureGit() → 检查 git 可用
ensureServerlessDevs() → 检查/安装 Serverless Devs CLI (s)
ensureAliyunCli() → 检查 aliyun CLI(macOS 尝试 brew 安装)
ensureGhAuth() → 检查 GitHub CLI (gh) 已登录2. 收集配置信息
交互式或通过命令行参数收集:
- Region(默认
cn-shenzhen) - 阿里云 AccessKey ID/Secret(必填)
- 数据库连接串:生产库(用于 GitHub Secrets)、开发库(用于本地 .env)
- VPC/VSwitch/SecurityGroup ID(必填,FC 必须与 RDS 同 VPC)
- GitHub 组织(必填)
以下字段自动从项目名派生,无需输入:
- FC 服务名:默认使用项目名
- OSS Bucket 名:默认使用项目名
- GitHub 仓库名:默认使用项目名
3. 克隆模板
cloneTemplate(targetDir)
├── git clone --depth 1 https://github.com/kaiyan-tech/ky-framework.git
├── 删除模板的 .git 目录
└── git init -b main // 立即初始化新仓库,避免 husky 报错4. 修复模板配置
fixSharedTypesExport(targetDir)
└── 调整 packages/shared/package.json 的 types 导出,避免 tsup 警告5. 安装依赖
installDeps(targetDir)
├── 写入 .npmrc 批准构建脚本包(prisma, esbuild 等)
└── pnpm install批准的包列表:
@prisma/client@prisma/enginesprismaesbuild@nestjs/core
6. 生成 Prisma Client
generatePrismaClient(targetDir)
└── pnpm --filter backend prisma:generate7. 更新基础设施配置
updateInfraRegion(targetDir, region)
└── 更新 s.yaml 和 s.prod.yaml 的 region 配置
// functionName 使用环境变量 ${env('FC_SERVICE_NAME')}-api,无需替换8. 创建 OSS Bucket
ensureOssBucket(targetDir, bucket, region, env)
├── 创建临时 aliyun CLI profile
├── aliyun oss mb oss://{bucket} // 创建 Bucket
├── aliyun oss set-acl ... public-read // 设置公开读
├── aliyun oss website ... // 应用 website.xml 配置
└── aliyun oss cors ... // 应用 cors.xml 配置Endpoint 格式: oss-{region}.aliyuncs.com
额外操作: 阿里云的OSS设置成静态页面后,依然无法直接访问,必须到OSS的控制面板中进行手动绑定域名。
9. 构建后端
buildForFc(targetDir)
├── pnpm --filter @kaiyan/shared build
└── pnpm --filter backend build10. 部署到函数计算(生产环境)
deployFc(targetDir, env, { configFile: 's.prod.yaml', envName: 'prod' })
├── 清空 fc-deploy 目录
├── pnpm deploy 创建独立部署包
├── s deploy -y --use-local -t infra/s.prod.yaml
└── 获取生产 FC URLFC 函数命名(自动从项目名派生):
| FC_SERVICE_NAME | 函数名 | 示例(项目名=my-app) |
|-----------------|--------|----------------------|
| ${projectName} | ${FC_SERVICE_NAME}-api | my-app-api |
FC 部署环境变量:
| 变量 | 值 |
|------|----------|
| NODE_ENV | production |
| DATABASE_URL | 生产数据库 |
| JWT_SECRET | 自动生成 |
| JWT_EXPIRES_IN | 7d |
| APP_VERSION | init-{timestamp} |
| MIGRATION_TOKEN | 自动生成 |
| FC_SERVICE_NAME | ${projectName} |
11. 写入环境变量文件
writeEnvFiles(targetDir, answers, fcDomain)
├── apps/backend/.env
└── apps/frontend/.env12. 创建 GitHub 仓库
createGithubRepo(org, name, visibility)
└── gh repo create {org}/{name} --public --confirm13. 同步 GitHub Secrets
syncSecrets(targetDir, answers, fcDomainProd, repoSlug)
└── 遍历所有 secrets,使用 gh secret set 写入14. 推送代码
gitInitAndPush(targetDir, remote)
├── git add .
├── git commit --no-verify -m "feat: 项目初始化 by kaiyan-init"
├── git remote add origin {remote}
└── git push -u origin main注意: 使用 --no-verify 跳过 pre-commit hooks,避免 lint-staged 在初始化时失败。
先决条件
必需工具
| 工具 | 最低版本 | 安装方式 | 说明 |
|------|----------|----------|------|
| Node.js | 22.0.0 | nodejs.org | 运行时环境 |
| pnpm | 10.0.0 | npm install -g pnpm | 包管理器 |
| git | - | 系统自带或 brew/apt | 版本控制 |
| Serverless Devs | 3.x | npm install -g @serverless-devs/s | FC 部署工具(脚本可自动安装) |
| aliyun CLI | - | brew install aliyun-cli | 阿里云资源管理 |
| GitHub CLI | - | brew install gh | GitHub 操作 |
阿里云准备
AccessKey:需具备以下权限
- OSS:创建 Bucket、设置 ACL、配置 website/CORS
- FC:创建/更新函数、触发器
- VPC:读取 VPC/VSwitch/SecurityGroup
RDS 数据库:
- 准备两个数据库:生产环境和开发环境
- 连接串格式:
postgresql://user:pass@host:5432/dbname?schema=public - 生产库用于 FC 部署,开发库用于本地开发
- 确保 FC 所在 VPC 可访问生产数据库
VPC 配置:
- 提供 VPC ID、VSwitch ID、Security Group ID
- RDS 必须在同一个 VPC 内
- FC 必须部署到同一 VPC 以访问数据库
GitHub 准备
安装并登录 GitHub CLI:
gh auth login确保有权限在目标组织下创建仓库
安装
全局安装(推荐)
npm install -g @kaiyan/init使用 npx(无需安装)
npx @kaiyan/init my-project本地开发
cd packages/init
pnpm link --global
# 或
npm link使用方法
交互式(推荐新手)
kaiyan-init my-project按提示依次输入所需信息。
命令行参数(适合自动化)
kaiyan-init my-project \
--ak-id AKID \
--ak-secret AKSECRET \
--db-url "postgresql://user:pass@host:5432/prod?schema=public" \
--db-url-dev "postgresql://user:pass@host:5432/dev?schema=public" \
--vpc-id vpc-xxx \
--vsw-id vsw-xxx \
--sg-id sg-xxx \
--github-org my-org以上命令会自动派生:
- FC 服务名:
my-project - OSS Bucket:
my-project - GitHub 仓库名:
my-project
使用已有仓库
kaiyan-init my-project --no-auto-create-repo
# 然后输入已有仓库地址参数详解
必填参数
| 参数 | 说明 | 示例 |
|------|------|------|
| <project-name> 或 --project | 项目名称,也是目标目录名 | my-project |
| --ak-id | 阿里云 AccessKey ID | LTAI5t... |
| --ak-secret | 阿里云 AccessKey Secret | xxxxxxxx |
| --db-url | 生产环境数据库连接串(用于 GitHub Secrets) | postgresql://... |
| --db-url-dev | 开发环境数据库连接串(用于本地 .env) | postgresql://... |
| --vpc-id | VPC ID(FC 必须与 RDS 同 VPC) | vpc-xxx |
| --vsw-id | VSwitch ID | vsw-xxx |
| --sg-id | Security Group ID | sg-xxx |
| --github-org | GitHub 组织/用户名 | my-org |
可选参数(有智能默认值)
| 参数 | 默认值 | 说明 |
|------|--------|------|
| --region | cn-shenzhen | 阿里云 Region |
| --fc-service-name | 项目名 | FC 服务名 |
| --oss-bucket | 项目名 | OSS Bucket 名 |
| --repo | 项目名 | GitHub 仓库名 |
| --auto-create-repo | true | 是否自动创建 GitHub 仓库 |
| --no-auto-create-repo | - | 使用已有仓库 |
| --help / -h | - | 显示帮助信息 |
自动生成的配置
JWT Secret
- 生成方式:
crypto.randomBytes(32).toString('hex') - 长度: 64 字符十六进制
- 存储位置:
apps/backend/.env、GitHub Secrets
Migration Token
- 生成方式:
crypto.randomBytes(24).toString('hex') - 长度: 48 字符十六进制
- 用途: 保护数据库迁移 API 端点
- 存储位置:
apps/backend/.env、GitHub Secrets(MIGRATION_TOKEN_PROD)
环境变量文件
apps/backend/.env:(本地开发使用 dev 数据库)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://...dev...
JWT_SECRET=<自动生成>
MIGRATION_TOKEN=<自动生成>
JWT_EXPIRES_IN=7d
CORS_ORIGIN=http://localhost:5173
OSS_BUCKET=xxx
VPC_ID=
VSWITCH_ID=
SECURITY_GROUP_ID=apps/frontend/.env:
VITE_API_BASE_URL=https://xxx.cn-shenzhen.fcapp.run
VITE_SENTRY_DSN=GitHub Secrets
脚本会自动同步以下 Secrets 到 GitHub 仓库:
| Secret | 说明 | 来源 |
|--------|------|------|
| ALIYUN_ACCESS_KEY_ID | 阿里云 AK ID | 用户输入 |
| ALIYUN_ACCESS_KEY_SECRET | 阿里云 AK Secret | 用户输入 |
| OSS_BUCKET_PROD | OSS Bucket | 自动派生 |
| FC_SERVICE_NAME | FC 函数名 | 自动派生 |
| DATABASE_URL | 生产数据库连接串 | 用户输入 |
| DATABASE_URL_DEV | 开发数据库连接串 | 用户输入 |
| JWT_SECRET | JWT 密钥 | 自动生成 |
| VPC_ID | VPC ID | 用户输入 |
| VSWITCH_ID | VSwitch ID | 用户输入 |
| SECURITY_GROUP_ID | 安全组 ID | 用户输入 |
| VITE_API_BASE_URL | 后端 API 地址 | FC 部署后获取 |
| VITE_SENTRY_DSN | Sentry DSN | 空(需手动配置) |
| MIGRATION_TOKEN_PROD | 生产迁移令牌 | 自动生成 |
| MIGRATION_ENDPOINT_PROD | 生产迁移 API 端点 | 生产 FC URL + /api/internal/db-migrate |
注意事项
OSS Bucket 命名
- Bucket 名称全局唯一,如果被占用会导致初始化失败
- 默认使用项目名作为 Bucket 名
- 命名规则:3-63 字符,小写字母、数字、短横线
CORS 配置
默认 infra/oss/cors.xml 允许的域名:
https://app.kaiyan.net
如需自定义域名,请在初始化后修改该文件并重新应用:
aliyun oss cors --method put oss://your-bucket infra/oss/cors.xml -e oss-cn-shenzhen.aliyuncs.comVPC 部署(必填)
RDS 在 VPC 内,FC 必须与 RDS 在同一 VPC 才能互联:
- VPC ID、VSwitch ID、Security Group ID 为必填参数
- 确保 Security Group 允许 FC 访问 RDS 端口(通常 5432)
- VSwitch 需要与 RDS 在同一可用区
数据库迁移
数据库迁移通过 FC 内部 API 端点触发,CI/CD 流水线会在部署后自动调用:
POST /api/internal/db-migrate
Headers:
x-migration-token: {MIGRATION_TOKEN_PROD}
Body:
{"env": "prod", "gitSha": "xxx"}FC 环境特殊处理:由于 custom.debian12 运行时中 node、npx 不在默认 PATH,迁移脚本会直接使用 /var/fc/lang/nodejs22/bin/node 运行 Prisma CLI。
敏感信息安全
- 脚本运行时会在终端显示敏感信息(AK、数据库连接串等)
- 请勿在不安全的环境中运行
.env文件已被.gitignore忽略,不会提交到仓库
后续开发注意事项(初始化后)
kaiyan-init 完成后,后续开发可以完全通过正常的 git push 触发 CI/CD。但存在以下需要注意的脱节点:
1. OSS 配置文件(website.xml/cors.xml)不会自动更新
问题:kaiyan-init 在初始化时会将 infra/oss/website.xml 和 infra/oss/cors.xml 应用到 OSS Bucket。但后续的 GitHub Actions 前端部署只上传静态文件,不会重新应用这些配置。
影响:如果你修改了 cors.xml(如添加新域名)或 website.xml(如修改默认首页),需要手动重新应用。
解决方法:
# 手动应用 website 配置
aliyun oss website --method put oss://your-bucket infra/oss/website.xml -e oss-cn-shenzhen.aliyuncs.com
# 手动应用 CORS 配置
aliyun oss cors --method put oss://your-bucket infra/oss/cors.xml -e oss-cn-shenzhen.aliyuncs.com可选优化:在 GitHub Actions 的前端部署流程中添加自动应用配置的步骤:
- name: 更新 OSS 配置
run: |
aliyun oss website --method put oss://${{ secrets.OSS_BUCKET_PROD }} infra/oss/website.xml
aliyun oss cors --method put oss://${{ secrets.OSS_BUCKET_PROD }} infra/oss/cors.xml2. VPC 配置修改需要手动更新 GitHub Secrets
问题:初始化时指定的 VPC/VSwitch/SecurityGroup ID 被写入 GitHub Secrets。后续 CI/CD 部署会读取这些 Secrets。
影响:如果需要修改 VPC 配置(如切换可用区、更换安全组),需要手动更新 GitHub Secrets。
解决方法:
- 进入 GitHub 仓库 → Settings → Secrets and variables → Actions
- 更新
VPC_ID、VSWITCH_ID、SECURITY_GROUP_ID - 下次
git push时新配置会自动生效
或使用命令行:
gh secret set VPC_ID --body "vpc-new-xxx" --repo your-org/your-repo
gh secret set VSWITCH_ID --body "vsw-new-xxx" --repo your-org/your-repo
gh secret set SECURITY_GROUP_ID --body "sg-new-xxx" --repo your-org/your-repo3. FC 和 OSS 资源支持无限次更新
无需担心:阿里云 FC 和 OSS 都支持幂等部署:
- FC 函数:
s deploy会自动判断是创建还是更新,不存在"只能创建"的问题 - OSS 文件:上传会覆盖已存在的同名文件
- 数据库迁移:Prisma 通过
_prisma_migrations表记录已执行的迁移,重复调用是安全的
4. .prisma 目录检查(v0.7.3+ 强制错误)
从 v0.7.3 版本开始,如果在 FC 部署包创建过程中未找到 .prisma 目录,脚本会立即报错并中止,而非仅输出警告。
如果遇到此错误:
# 确保已安装依赖
pnpm install
# 手动生成 Prisma Client
pnpm --filter backend exec prisma generate
# 检查 .prisma 目录是否存在
ls node_modules/.pnpm/@prisma+client*/node_modules/.prisma故障排除
常见错误
1. Bucket 名 xxx 已被占用
OSS Bucket 名称全局唯一,并且删除后也不可用,请更换一个独特的名称。
2. gh 未登录
gh auth login
# 选择 GitHub.com,使用浏览器登录3. s deploy 失败
可能原因:
- AccessKey 权限不足
- Region 不正确
- 网络问题 调试:
cd your-project
s deploy -y --use-local -t infra/s.yaml --debug4. git push 失败
可能原因:
- SSH 密钥未配置
- 仓库权限不足 检查:
ssh -T [email protected]
gh auth status5. FC 域名获取失败
如果出现 未能获取 FC 域名 警告:
cd your-project
s info -t infra/s.yaml手动获取 system_url 并更新 apps/frontend/.env 和 GitHub Secrets。
6. TypeScript 构建错误(CI/CD)
如果 GitHub Actions 报告 TypeScript 错误,这通常是模板仓库 ky-framework 的问题,而非 kaiyan-init 的问题。常见问题:
tsconfig.node.json缺少noEmit配置tsconfig.json的exclude未包含test目录 请在模板仓库中修复这些问题。
7. DB Migration 失败:spawn npx ENOENT
原因:FC3 custom.debian12 运行时中 npx 不在默认 PATH
解决:此问题已在模板仓库 ky-framework 中修复。如果使用旧版本模板创建的项目遇到此问题,需要更新 apps/backend/src/migration/prisma-migration.runner.ts,直接使用 /var/fc/lang/nodejs22/bin/node 运行 Prisma CLI。
8. alias publish 失败:Version ID not specified
原因:FC3 组件不返回版本号,导致 alias publish 步骤失败 解决:此问题已在模板仓库中修复,workflow 会在没有版本号时自动跳过 alias publish 步骤。FC3 的 HTTP 触发器默认就指向最新部署,跳过此步骤不影响正常访问。
9. ERR_PNPM_DEPLOY_DIR_NOT_EMPTY
原因:连续部署时 fc-deploy 目录已存在
解决:此问题已在模板仓库和 CLI 中修复,每次部署前会自动清空 fc-deploy 目录。
日志前缀说明
| 前缀 | 含义 |
|------|------|
| [kaiyan] | 正常信息 |
| [kaiyan][warn] | 警告(可继续但需注意) |
模板仓库要求
kaiyan-init 依赖模板仓库 ky-framework 的特定结构:
ky-framework/
├── apps/
│ ├── backend/ # NestJS 后端
│ │ ├── prisma/
│ │ ├── src/
│ │ │ └── migration/ # DB Migration 模块
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── frontend/ # React + Vite 前端
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
├── packages/
│ └── shared/ # 共享类型/工具
├── infra/
│ ├── s.yaml # Serverless Devs 配置(生产)
│ ├── s.prod.yaml # 生产环境完整配置
│ └── oss/
│ ├── website.xml # OSS 静态网站配置
│ └── cors.xml # OSS CORS 配置
├── .github/
│ └── workflows/ # CI/CD 流水线
├── docs/
│ └── FC-DEPLOY-PATCHES.md # FC 部署补丁记录
├── package.json # pnpm workspace 根配置
└── pnpm-workspace.yamlFC3 Custom Runtime 配置
模板使用 custom.debian12 运行时,s.yaml 配置示例:
resources:
api-server:
component: fc3
props:
runtime: custom.debian12
customRuntimeConfig:
command:
- /var/fc/lang/nodejs22/bin/node
args:
- dist/main.js
port: 9000
memorySize: 512
timeout: 180
instanceConcurrency: 10重要:command 和 args 需要分开配置,不能都放在 command 数组中。
模板修改注意事项
如果修改模板仓库,请确保:
s.yaml 兼容性:
- 使用
custom.debian12运行时 - 使用完整 Node.js 路径
/var/fc/lang/nodejs22/bin/node - 使用
resources:而非旧版services: - 使用
code:而非旧版codeUri:
- 使用
DB Migration 兼容性:
prisma-migration.runner.ts需要检测 FC 环境并使用完整路径- 设置 PATH 环境变量供 Prisma 内部调用
TypeScript 配置:
tsconfig.node.json需要noEmit: true(如使用allowImportingTsExtensions)tsconfig.json需要正确的exclude配置
pnpm 10 兼容性:
- 需要批准的构建脚本包应在
.npmrc中配置 - 或在
package.json的pnpm.onlyBuiltDependencies中配置
- 需要批准的构建脚本包应在
Prisma binaryTargets:
generator client { provider = "prisma-client-js" // native: 本地开发,debian-openssl-3.0.x: 阿里云 FC custom.debian12 运行时 binaryTargets = ["native", "debian-openssl-3.0.x"] }
开发者迭代指南
项目结构
packages/init/
├── bin/
│ └── kaiyan.js # CLI 主程序(单文件,无需构建)
├── package.json
└── README.md本地测试
# 链接到全局
cd packages/init
pnpm link --global
# 测试运行
kaiyan-init test-project --help发布流程
更新版本号:
npm version patch # 或 minor / major检查打包内容:
npm pack --dry-run # 或实际打包检查 npm pack tar -tf kaiyan-init-*.tgz rm kaiyan-init-*.tgz发布:
npm publish --access public
添加新功能
新增参数:
- 在
printHelp()中添加帮助文档 - 在
main()的answers对象中添加处理逻辑 - 更新 README 的参数表格
- 在
新增步骤:
- 创建对应的 async 函数
- 在
main()的 try 块中按顺序调用 - 添加适当的日志输出
修改模板处理:
- 如需修改模板文件,在对应的处理函数中添加逻辑
- 注意处理文件不存在的情况
调试技巧
查看命令输出:
const res = await runCmd('cmd', ['args'], { capture: true }); console.log('stdout:', res.stdout); console.log('stderr:', res.stderr);跳过某些步骤: 临时注释掉
main()中的函数调用保留中间状态: 脚本失败时,目标目录会保留,可以进入目录手动调试
版本兼容性
- Node.js: 要求 >= 22(使用 ES Modules)
- pnpm: 要求 >= 10(使用
onlyBuiltDependencies) - Serverless Devs: 3.x + FC3 组件
- aliyun CLI: 使用 profile 模式,避免修改默认配置
与模板仓库的关系
@kaiyan/init 是一个脚手架工具,每次运行时从 GitHub 动态克隆 ky-framework 模板:
const templateRepo = 'https://github.com/kaiyan-tech/ky-framework.git';
await runCmd('git', ['clone', '--depth', '1', templateRepo, targetDir]);这意味着:
- 模板的更新不需要发布新版本的
@kaiyan/init - 用户运行
kaiyan-init时会自动获取最新模板 - 只有 CLI 工具本身的逻辑变更才需要发布新版本
