@hile/cli 1.0.1

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 ADDED
@@ -0,0 +1,128 @@
1
+ # @hile/cli
2
+
3
+ Hile 命令行工具,用于启动基于 `@hile/core` 的服务应用。支持通过 `package.json` 配置和/或自动扫描 `*.boot.{ts,js}` 文件加载服务,并注册退出钩子实现优雅关闭。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm add @hile/cli
9
+ ```
10
+
11
+ 全局安装后可直接使用 `hile` 命令:
12
+
13
+ ```bash
14
+ pnpm add -g @hile/cli
15
+ ```
16
+
17
+ ## 命令
18
+
19
+ ### `hile start`
20
+
21
+ 在**当前工作目录**(通常为项目根,且含 `package.json`)下启动服务。按以下顺序加载服务并启动:
22
+
23
+ 1. **package.json 中的 `hile.auto_load_packages`**(若存在):按数组顺序加载所列**模块名**的默认导出作为服务。
24
+ 2. **运行时目录下的 `*.boot.ts` / `*.boot.js`**:扫描并加载每个文件的默认导出作为服务。
25
+
26
+ 若上述两者均未提供任何可加载项,CLI 会输出 `no services to load` 并退出。每个加载项(模块或 boot 文件)的默认导出须通过 `isService` 校验,否则会抛出 `invalid service file`。
27
+
28
+ ```bash
29
+ hile start # 生产模式,扫描 dist/ 目录
30
+ hile start --dev # 开发模式,扫描 src/ 目录(通过 tsx 支持 TypeScript)
31
+ ```
32
+
33
+ | 选项 | 说明 | 默认值 |
34
+ |------|------|--------|
35
+ | `-d, --dev` | 开发模式,使用 tsx 运行 TypeScript | `false` |
36
+
37
+ ### 其他
38
+
39
+ ```bash
40
+ hile -v # 查看版本号
41
+ hile -h # 查看帮助
42
+ ```
43
+
44
+ ## 运行时目录
45
+
46
+ CLI 按以下优先级确定扫描目录:
47
+
48
+ 1. 环境变量 `HILE_RUNTIME_DIR`(如果设置)
49
+ 2. 开发模式(`--dev`)→ `src/`
50
+ 3. 生产模式 → `dist/`
51
+
52
+ 可通过环境变量自定义:
53
+
54
+ ```bash
55
+ HILE_RUNTIME_DIR=./custom hile start
56
+ ```
57
+
58
+ ## package.json 配置(可选)
59
+
60
+ 在项目根目录的 `package.json` 中可增加 `hile.auto_load_packages`,用于在扫描 boot 文件**之前**先加载指定模块的默认导出作为服务:
61
+
62
+ ```json
63
+ {
64
+ "name": "my-app",
65
+ "hile": {
66
+ "auto_load_packages": ["@hile/http", "my-local-service"]
67
+ }
68
+ }
69
+ ```
70
+
71
+ - **含义**:数组中的每一项为**模块名**(与 `import('模块名')` 一致),不能写文件路径。
72
+ - **顺序**:按数组顺序依次加载,再加载运行时目录下的 `*.boot.{ts,js}`。
73
+ - **要求**:每个模块的默认导出必须是 `defineService` / `container.register` 的返回值(通过 `isService` 校验)。若无 `hile` 或 `auto_load_packages`,则仅通过 boot 文件加载服务。
74
+ - **注意**:`hile` 配置为可选项。若当前工作目录存在 `package.json`,会读取其中可选的 `hile.auto_load_packages` 并优先加载;未配置该项时,仅通过 boot 文件加载服务。
75
+
76
+ ## Boot 文件规范
77
+
78
+ 每个 `*.boot.ts` 文件必须默认导出一个通过 `defineService` 定义的服务:
79
+
80
+ ```typescript
81
+ // src/database.boot.ts
82
+ import { defineService, loadService } from '@hile/core'
83
+ import { configService } from './services/config'
84
+
85
+ export default defineService(async (shutdown) => {
86
+ const config = await loadService(configService)
87
+ const pool = await createPool(config.dbUrl)
88
+ shutdown(() => pool.end())
89
+ return pool
90
+ })
91
+ ```
92
+
93
+ **要求:**
94
+ - 文件名必须以 `.boot.ts` 或 `.boot.js` 结尾
95
+ - 必须有 `default` 导出
96
+ - 导出值必须是 `defineService` / `container.register` 的返回值(通过 `isService` 校验)
97
+
98
+ ## 优雅关闭
99
+
100
+ 进程收到退出信号时(SIGTERM、SIGINT 等),CLI 自动调用 `container.shutdown()` 按逆序销毁所有已启动的服务,确保资源正确释放。
101
+
102
+ ## 项目结构示例
103
+
104
+ ```
105
+ my-app/
106
+ ├── src/
107
+ │ ├── database.boot.ts # 数据库服务(自启动)
108
+ │ ├── http.boot.ts # HTTP 服务(自启动)
109
+ │ └── services/
110
+ │ ├── config.ts # 配置服务(被依赖,不自启动)
111
+ │ └── cache.ts # 缓存服务(被依赖,不自启动)
112
+ ├── package.json # 可含 hile.auto_load_packages
113
+ └── tsconfig.json
114
+ ```
115
+
116
+ 服务加载来源:先按 `package.json` 的 `hile.auto_load_packages`(若有)加载模块默认导出,再扫描运行时目录下的 `*.boot.{ts,js}`;其余服务通过 `loadService` 按需加载。
117
+
118
+ ## 开发
119
+
120
+ ```bash
121
+ pnpm install
122
+ pnpm build # 编译
123
+ pnpm dev # 监听模式
124
+ ```
125
+
126
+ ## License
127
+
128
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import pkg from '../package.json' with { type: 'json' };
3
+ import exitHook from 'async-exit-hook';
4
+ import { program } from 'commander';
5
+ import { glob } from 'glob';
6
+ import { resolve } from 'node:path';
7
+ import { container, isService, loadService } from '@hile/core';
8
+ program.version(pkg.version, '-v, --version', '当前版本号');
9
+ /**
10
+ * 启动服务
11
+ * 1. 加载所有后缀为 boot.ts 或 boot.js 的服务
12
+ * 2. 注册退出钩子,在进程退出时销毁所有服务
13
+ * 3. 如果 HILE_RUNTIME_DIR 环境变量存在,则使用该目录作为运行时目录,否则使用 src 或 dist 目录
14
+ * @param options - 选项
15
+ * @param options.dev - 开发模式
16
+ * @returns - 启动服务
17
+ */
18
+ program
19
+ .command('start')
20
+ .option('-d, --dev', '开发模式', false)
21
+ .description('启动服务,加载所有后缀为 boot.ts 或 boot.js 的服务,并注册退出钩子,在进程退出时销毁所有服务')
22
+ .action(async (options) => {
23
+ // 开发模式下,使用 tsx 运行
24
+ if (options.dev)
25
+ await import('tsx/esm');
26
+ // 加载所有后缀为 boot.ts 或 boot.js 的服务
27
+ const directory = resolve(process.cwd(), process.env.HILE_RUNTIME_DIR || (options.dev ? 'src' : 'dist'));
28
+ const files = await glob(`**/*.boot.{ts,js}`, { cwd: directory });
29
+ // 加载所有自启动服务
30
+ await Promise.all(files.map(async (file) => {
31
+ const filepath = resolve(directory, file);
32
+ const target = await import(filepath);
33
+ const fn = target.default;
34
+ if (!fn || !isService(fn))
35
+ throw new Error(`missing default export in ${file}`);
36
+ if (!fn.id)
37
+ throw new Error(`invalid service file: ${file}`);
38
+ await loadService(fn);
39
+ }));
40
+ // 注册退出钩子,在进程退出时销毁所有服务
41
+ exitHook(exit => {
42
+ container.shutdown()
43
+ .catch(e => console.error(e))
44
+ .finally(exit);
45
+ });
46
+ });
47
+ program.parseAsync(process.argv);
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@hile/cli",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc -b",
9
+ "dev": "tsc -b --watch"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "bin": {
16
+ "hile": "./dist/index.js"
17
+ },
18
+ "license": "MIT",
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "devDependencies": {
23
+ "@types/async-exit-hook": "^2.0.2",
24
+ "tsx": "^4.21.0",
25
+ "vitest": "^4.0.18"
26
+ },
27
+ "dependencies": {
28
+ "@hile/core": "1.0.9",
29
+ "async-exit-hook": "^2.0.1",
30
+ "commander": "^14.0.3",
31
+ "glob": "^13.0.6"
32
+ },
33
+ "gitHead": "315d22b9f3c2a21f40938bbefe422d100fca2cee"
34
+ }