@ranger1/dx 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -14
- package/bin/dx.js +45 -9
- package/lib/cli/dx-cli.js +14 -6
- package/lib/cli/flags.js +6 -0
- package/lib/cli/help.js +7 -3
- package/lib/version.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
# dx
|
|
2
2
|
|
|
3
|
-
一个可安装的 Node.js CLI
|
|
3
|
+
一个可安装的 Node.js CLI,用于管理符合约定的 pnpm + nx monorepo 项目的构建/启动/数据库/部署等流程。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
全局安装(推荐):
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pnpm add -
|
|
10
|
+
pnpm add -g @ranger1/dx
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
安装后即可在任意目录使用:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
pnpm exec dx build sdk --dev
|
|
16
|
+
dx --help
|
|
17
|
+
dx status
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
项目内安装(可选,如果你更希望锁定版本):
|
|
22
21
|
|
|
23
22
|
```bash
|
|
24
|
-
pnpm add -
|
|
25
|
-
dx --help
|
|
23
|
+
pnpm add -D @ranger1/dx
|
|
24
|
+
pnpm exec dx --help
|
|
26
25
|
```
|
|
27
26
|
|
|
28
27
|
## 项目配置(必须)
|
|
@@ -46,6 +45,8 @@ dx/
|
|
|
46
45
|
- 环境变量:`DX_CONFIG_DIR=/abs/path/to/config`
|
|
47
46
|
- 参数:`dx --config-dir /abs/path/to/config ...`
|
|
48
47
|
|
|
48
|
+
全局安装场景下,如果你不在项目目录内执行,也可以通过 `DX_CONFIG_DIR` / `--config-dir` 显式指定配置目录(目录下需要存在 `commands.json`)。
|
|
49
|
+
|
|
49
50
|
## 命令
|
|
50
51
|
|
|
51
52
|
dx 的命令由 `dx/config/commands.json` 驱动,并且内置了一些 internal runner(避免项目侧依赖任何 `scripts/lib/*.js`):
|
|
@@ -75,7 +76,7 @@ dx test e2e backend
|
|
|
75
76
|
|
|
76
77
|
```json
|
|
77
78
|
{
|
|
78
|
-
"command": "
|
|
79
|
+
"command": "dx-with-version-env --app front -- next build"
|
|
79
80
|
}
|
|
80
81
|
```
|
|
81
82
|
|
|
@@ -83,10 +84,11 @@ dx test e2e backend
|
|
|
83
84
|
|
|
84
85
|
## 约束与假设
|
|
85
86
|
|
|
86
|
-
当前版本面向
|
|
87
|
+
当前版本面向 pnpm + nx 的 monorepo,默认假设:
|
|
87
88
|
|
|
88
89
|
- 使用 pnpm + nx
|
|
89
|
-
- 项目布局包含 `apps/backend`、`apps/front`、`apps/admin-front`、`apps/sdk
|
|
90
|
+
- 项目布局包含 `apps/backend`、`apps/front`、`apps/admin-front`、`apps/sdk`(如果你的命令配置不依赖这些目录,可自行调整)
|
|
91
|
+
- 版本注入脚本 `dx-with-version-env` 默认支持 app: `backend` / `front` / `admin`
|
|
90
92
|
|
|
91
93
|
## 发布到 npm(准备工作)
|
|
92
94
|
|
|
@@ -100,4 +102,3 @@ dx test e2e backend
|
|
|
100
102
|
npm publish --access public --registry=https://registry.npmjs.org
|
|
101
103
|
```
|
|
102
104
|
|
|
103
|
-
提示:当前仓库包含一个 `.npmrc`,用于确保 publish 走 npm 官方 registry(避免镜像源导致发布失败)。
|
package/bin/dx.js
CHANGED
|
@@ -43,24 +43,60 @@ function findProjectRootFrom(startDir) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function findRepoRootFrom(startDir) {
|
|
47
|
+
let current = resolve(startDir)
|
|
48
|
+
while (true) {
|
|
49
|
+
// ai-monorepo style marker
|
|
50
|
+
if (existsSync(join(current, 'pnpm-workspace.yaml'))) return current
|
|
51
|
+
// fallback marker
|
|
52
|
+
if (existsSync(join(current, 'package.json'))) return current
|
|
53
|
+
|
|
54
|
+
const parent = dirname(current)
|
|
55
|
+
if (parent === current) return null
|
|
56
|
+
current = parent
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function inferProjectRootFromConfigDir(configDir, startDir) {
|
|
61
|
+
const normalized = String(configDir).replace(/\\/g, '/')
|
|
62
|
+
if (normalized.endsWith('/dx/config')) return resolve(configDir, '..', '..')
|
|
63
|
+
if (normalized.endsWith('/scripts/config')) return resolve(configDir, '..', '..')
|
|
64
|
+
|
|
65
|
+
return findRepoRootFrom(configDir) || findRepoRootFrom(startDir) || resolve(startDir)
|
|
66
|
+
}
|
|
67
|
+
|
|
46
68
|
async function main() {
|
|
47
69
|
const rawArgs = process.argv.slice(2)
|
|
48
70
|
const overrideConfigDir = parseConfigDir(rawArgs)
|
|
49
71
|
const filteredArgs = stripConfigDirArgs(rawArgs)
|
|
50
72
|
|
|
51
73
|
const startDir = process.cwd()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
let projectRoot
|
|
75
|
+
let configDir
|
|
76
|
+
|
|
77
|
+
if (overrideConfigDir) {
|
|
78
|
+
// When dx is installed globally, users may prefer providing DX_CONFIG_DIR/--config-dir.
|
|
79
|
+
// In that case, do not require dx/config marker discovery.
|
|
80
|
+
configDir = resolve(startDir, overrideConfigDir)
|
|
81
|
+
if (!existsSync(join(configDir, 'commands.json'))) {
|
|
82
|
+
console.error(`dx: 配置目录无效: ${configDir}`)
|
|
83
|
+
console.error('dx: 期望存在 commands.json')
|
|
84
|
+
process.exit(1)
|
|
85
|
+
}
|
|
86
|
+
projectRoot = inferProjectRootFromConfigDir(configDir, startDir)
|
|
87
|
+
} else {
|
|
88
|
+
projectRoot = findProjectRootFrom(startDir)
|
|
89
|
+
if (!projectRoot) {
|
|
90
|
+
console.error('dx: 未找到项目配置目录: dx/config/commands.json')
|
|
91
|
+
console.error('dx: 请在项目目录内执行 dx,或先创建 dx/config 并放置 commands.json')
|
|
92
|
+
console.error('dx: 也可通过 DX_CONFIG_DIR 或 --config-dir 指定配置目录')
|
|
93
|
+
process.exit(1)
|
|
94
|
+
}
|
|
95
|
+
configDir = join(projectRoot, 'dx', 'config')
|
|
58
96
|
}
|
|
59
97
|
|
|
60
98
|
process.env.DX_PROJECT_ROOT = projectRoot
|
|
61
|
-
|
|
62
|
-
const defaultConfigDir = join(projectRoot, 'dx', 'config')
|
|
63
|
-
process.env.DX_CONFIG_DIR = overrideConfigDir ? resolve(projectRoot, overrideConfigDir) : defaultConfigDir
|
|
99
|
+
process.env.DX_CONFIG_DIR = configDir
|
|
64
100
|
|
|
65
101
|
process.chdir(projectRoot)
|
|
66
102
|
|
package/lib/cli/dx-cli.js
CHANGED
|
@@ -8,6 +8,7 @@ import { validateEnvironment } from '../validate-env.js'
|
|
|
8
8
|
import { FLAG_DEFINITIONS, parseFlags } from './flags.js'
|
|
9
9
|
import { getCleanArgs } from './args.js'
|
|
10
10
|
import { showHelp, showCommandHelp } from './help.js'
|
|
11
|
+
import { getPackageVersion } from '../version.js'
|
|
11
12
|
import {
|
|
12
13
|
handleHelp,
|
|
13
14
|
handleDev,
|
|
@@ -261,6 +262,11 @@ class DxCli {
|
|
|
261
262
|
// 主执行方法
|
|
262
263
|
async run() {
|
|
263
264
|
try {
|
|
265
|
+
if (this.flags.version) {
|
|
266
|
+
console.log(getPackageVersion())
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
264
270
|
// 显示帮助
|
|
265
271
|
if (this.flags.help || !this.command) {
|
|
266
272
|
if (this.flags.help && this.command && this.command !== 'help') {
|
|
@@ -610,17 +616,19 @@ class DxCli {
|
|
|
610
616
|
// 校验是否在仓库根目录执行
|
|
611
617
|
ensureRepoRoot() {
|
|
612
618
|
const cwd = process.cwd()
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
'package.json',
|
|
616
|
-
'apps',
|
|
617
|
-
'dx/config/commands.json',
|
|
618
|
-
]
|
|
619
|
+
|
|
620
|
+
const markers = ['pnpm-workspace.yaml', 'package.json', 'apps']
|
|
619
621
|
const missing = markers.filter(p => !existsSync(join(cwd, p)))
|
|
620
622
|
if (missing.length) {
|
|
621
623
|
logger.error(`请从仓库根目录运行此命令。缺少标识文件/目录: ${missing.join(', ')}`)
|
|
622
624
|
process.exit(1)
|
|
623
625
|
}
|
|
626
|
+
|
|
627
|
+
const commandsPath = join(this.configDir, 'commands.json')
|
|
628
|
+
if (!existsSync(commandsPath)) {
|
|
629
|
+
logger.error(`未找到命令配置文件: ${commandsPath}`)
|
|
630
|
+
process.exit(1)
|
|
631
|
+
}
|
|
624
632
|
}
|
|
625
633
|
|
|
626
634
|
async getWorktreeManager() {
|
package/lib/cli/flags.js
CHANGED
|
@@ -15,6 +15,8 @@ export const FLAG_DEFINITIONS = {
|
|
|
15
15
|
{ flag: '--verbose' },
|
|
16
16
|
{ flag: '-h' },
|
|
17
17
|
{ flag: '--help' },
|
|
18
|
+
{ flag: '-V' },
|
|
19
|
+
{ flag: '--version' },
|
|
18
20
|
{ flag: '--parallel' },
|
|
19
21
|
{ flag: '-P' },
|
|
20
22
|
],
|
|
@@ -74,6 +76,10 @@ export function parseFlags(args = []) {
|
|
|
74
76
|
case '--help':
|
|
75
77
|
flags.help = true
|
|
76
78
|
break
|
|
79
|
+
case '-V':
|
|
80
|
+
case '--version':
|
|
81
|
+
flags.version = true
|
|
82
|
+
break
|
|
77
83
|
case '--no-env-check':
|
|
78
84
|
flags.noEnvCheck = true
|
|
79
85
|
break
|
package/lib/cli/help.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { getPackageVersion } from '../version.js'
|
|
2
|
+
|
|
1
3
|
export function showHelp() {
|
|
4
|
+
const version = getPackageVersion()
|
|
2
5
|
console.log(`
|
|
3
|
-
DX CLI - 统一开发环境管理工具
|
|
6
|
+
DX CLI v${version} - 统一开发环境管理工具
|
|
4
7
|
|
|
5
8
|
用法:
|
|
6
9
|
dx <命令> [选项] [参数...]
|
|
@@ -67,8 +70,9 @@ DX CLI - 统一开发环境管理工具
|
|
|
67
70
|
--test 使用测试环境
|
|
68
71
|
--e2e 使用E2E测试环境
|
|
69
72
|
-Y, --yes 跳过所有确认提示
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
-v, --verbose 详细输出
|
|
74
|
+
-h, --help 显示此帮助信息
|
|
75
|
+
-V, --version 显示版本号
|
|
72
76
|
|
|
73
77
|
示例:
|
|
74
78
|
dx start stack # PM2 交互式服务栈(推荐)- 同时管理三个服务
|
package/lib/version.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { join, dirname } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
export function getPackageVersion() {
|
|
6
|
+
try {
|
|
7
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const pkgPath = join(here, '..', 'package.json')
|
|
9
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
10
|
+
return typeof pkg.version === 'string' ? pkg.version : '0.0.0'
|
|
11
|
+
} catch {
|
|
12
|
+
return '0.0.0'
|
|
13
|
+
}
|
|
14
|
+
}
|