@winner-fed/deploy-cli
Version:
CLI tool for deploy.
721 lines (603 loc) • 19 kB
Markdown
> 一站式前端项目部署命令行工具
`@winner-fed/deploy-cli` 是一个集成了 SEE 平台部署包生成和 FTP/SFTP 文件上传功能的命令行工具。它简化了前端项目的部署流程,支持多种配置方式和部署场景,完美支持 monorepo 环境,让部署变得更加简单高效。
- 🚀 **一键部署**: 支持 SEE 包生成和 FTP 上传的一体化部署
- 📦 **SEE 平台集成**: 完整支持 SEE 平台的部署包规范
- 🌐 **FTP/SFTP 支持**: 灵活的文件传输协议支持
- 🏗️ **Monorepo 支持**: 智能识别 monorepo 环境,自动向上查找 git 仓库根目录
- ⚙️ **多配置格式**: 支持 JS、TS、JSON 等多种配置文件格式
- 🎯 **TypeScript 支持**: 完整的类型定义和智能提示
- 🔧 **灵活配置**: 支持环境变量、命令行参数等多种配置方式
- 📊 **详细日志**: 提供详细的部署过程日志和错误信息
```bash
npm install -g @winner-fed/deploy-cli
yarn global add @winner-fed/deploy-cli
pnpm add -g @winner-fed/deploy-cli
```
```bash
npm install @winner-fed/deploy-cli --save-dev
yarn add @winner-fed/deploy-cli --dev
pnpm add @winner-fed/deploy-cli -D
```
```bash
deploy-cli see
npx deploy-cli see
yarn deploy-cli see
cd packages/my-app
npx deploy-cli see
```
```bash
deploy-cli ftp
npx deploy-cli ftp
yarn deploy-cli ftp
cd packages/my-app
npx deploy-cli ftp
```
```bash
deploy-cli deploy
```
```bash
deploy-cli [command] [options]
Options:
--config <path> 指定配置文件路径
--help 显示帮助信息
--version 显示版本信息
```
```bash
deploy-cli see [options]
Options:
--config <path> 指定配置文件路径
--output <dir> 指定输出目录
--type <type> 应用类型 (bizframe|subsystem)
--docker 生成 Docker 容器化包
```
```bash
deploy-cli ftp [options]
Options:
--config <path> 指定配置文件路径
--host <host> FTP 服务器地址
--port <port> FTP 服务器端口
--sftp 使用 SFTP 协议
```
`deploy-cli` 支持多种配置文件格式,会按以下优先级查找配置:
1. `deploy.config.ts`
2. `deploy.config.js`
3. `deploy.config.cjs`
4. `deploy.config.mjs`
5. `deploy.config.json`
6. `package.json` 中的 `deploy` 属性
```javascript
// deploy.config.js
module.exports = {
// 项目源码路径
source: process.cwd(),
// SEE 包配置
seeConfig: {
system: 'my-system',
type: 'subsystem',
name: 'my-app',
version: '1.0.0',
description: '我的应用',
outputName: 'dist'
},
// FTP 配置
ftpConfig: {
user: 'deploy-user',
password: 'your-password',
host: 'your-server.com',
port: 22,
localPath: './dist',
remotePath: '/var/www/html',
include: ['*', '**/*'],
exclude: ['**/*.map'],
sftp: true
}
};
```
```typescript
// deploy.config.ts
import type { UserConfig } from '@winner-fed/deploy-cli';
const config: UserConfig = {
source: process.cwd(),
seeConfig: {
system: 'winner-front',
type: 'bizframe',
name: 'main-app',
version: '2.0.0',
description: '主框架应用',
variables: [
{
type: 'input',
label: 'API 基础路径',
name: 'API_BASE_URL',
required: true,
tooltip: '后端 API 服务地址',
default: 'https://api.example.com'
},
{
type: 'switch',
label: '启用调试模式',
name: 'DEBUG_MODE',
options: 'true:是;false:否',
required: false,
tooltip: '是否启用调试模式',
default: 'false'
},
{
type: 'password',
label: '数据库密码',
name: 'DB_PASSWORD',
required: true,
tooltip: '数据库连接密码',
default: ''
},
{
type: 'hidden',
label: '应用版本号',
name: 'APP_VERSION',
required: false,
tooltip: '应用内部版本号,用于系统识别',
default: '1.0.0'
}
],
isProduction: process.env.NODE_ENV === 'production',
dockerImage: 'my-app:latest'
},
ftpConfig: {
user: process.env.FTP_USER!,
password: process.env.FTP_PASSWORD!,
host: process.env.FTP_HOST!,
port: parseInt(process.env.FTP_PORT || '22'),
localPath: './dist',
remotePath: '/usr/local/nginx/html/my-app',
include: ['*', '**/*'],
exclude: ['**/*.map', '**/*.log', '.DS_Store', 'Thumbs.db'],
deleteRemote: true,
sftp: true
}
};
export default config;
```
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| --------- | --------- | ---- | ------------- | ------------------ |
| source | string | 否 | process.cwd() | 项目源码路径 |
| seeConfig | SeeConfig | 否 | - | SEE 包配置 |
| ftpConfig | FtpConfig | 否 | - | FTP 配置 |
| config | string | 否 | - | 自定义配置文件路径 |
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| -------------- | ------------------------- | ---- | ------------------------------ | -------------------------- |
| system | string | 否 | 'winner-front' | 系统类型,SEE 平台分组维度 |
| type | 'bizframe' \| 'subsystem' | 否 | 'bizframe' | 应用类型 |
| name | string | 否 | package.json.name | 发布物名称 |
| version | string | 否 | package.json.version | 发布包版本 |
| description | string | 否 | package.json.description | 发布包描述 |
| appType | string | 否 | name | 发布物类型 |
| group | string | 否 | 'bizframe' | 应用分组 |
| configName | string | 否 | 'config.local' | 配置文件名称(不含.js) |
| outputName | string | 否 | 'dist' | 输出目录名称 |
| templateFunc | function | 否 | - | 自定义变量配置文件生成函数 |
| variables | Array<variables> | 否 | [] | deploy.xml 模板变量 |
| copyFiles | string[] | 否 | [] | 需要直接拷贝的文件列表 |
| seePackageName | string | 否 | `${system}-${name}-${version}` | SEE 包名称 |
| seePackageType | 'web' \| 'docker' | 否 | 'web' | SEE 包类型 |
| isDocker | boolean | 否 | false | 是否为 Docker 包 |
| dockerImage | string | 否 | - | Docker 镜像名 |
| scriptsType | 'python' \| 'bash' | 否 | 'python' | 脚本类型 |
| buildVersion | string | 否 | - | 构建版本 |
| isProduction | boolean | 否 | false | 是否为生产包 |
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| ------------ | -------- | ---- | ------ | ---------------------- |
| user | string | 是 | - | 服务器登录用户名 |
| password | string | 是 | - | 服务器登录密码 |
| host | string | 是 | - | 服务器主机地址 |
| port | number | 是 | - | 服务器端口 |
| localPath | string | 是 | - | 本地文件路径 |
| remotePath | string | 是 | - | 远程服务器路径 |
| include | string[] | 是 | - | 包含的文件模式 |
| exclude | string[] | 否 | [] | 排除的文件模式 |
| deleteRemote | boolean | 否 | false | 上传前是否删除远程文件 |
| forcePasv | boolean | 否 | true | 是否强制被动模式 |
| sftp | boolean | 否 | false | 是否使用 SFTP |
```typescript
interface variables {
type:
| 'input'
| 'select'
| 'editor'
| 'switch'
| 'smallfile'
| 'table'
| 'mselect'
| 'switchForm'
| 'complexSelect'
| 'division'
| 'password'
| 'hidden';
label: string; // 控件标签
name: string; // 变量名称
options?: string; // 选项配置(select 类型使用)
required: boolean; // 是否必填
fold?: boolean; // 是否可折叠
children?: variables[]; // 子控件
tooltip: string; // 提示信息
default: string; // 默认值
}
```
```javascript
// deploy.config.js
module.exports = {
seeConfig: {
system: 'my-system',
type: 'subsystem',
name: 'user-management',
version: '1.0.0',
description: '用户管理系统',
variables: [
{
type: 'input',
label: 'API 地址',
name: 'API_URL',
required: true,
tooltip: '后端 API 服务地址',
default: 'https://api.example.com'
},
{
type: 'password',
label: '数据库密码',
name: 'DB_PASSWORD',
required: true,
tooltip: '数据库连接密码',
default: ''
},
{
type: 'hidden',
label: '应用版本号',
name: 'APP_VERSION',
required: false,
tooltip: '应用内部版本号,用于系统识别',
default: '1.0.0'
}
],
isProduction: true
},
ftpConfig: {
user: 'deploy',
password: process.env.DEPLOY_PASSWORD,
host: 'prod.example.com',
port: 22,
localPath: './dist',
remotePath: '/var/www/html/user-management',
include: ['*', '**/*'],
exclude: ['**/*.map', '**/*.log'],
deleteRemote: true,
sftp: true
}
};
```
```javascript
// deploy.config.js
const env = process.env.NODE_ENV || 'development';
const environments = {
development: {
host: 'dev.example.com',
remotePath: '/var/www/dev'
},
staging: {
host: 'staging.example.com',
remotePath: '/var/www/staging'
},
production: {
host: 'prod.example.com',
remotePath: '/var/www/prod'
}
};
module.exports = {
seeConfig: {
system: 'my-system',
type: 'subsystem',
isProduction: env === 'production'
},
ftpConfig: {
user: 'deploy',
password: process.env.DEPLOY_PASSWORD,
host: environments[env].host,
port: 22,
localPath: './dist',
remotePath: environments[env].remotePath,
include: ['*', '**/*'],
exclude: ['**/*.map'],
deleteRemote: true,
sftp: true
}
};
```
```javascript
// deploy.config.js
module.exports = {
seeConfig: {
system: 'container-system',
type: 'subsystem',
name: 'my-app',
version: '1.0.0',
seePackageType: 'docker',
isDocker: true,
dockerImage: 'my-app:1.0.0',
scriptsType: 'bash'
}
};
```
```javascript
// packages/my-app/deploy.config.js
module.exports = {
// 工具会自动从子包目录向上查找 git 仓库根目录
// 例如:从 /monorepo/packages/my-app 向上查找到 /monorepo/.git
source: __dirname, // 子包目录
seeConfig: {
system: 'monorepo-system',
type: 'subsystem',
name: 'my-app',
version: '1.0.0',
description: 'Monorepo 中的子应用',
outputName: 'dist',
// 工具会自动获取正确的 git hash,即使在子包中运行
isProduction: process.env.NODE_ENV === 'production'
},
ftpConfig: {
user: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
host: 'example.com',
port: 22,
localPath: './dist',
remotePath: '/var/www/html/my-app',
include: ['*', '**/*'],
exclude: ['**/*.map'],
sftp: true
}
};
```
```json
{
"name": "my-app",
"version": "1.0.0",
"scripts": {
"build": "npm run build:prod",
"deploy:see": "deploy-cli see",
"deploy:ftp": "deploy-cli ftp",
"deploy": "npm run build && deploy-cli see && deploy-cli ftp"
},
"deploy": {
"seeConfig": {
"system": "my-system",
"type": "subsystem",
"outputName": "dist"
},
"ftpConfig": {
"user": "deploy",
"host": "example.com",
"port": 22,
"localPath": "./dist",
"remotePath": "/var/www/html",
"include": ["*", "**/*"],
"exclude": ["**/*.map"],
"sftp": true
}
}
}
```
为了安全起见,建议将敏感信息通过环境变量配置:
```bash
FTP_USER=deploy-user
FTP_PASSWORD=your-secure-password
FTP_HOST=your-server.com
FTP_PORT=22
NODE_ENV=production
```
```javascript
// deploy.config.js
require('dotenv').config();
module.exports = {
ftpConfig: {
user: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
host: process.env.FTP_HOST
// ... 其他配置
}
};
```
```bash
deploy-cli see --config ./build/deploy.config.js
deploy-cli ftp --config ./config/production.js
deploy-cli see --config ../shared/deploy.config.js
```
1. **配置文件未找到**
```bash
Error: Configuration file not found
```
解决方案:确保配置文件存在且路径正确
2. **SEE 包生成失败**
```bash
Error: Failed to generate SEE package
```
解决方案:检查 `outputName` 目录是否存在,确保有足够的磁盘空间
3. **FTP 连接失败**
```bash
Error: FTP connection failed
```
解决方案:检查网络连接、服务器地址、端口和凭据
```bash
DEBUG=deploy-cli* deploy-cli see
DEBUG=deploy-cli* deploy-cli ftp
```
```javascript
// 使用配置工厂函数
function createConfig(env) {
const baseConfig = {
seeConfig: {
system: 'my-system',
type: 'subsystem'
}
};
const envConfigs = {
development: {
ftpConfig: {
host: 'dev.example.com',
deleteRemote: false
}
},
production: {
ftpConfig: {
host: 'prod.example.com',
deleteRemote: true
}
}
};
return {
...baseConfig,
...envConfigs[env]
};
}
module.exports = createConfig(process.env.NODE_ENV || 'development');
```
```javascript
// 使用环境变量和配置验证
const requiredEnvVars = ['FTP_USER', 'FTP_PASSWORD', 'FTP_HOST'];
const missingVars = requiredEnvVars.filter((varName) => !process.env[varName]);
if (missingVars.length > 0) {
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
}
module.exports = {
ftpConfig: {
user: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
host: process.env.FTP_HOST
// ... 其他配置
}
};
```
```json
{
"scripts": {
"build": "npm run build:prod",
"deploy:dev": "NODE_ENV=development deploy-cli deploy",
"deploy:staging": "NODE_ENV=staging deploy-cli deploy",
"deploy:prod": "NODE_ENV=production deploy-cli deploy",
"deploy": "npm run build && npm run deploy:prod"
}
}
```
```json
// packages/my-app/package.json
{
"name": "@my-org/my-app",
"version": "1.0.0",
"scripts": {
"build": "vite build",
"deploy:dev": "NODE_ENV=development deploy-cli deploy",
"deploy:prod": "NODE_ENV=production deploy-cli deploy"
}
}
```
```javascript
// packages/my-app/deploy.config.js
module.exports = {
// 当前子包目录
source: __dirname,
seeConfig: {
system: 'my-system',
type: 'subsystem',
name: 'my-app',
version: require('./package.json').version,
description: require('./package.json').description,
outputName: 'dist',
// 工具会自动向上查找 git 仓库,获取正确的 git hash
isProduction: process.env.NODE_ENV === 'production'
},
ftpConfig: {
// 使用环境变量配置敏感信息
user: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
host: process.env.FTP_HOST,
port: parseInt(process.env.FTP_PORT || '22'),
localPath: './dist',
remotePath: `/var/www/html/${require('./package.json').name}`,
include: ['*', '**/*'],
exclude: ['**/*.map', '**/*.log'],
sftp: true
}
};
```
1. **配置文件优先级**: 命令行 `--config` 参数 > 项目根目录配置文件 > package.json
2. **环境变量**: 建议使用环境变量管理敏感信息
3. **路径处理**: 所有路径都相对于 `source` 配置的目录
4. **Monorepo 支持**: 工具会自动向上查找 `.git` 目录,支持在子包中运行并正确获取 git 信息
5. **Docker 部署**: 使用 Docker 模式时,确保镜像已构建并推送到仓库
6. **网络连接**: FTP/SFTP 部署需要确保网络连接和防火墙配置正确
- **Monorepo 支持增强**: 新增智能 git 目录查找功能,支持在 monorepo 子包中正确获取 git 信息
- **类型安全改进**: 修复了 TypeScript 类型错误,提供更好的类型支持
- **API 改进**: 将部分内部工具函数暴露为公共 API,方便扩展使用
详细的更新日志请查看 [CHANGELOG.md](./CHANGELOG.md)。
ISC License
欢迎提交 Issue 和 Pull Request 来改进这个项目。
- [@winner-fed/winner-deploy](../see-deploy/README.md) - SEE 平台部署包生成工具
- [@winner-fed/ftp-deploy](../ftp-deploy/README.md) - FTP/SFTP 文件上传工具