@thinkbun/plugin 1.0.0

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,305 @@
1
+ # ThinkBun Plugin
2
+
3
+ ThinkBun 框架的官方插件集合,提供常用的功能扩展,包括日志增强和服务器集群支持。
4
+
5
+ ## 子项目概述
6
+
7
+ Plugin 包提供了 ThinkBun 框架的官方插件实现,这些插件可以直接集成到 ThinkBun 应用程序中,为应用提供额外的功能。当前版本包含日志插件和服务器插件,后续将添加更多官方插件。
8
+
9
+ ## 与主项目的关系
10
+
11
+ Plugin 包依赖于 ThinkBun Core 包,为其提供扩展功能。这些插件遵循 Core 包定义的插件接口和生命周期,与框架无缝集成。
12
+
13
+ ## 核心插件
14
+
15
+ ### LoggerPlugin
16
+
17
+ 增强应用程序的日志功能,支持彩色输出、作用域标识和不同日志级别。
18
+
19
+ #### 功能特性
20
+ - 彩色日志输出,提高可读性
21
+ - 支持日志作用域标识
22
+ - 自定义日志级别
23
+ - 与框架日志系统无缝集成
24
+
25
+ #### 安装
26
+
27
+ ```bash
28
+ # 使用 Bun
29
+ bun add @thinkbun/plugin
30
+
31
+ # 使用 npm
32
+ npm install @thinkbun/plugin
33
+
34
+ # 使用 yarn
35
+ yarn add @thinkbun/plugin
36
+ ```
37
+
38
+ #### 使用方法
39
+
40
+ ```typescript
41
+ import { createApplication } from '@thinkbun/core';
42
+ import { LoggerPlugin } from '@thinkbun/plugin';
43
+
44
+ // 创建应用实例
45
+ const app = await createApplication({
46
+ APP_PATH: './src',
47
+ ROOT_PATH: __dirname,
48
+ });
49
+
50
+ // 注册 LoggerPlugin
51
+ app.loader.plugins.push(LoggerPlugin);
52
+
53
+ // 设置应用
54
+ await app.setup();
55
+
56
+ // 使用增强的日志功能
57
+ app.logger.info('应用程序已启动');
58
+ app.logger.error('发生错误', 'ErrorScope');
59
+ app.logger.debug('调试信息', ['Debug', 'Detail']);
60
+ app.logger.warn('警告信息');
61
+ ```
62
+
63
+ #### 日志方法
64
+
65
+ - `app.logger.info(message, scope)`: 输出信息级别的日志
66
+ - `app.logger.error(message, scope)`: 输出错误级别的日志
67
+ - `app.logger.debug(message, scope)`: 输出调试级别的日志
68
+ - `app.logger.warn(message, scope)`: 输出警告级别的日志
69
+
70
+ **参数**:
71
+ - `message`: 日志消息内容
72
+ - `scope`: 可选,日志作用域,可以是字符串或字符串数组
73
+
74
+ ### ServerPlugin
75
+
76
+ 提供服务器启动和集群支持功能,优化应用程序的性能和可靠性。
77
+
78
+ #### 功能特性
79
+ - 基于 Bun.serve 的高性能服务器
80
+ - 自动集群管理,充分利用多核 CPU
81
+ - 工作进程自动重启
82
+ - 优雅的关闭流程
83
+ - 配置化的服务器参数
84
+
85
+ #### 安装
86
+
87
+ ```bash
88
+ # 使用 Bun
89
+ bun add @thinkbun/plugin
90
+
91
+ # 使用 npm
92
+ npm install @thinkbun/plugin
93
+
94
+ # 使用 yarn
95
+ yarn add @thinkbun/plugin
96
+ ```
97
+
98
+ #### 使用方法
99
+
100
+ ```typescript
101
+ import { createApplication } from '@thinkbun/core';
102
+ import { ServerPlugin } from '@thinkbun/plugin';
103
+
104
+ // 创建应用实例
105
+ const app = await createApplication({
106
+ APP_PATH: './src',
107
+ ROOT_PATH: __dirname,
108
+ });
109
+
110
+ // 注册 ServerPlugin
111
+ app.loader.plugins.push(ServerPlugin);
112
+
113
+ // 设置应用
114
+ await app.setup();
115
+
116
+ // 运行应用(ServerPlugin 会自动启动服务器)
117
+ await app.run();
118
+ ```
119
+
120
+ #### 配置选项
121
+
122
+ 在应用配置文件中配置服务器参数:
123
+
124
+ ```typescript
125
+ // src/config/index.ts
126
+ export default {
127
+ port: 3000, // 服务器端口
128
+ host: '0.0.0.0', // 服务器主机
129
+ workers: 4, // 工作进程数量,默认自动检测 CPU 核心数
130
+ // 其他配置...
131
+ };
132
+ ```
133
+
134
+ #### 集群模式
135
+
136
+ ServerPlugin 自动支持集群模式:
137
+ - 主进程管理工作进程的创建和重启
138
+ - 工作进程处理实际的 HTTP 请求
139
+ - 当工作进程意外退出时,自动创建新的工作进程
140
+ - 支持优雅关闭,确保请求处理完成后再退出
141
+
142
+ ## 插件生命周期
143
+
144
+ ### LoggerPlugin 生命周期
145
+
146
+ | 阶段 | 执行顺序 | 功能 |
147
+ |------|----------|------|
148
+ | `setup` | `pre` | 初始化日志功能,替换默认日志器 |
149
+ | `run` | - | 无 |
150
+ | `close` | - | 无 |
151
+
152
+ ### ServerPlugin 生命周期
153
+
154
+ | 阶段 | 执行顺序 | 功能 |
155
+ |------|----------|------|
156
+ | `setup` | - | 无 |
157
+ | `run` | `post` | 启动服务器,根据配置创建工作进程 |
158
+ | `close` | - | 优雅关闭服务器和工作进程 |
159
+
160
+ ## 独立运行/测试
161
+
162
+ ### 运行示例
163
+
164
+ ```bash
165
+ # 安装依赖
166
+ bun install
167
+
168
+ # 运行测试
169
+ bun test
170
+ ```
171
+
172
+ ### 测试
173
+
174
+ ```bash
175
+ # 运行单元测试
176
+ bun test
177
+
178
+ # 运行测试并生成覆盖率报告
179
+ bun test --coverage
180
+ ```
181
+
182
+ ## 自定义插件开发
183
+
184
+ Plugin 包不仅提供官方插件,还展示了如何开发自定义插件。以下是开发自定义插件的示例:
185
+
186
+ ```typescript
187
+ import { type Plugin } from '@thinkbun/core';
188
+
189
+ export const CustomPlugin: Plugin = {
190
+ name: 'CustomPlugin',
191
+ enforce: 'pre', // 插件执行顺序,可以是 'pre'、'post' 或省略
192
+ setup(app) {
193
+ // 插件初始化逻辑
194
+ console.log('CustomPlugin 初始化');
195
+ },
196
+ run(app) {
197
+ // 应用运行时逻辑
198
+ console.log('CustomPlugin 运行中');
199
+ },
200
+ close(app) {
201
+ // 应用关闭时清理逻辑
202
+ console.log('CustomPlugin 已关闭');
203
+ },
204
+ };
205
+ ```
206
+
207
+ ## 插件执行顺序
208
+
209
+ 插件的执行顺序由 `enforce` 属性决定:
210
+ - `pre`: 在核心功能之前执行
211
+ - `post`: 在核心功能之后执行
212
+ - 省略: 默认执行顺序
213
+
214
+ ## 最佳实践
215
+
216
+ 1. **插件注册**:
217
+ - 将插件注册放在 `plugins.ts` 文件中,集中管理
218
+ - 按照依赖关系和执行顺序注册插件
219
+
220
+ 2. **插件配置**:
221
+ - 将插件配置放在应用配置文件中
222
+ - 支持环境特定的配置
223
+
224
+ 3. **错误处理**:
225
+ - 在插件中添加适当的错误处理
226
+ - 提供清晰的错误信息
227
+
228
+ 4. **性能考虑**:
229
+ - 避免在插件中执行耗时操作
230
+ - 合理使用插件生命周期阶段
231
+
232
+ ## API 参考
233
+
234
+ ### LoggerPlugin
235
+
236
+ ```typescript
237
+ interface Plugin {
238
+ name: 'LoggerPlugin';
239
+ enforce: 'pre';
240
+ setup(app: Application): void;
241
+ }
242
+ ```
243
+
244
+ ### ServerPlugin
245
+
246
+ ```typescript
247
+ interface Plugin {
248
+ name: 'ServerPlugin';
249
+ enforce: 'post';
250
+ run(app: Application): void;
251
+ close(app: Application): Promise<void>;
252
+ }
253
+ ```
254
+
255
+ ## 常见问题
256
+
257
+ ### Q: 如何自定义日志颜色?
258
+
259
+ A: 目前 LoggerPlugin 支持的颜色是预定义的,可以通过修改源代码来自定义:
260
+
261
+ ```typescript
262
+ // 在 logger.ts 中修改 colorMap 对象
263
+ const colorMap = {
264
+ app: 'yellow',
265
+ PluginManager: 'yellow',
266
+ // 添加自定义颜色映射
267
+ CustomScope: 'cyan',
268
+ };
269
+ ```
270
+
271
+ ### Q: 如何配置服务器端口?
272
+
273
+ A: 在应用配置文件中设置 `port` 选项:
274
+
275
+ ```typescript
276
+ // src/config/index.ts
277
+ export default {
278
+ port: 8080, // 设置为不同的端口
279
+ };
280
+ ```
281
+
282
+ ### Q: 如何禁用集群模式?
283
+
284
+ A: 在应用配置文件中将 `workers` 设置为 1:
285
+
286
+ ```typescript
287
+ // src/config/index.ts
288
+ export default {
289
+ workers: 1, // 禁用集群模式,只使用一个进程
290
+ };
291
+ ```
292
+
293
+ ## 许可证
294
+
295
+ [MIT License](LICENSE)
296
+
297
+ ## 联系方式
298
+
299
+ - 📧 邮箱:contact@thinkbun.dev
300
+ - 📦 GitHub:[https://github.com/thinkbun/thinkbun](https://github.com/thinkbun/thinkbun)
301
+ - 💬 Discord:[ThinkBun Community](https://discord.gg/thinkbun)
302
+
303
+ ---
304
+
305
+ **ThinkBun Plugin** - 为 ThinkBun 框架提供强大的扩展功能 🧩
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@thinkbun/plugin",
3
+ "version": "1.0.0",
4
+ "module": "src/index.ts",
5
+ "type": "module",
6
+ "devDependencies": {
7
+ "@types/bun": "latest"
8
+ },
9
+ "peerDependencies": {
10
+ "typescript": "^5"
11
+ },
12
+ "dependencies": {
13
+ "picocolors": "^1.1.1",
14
+ "@thinkbun/core": "workspace:*"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ }
19
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './logger.ts';
2
+ export * from './server.ts';
package/src/logger.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { type Plugin } from '@thinkbun/core';
2
+ import pc from 'picocolors';
3
+
4
+ const colorMap = {
5
+ app: 'yellow',
6
+ PluginManager: 'yellow',
7
+ };
8
+ export const LoggerPlugin: Plugin = {
9
+ name: 'LoggerPlugin',
10
+ enforce: 'pre',
11
+ setup(app) {
12
+ const genScope = (scope: string | string[]) => (Array.isArray(scope) ? scope.map((el) => `[${el}]`) : `[${scope}]`);
13
+ app.logger = {
14
+ // @ts-ignore
15
+ info: (msg: string, scope = 'app') => console.log(pc[colorMap[scope] || 'yellow'](genScope(scope)), msg),
16
+ // @ts-ignore
17
+ error: (msg: string, scope = 'app') => console.error(pc[colorMap[scope] || 'yellow'](genScope(scope)), msg),
18
+ // @ts-ignore
19
+ debug: (msg: string, scope = 'app') => console.debug(pc[colorMap[scope] || 'yellow'](genScope(scope)), msg),
20
+ // @ts-ignore
21
+ warn: (msg: string, scope = 'app') => console.warn(pc[colorMap[scope] || 'yellow'](genScope(scope)), msg),
22
+ };
23
+ },
24
+ };
package/src/server.ts ADDED
@@ -0,0 +1,83 @@
1
+ import cluster from 'node:cluster';
2
+ import os from 'node:os';
3
+
4
+ import { type Plugin } from '@thinkbun/core';
5
+
6
+ const isTest = typeof Bun !== 'undefined' && Bun.env.NODE_ENV === 'test';
7
+
8
+ let shuttingDown = false;
9
+ let isPrimary = false;
10
+ export const ServerPlugin: Plugin = {
11
+ name: 'ServerPlugin',
12
+ enforce: 'post',
13
+ run(app) {
14
+ isPrimary = cluster.isPrimary;
15
+ isPrimary = cluster.isPrimary;
16
+ const cpuCount = os.cpus().length;
17
+ const workers = Math.max(1, Math.min(cpuCount, app.loader.config.workers));
18
+
19
+ if (isPrimary && workers > 1) {
20
+ for (let i = 0; i < workers; i++) {
21
+ cluster.fork();
22
+ }
23
+
24
+ cluster.on('exit', () => {
25
+ if (shuttingDown) return;
26
+ cluster.fork();
27
+ });
28
+ } else {
29
+ app.server = Bun.serve({
30
+ port: app.loader.config.port,
31
+ hostname: app.loader.config.host,
32
+ reusePort: true,
33
+ routes: app.routes,
34
+ });
35
+
36
+ process.on('message', async (msg: { type: string }) => {
37
+ if (typeof msg === 'object' && msg !== null && msg.type === 'shutdown') {
38
+ await app.server?.stop?.();
39
+ process.exit(0);
40
+ }
41
+ });
42
+ }
43
+ },
44
+ async close(app) {
45
+ if (isTest) {
46
+ // 只关闭 server,不退出进程
47
+ await app.server?.stop?.();
48
+ return;
49
+ }
50
+ // 只允许 primary 主动关闭 cluster
51
+ if (!isPrimary) {
52
+ await app.server?.stop?.();
53
+ process.exit(0);
54
+ }
55
+
56
+ if (shuttingDown) return;
57
+ shuttingDown = true;
58
+
59
+ // 通知所有 worker
60
+ for (const id in cluster.workers) {
61
+ cluster.workers[id]?.send({ type: 'shutdown' });
62
+ }
63
+
64
+ // 等待 worker 退出 or 强杀
65
+ await new Promise<void>((resolve) => {
66
+ const timer = setTimeout(() => {
67
+ for (const id in cluster.workers) {
68
+ cluster.workers[id]?.kill('SIGKILL');
69
+ }
70
+ resolve();
71
+ }, 5000);
72
+
73
+ cluster.on('exit', () => {
74
+ if (Object.keys(cluster?.workers || {}).length === 0) {
75
+ clearTimeout(timer);
76
+ resolve();
77
+ }
78
+ });
79
+ });
80
+
81
+ process.exit(0);
82
+ },
83
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "include": ["src"],
4
+ }