@linyjs/plugin-docs 0.1.3 → 0.1.4
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 +3 -8
- package/docs/api-reference/index.md +1 -1
- package/docs/best-practices/error-handling.md +1 -1
- package/docs/best-practices/naming-conventions.md +2 -1
- package/docs/best-practices/performance.md +4 -4
- package/docs/best-practices/service-definition.md +332 -0
- package/docs/faq.md +0 -1
- package/docs/getting-started/first-plugin.md +15 -15
- package/docs/getting-started/installation.md +1 -1
- package/docs/getting-started/quick-start.md +28 -22
- package/docs/guides/authentication.md +32 -24
- package/docs/guides/client-module.md +6 -0
- package/docs/guides/data-persistence.md +104 -43
- package/docs/guides/server-module.md +6 -0
- package/docs/migration/v0-to-v1.md +2 -2
- package/examples/analytics-plugin/src/client/index.tsx +43 -39
- package/examples/analytics-plugin/src/server/index.ts +20 -19
- package/examples/blog-plugin/README.md +4 -4
- package/examples/blog-plugin/package.json +1 -1
- package/examples/blog-plugin/src/client/index.tsx +44 -40
- package/examples/blog-plugin/src/server/index.ts +8 -8
- package/examples/hello-world/src/client/index.tsx +8 -8
- package/examples/hello-world/src/server/index.ts +8 -8
- package/package.json +10 -6
- package/src/cli.ts +12 -12
package/README.md
CHANGED
|
@@ -82,6 +82,7 @@ docs/
|
|
|
82
82
|
│ └── ui-slots-interface.md
|
|
83
83
|
├── best-practices/ # 最佳实践
|
|
84
84
|
│ ├── naming-conventions.md
|
|
85
|
+
│ ├── service-definition.md # ServiceDef 代码风格规范
|
|
85
86
|
│ ├── error-handling.md
|
|
86
87
|
│ ├── performance.md
|
|
87
88
|
│ └── security.md
|
|
@@ -107,7 +108,7 @@ examples/
|
|
|
107
108
|
|
|
108
109
|
linyjs 提供了以下核心模块,插件可以通过依赖注入方式调用这些基础服务:
|
|
109
110
|
|
|
110
|
-
### @linyjs/
|
|
111
|
+
### @linyjs/mdb
|
|
111
112
|
**MongoDB 数据库服务**
|
|
112
113
|
- 提供数据持久化存储
|
|
113
114
|
- 支持 CRUD 操作和复杂查询
|
|
@@ -125,15 +126,9 @@ linyjs 提供了以下核心模块,插件可以通过依赖注入方式调用
|
|
|
125
126
|
- 细粒度的权限定义
|
|
126
127
|
- 详情:[权限管理指南](./docs/guides/permissions.md)
|
|
127
128
|
|
|
128
|
-
## 🔗 相关链接
|
|
129
|
-
|
|
130
|
-
- [linyjs 框架](https://github.com/linyjs/linyjs)
|
|
131
|
-
- [CLI 工具文档](https://github.com/linyjs/linyjs/tree/main/packages/cli)
|
|
132
|
-
- [报告文档问题](https://github.com/linyjs/linyjs/issues)
|
|
133
|
-
|
|
134
129
|
## 📖 核心模块指南
|
|
135
130
|
|
|
136
|
-
- 💾 [数据持久化](./docs/guides/data-persistence.md) - 使用 @linyjs/
|
|
131
|
+
- 💾 [数据持久化](./docs/guides/data-persistence.md) - 使用 @linyjs/mdb
|
|
137
132
|
- 🔐 [用户认证](./docs/guides/authentication.md) - 使用 @linyjs/auth
|
|
138
133
|
- 🛡️ [权限管理](./docs/guides/permissions.md) - 使用 @linyjs/permission
|
|
139
134
|
|
|
@@ -487,9 +487,10 @@ git commit -m "Update the documentation for the slot feature" # 太长
|
|
|
487
487
|
## 相关文档
|
|
488
488
|
|
|
489
489
|
- ⚠️ [错误处理](./error-handling.md)
|
|
490
|
+
- 📐 [ServiceDef 代码风格规范](./service-definition.md)
|
|
490
491
|
- ⚡ [性能优化](./performance.md)
|
|
491
492
|
- 🔒 [安全性](./security.md)
|
|
492
493
|
|
|
493
494
|
---
|
|
494
495
|
|
|
495
|
-
**上一篇**: [数据持久化](../guides/data-persistence.md) | **下一篇**: [
|
|
496
|
+
**上一篇**: [数据持久化](../guides/data-persistence.md) | **下一篇**: [ServiceDef 代码风格规范](./service-definition.md)
|
|
@@ -150,10 +150,10 @@ function ResponsiveImage() {
|
|
|
150
150
|
```typescript
|
|
151
151
|
// ✅ 推荐:使用索引和投影
|
|
152
152
|
class OptimizedArticleService {
|
|
153
|
-
constructor(private
|
|
153
|
+
constructor(private mongodbService: IMongoDBService) {}
|
|
154
154
|
|
|
155
155
|
async getArticles() {
|
|
156
|
-
const db = this.
|
|
156
|
+
const db = this.mongodbService.getDb();
|
|
157
157
|
const collection = db.collection('articles');
|
|
158
158
|
|
|
159
159
|
// 使用索引字段查询
|
|
@@ -175,7 +175,7 @@ class OptimizedArticleService {
|
|
|
175
175
|
|
|
176
176
|
// 添加索引
|
|
177
177
|
async createIndexes() {
|
|
178
|
-
const db = this.
|
|
178
|
+
const db = this.mongodbService.getDb();
|
|
179
179
|
const collection = db.collection('articles');
|
|
180
180
|
|
|
181
181
|
await collection.createIndex({ status: 1, createdAt: -1 });
|
|
@@ -259,7 +259,7 @@ class AsyncProcessingService {
|
|
|
259
259
|
|
|
260
260
|
private async getBatchData(offset: number, limit: number) {
|
|
261
261
|
// 获取数据批次
|
|
262
|
-
const db = this.
|
|
262
|
+
const db = this.mongodbService.getDb();
|
|
263
263
|
return db.collection('items')
|
|
264
264
|
.find()
|
|
265
265
|
.skip(offset)
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# ServiceDef 代码风格规范
|
|
2
|
+
|
|
3
|
+
本指南介绍 linyjs 插件开发中 `ServiceDef` 的两条核心代码风格规范,确保代码组织一致、可读、易维护。
|
|
4
|
+
|
|
5
|
+
## 为什么需要规范?
|
|
6
|
+
|
|
7
|
+
- 📖 **提高可读性** — 服务定义与实现放在一起,一目了然
|
|
8
|
+
- 🔍 **便于查找** — 看到类就能找到它的 ServiceDef,反之亦然
|
|
9
|
+
- 🛠️ **减少错误** — 独立声明减少缩进层级,避免括号匹配错误
|
|
10
|
+
- 🤝 **团队协作** — 统一风格,降低 review 沟通成本
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 规则一:ServiceDef 必须声明为独立变量
|
|
15
|
+
|
|
16
|
+
### 规则说明
|
|
17
|
+
|
|
18
|
+
`ServiceDef` 必须先声明为独立变量,然后在 `serviceDefs` 数组中通过变量名引用。**禁止**将 `ServiceDef` 对象字面量直接内联在 `serviceDefs` 数组中。
|
|
19
|
+
|
|
20
|
+
### ✅ 正确写法
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import type { IModule, IServiceDef } from '@linyjs/server-module-interface';
|
|
24
|
+
|
|
25
|
+
class HelloController {
|
|
26
|
+
getRoutes() {
|
|
27
|
+
return [/* ... */];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const helloControllerDef: IServiceDef = {
|
|
32
|
+
serviceTag: 'helloController',
|
|
33
|
+
serviceImpl: HelloController,
|
|
34
|
+
meta: { usageType: 'controller' }
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const helloServerModule: IModule = {
|
|
38
|
+
name: 'helloServer',
|
|
39
|
+
serviceDefs: [helloControllerDef]
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### ❌ 错误写法
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import type { IModule } from '@linyjs/server-module-interface';
|
|
47
|
+
|
|
48
|
+
class HelloController {
|
|
49
|
+
getRoutes() {
|
|
50
|
+
return [/* ... */];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const helloServerModule: IModule = {
|
|
55
|
+
name: 'helloServer',
|
|
56
|
+
serviceDefs: [
|
|
57
|
+
{
|
|
58
|
+
serviceTag: 'helloController',
|
|
59
|
+
serviceImpl: HelloController,
|
|
60
|
+
meta: { usageType: 'controller' }
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 原因
|
|
67
|
+
|
|
68
|
+
| 对比项 | 独立变量声明 | 内联在数组中 |
|
|
69
|
+
|--------|------------|------------|
|
|
70
|
+
| 缩进层级 | 浅(2层) | 深(4层+) |
|
|
71
|
+
| 可读性 | 高,变量名即语义 | 低,大段对象字面量淹没模块声明 |
|
|
72
|
+
| 复用性 | 可被多个模块引用 | 无法复用 |
|
|
73
|
+
| 维护性 | 修改时不影响模块声明 | 修改时需在数组中定位 |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 规则二:ServiceDef 声明必须与实现类放在同一个文件中
|
|
78
|
+
|
|
79
|
+
### 规则说明
|
|
80
|
+
|
|
81
|
+
`ServiceDef` 声明必须紧挨着它的 `serviceImpl` 实现类,放在同一个文件中。**禁止**将 `ServiceDef` 和实现类分离到不同文件,然后在模块入口文件中重新声明。
|
|
82
|
+
|
|
83
|
+
### ✅ 正确写法
|
|
84
|
+
|
|
85
|
+
**`src/server/services/article-controller.ts`**
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import type { IControllerService, IControllerServiceDef } from '@linyjs/server-module-interface';
|
|
89
|
+
|
|
90
|
+
export class ArticleController implements IControllerService {
|
|
91
|
+
getRoutes() {
|
|
92
|
+
return [/* ... */];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const articleControllerDef: IControllerServiceDef = {
|
|
97
|
+
serviceTag: 'articleController',
|
|
98
|
+
serviceImpl: ArticleController,
|
|
99
|
+
dependencies: ['mdb.mongoDBService'],
|
|
100
|
+
meta: { usageType: 'controller' }
|
|
101
|
+
};
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**`src/server/server-module.ts`**
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import type { IModule } from '@linyjs/server-module-interface';
|
|
108
|
+
import { articleControllerDef } from './services/article-controller.js';
|
|
109
|
+
|
|
110
|
+
export const articleServerModule: IModule = {
|
|
111
|
+
name: 'articleServer',
|
|
112
|
+
moduleDependencies: ['mdb'],
|
|
113
|
+
serviceDefs: [articleControllerDef]
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### ❌ 错误写法
|
|
118
|
+
|
|
119
|
+
**`src/server/services/article-controller.ts`** — 只有类,没有 ServiceDef
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
export class ArticleController implements IControllerService {
|
|
123
|
+
getRoutes() {
|
|
124
|
+
return [/* ... */];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**`src/server/server-module.ts`** — ServiceDef 与类分离
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { ArticleController } from './services/article-controller.js';
|
|
133
|
+
|
|
134
|
+
const articleControllerDef: IControllerServiceDef = {
|
|
135
|
+
serviceTag: 'articleController',
|
|
136
|
+
serviceImpl: ArticleController,
|
|
137
|
+
dependencies: ['mdb.mongoDBService'],
|
|
138
|
+
meta: { usageType: 'controller' }
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const articleServerModule: IModule = {
|
|
142
|
+
name: 'articleServer',
|
|
143
|
+
moduleDependencies: ['mdb'],
|
|
144
|
+
serviceDefs: [articleControllerDef]
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 原因
|
|
149
|
+
|
|
150
|
+
| 对比项 | 同文件放置 | 分离到不同文件 |
|
|
151
|
+
|--------|----------|-------------|
|
|
152
|
+
| 内聚性 | 高,定义与实现在一起 | 低,需跨文件查找 |
|
|
153
|
+
| 修改成本 | 低,改一处即可 | 高,可能漏改 |
|
|
154
|
+
| 文件职责 | 清晰,每个文件自包含 | 模糊,入口文件混杂声明 |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 完整示例
|
|
159
|
+
|
|
160
|
+
以下是一个完整的服务端模块示例,遵循两条规范:
|
|
161
|
+
|
|
162
|
+
### 项目结构
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
src/server/
|
|
166
|
+
├── controllers/
|
|
167
|
+
│ └── article-controller.ts # ArticleController 类 + articleControllerDef
|
|
168
|
+
├── middleware/
|
|
169
|
+
│ └── auth-middleware.ts # AuthMiddleware 类 + authMiddlewareDef
|
|
170
|
+
├── services/
|
|
171
|
+
│ └── article-service.ts # ArticleService 类 + articleServiceDef
|
|
172
|
+
└── server-module.ts # 模块入口,只做导入和组装
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 控制器文件
|
|
176
|
+
|
|
177
|
+
**`src/server/controllers/article-controller.ts`**
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import type { IControllerService, IControllerServiceDef } from '@linyjs/server-module-interface';
|
|
181
|
+
|
|
182
|
+
export class ArticleController implements IControllerService {
|
|
183
|
+
getRoutes() {
|
|
184
|
+
return [
|
|
185
|
+
{
|
|
186
|
+
method: 'GET' as const,
|
|
187
|
+
path: '/api/articles',
|
|
188
|
+
middlewares: [],
|
|
189
|
+
responseType: 'json' as const,
|
|
190
|
+
handler: async () => {
|
|
191
|
+
return { articles: [] };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export const articleControllerDef: IControllerServiceDef = {
|
|
199
|
+
serviceTag: 'articleController',
|
|
200
|
+
serviceImpl: ArticleController,
|
|
201
|
+
dependencies: ['articleService'],
|
|
202
|
+
meta: { usageType: 'controller' }
|
|
203
|
+
};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 中间件文件
|
|
207
|
+
|
|
208
|
+
**`src/server/middleware/auth-middleware.ts`**
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import type { IMiddlewareService, IMiddlewareServiceDef } from '@linyjs/server-module-interface';
|
|
212
|
+
|
|
213
|
+
export class AuthMiddleware implements IMiddlewareService {
|
|
214
|
+
getMiddlewares() {
|
|
215
|
+
return [{
|
|
216
|
+
middlewareId: 'auth',
|
|
217
|
+
handler: async (params, ctx, next) => {
|
|
218
|
+
// 认证逻辑...
|
|
219
|
+
await next();
|
|
220
|
+
}
|
|
221
|
+
}];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const authMiddlewareDef: IMiddlewareServiceDef = {
|
|
226
|
+
serviceTag: 'authMiddleware',
|
|
227
|
+
serviceImpl: AuthMiddleware,
|
|
228
|
+
meta: { usageType: 'middleware' }
|
|
229
|
+
};
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 模块入口文件
|
|
233
|
+
|
|
234
|
+
**`src/server/server-module.ts`**
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import type { IModule } from '@linyjs/server-module-interface';
|
|
238
|
+
import { articleControllerDef } from './controllers/article-controller.js';
|
|
239
|
+
import { authMiddlewareDef } from './middleware/auth-middleware.js';
|
|
240
|
+
|
|
241
|
+
export const myServerModule: IModule = {
|
|
242
|
+
name: 'myServer',
|
|
243
|
+
serviceDefs: [articleControllerDef, authMiddlewareDef]
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
> 模块入口文件只负责**导入和组装**,不包含任何 ServiceDef 声明或服务实现类。
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 客户端模块同样适用
|
|
252
|
+
|
|
253
|
+
以上两条规范同样适用于客户端模块:
|
|
254
|
+
|
|
255
|
+
### ✅ 正确写法
|
|
256
|
+
|
|
257
|
+
**`src/client/index.tsx`**
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import type { IModule, IRouteDef } from '@linyjs/client-module-interface';
|
|
261
|
+
import React from 'react';
|
|
262
|
+
|
|
263
|
+
function HelloPage() {
|
|
264
|
+
return <div>Hello!</div>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
class HelloRouteService implements IRouteService {
|
|
268
|
+
basePath = '/hello';
|
|
269
|
+
|
|
270
|
+
getRoutes() {
|
|
271
|
+
return [{
|
|
272
|
+
path: '/',
|
|
273
|
+
component: HelloPage,
|
|
274
|
+
key: 'hello-page',
|
|
275
|
+
meta: { title: 'Hello' }
|
|
276
|
+
}];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const helloRouteDef: IRouteDef = {
|
|
281
|
+
serviceTag: 'helloRoute',
|
|
282
|
+
serviceImpl: HelloRouteService,
|
|
283
|
+
meta: { usageType: 'route' }
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
export const helloClientModule: IModule = {
|
|
287
|
+
name: 'helloClient',
|
|
288
|
+
serviceDefs: [helloRouteDef]
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### ❌ 错误写法
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// ServiceDef 内联在数组中,且使用了匿名类
|
|
296
|
+
export const helloClientModule: IModule = {
|
|
297
|
+
name: 'helloClient',
|
|
298
|
+
serviceDefs: [{
|
|
299
|
+
serviceTag: 'helloRoute',
|
|
300
|
+
serviceImpl: class {
|
|
301
|
+
basePath = '/hello';
|
|
302
|
+
getRoutes() { /* ... */ }
|
|
303
|
+
},
|
|
304
|
+
meta: { usageType: 'route' }
|
|
305
|
+
}]
|
|
306
|
+
};
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
> 客户端模块中如果文件较小(如 Hello World 级别),可以将类、ServiceDef 和模块声明放在同一个文件中。但仍然禁止内联在 `serviceDefs` 数组中,也禁止使用匿名类作为 `serviceImpl`。
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 检查清单
|
|
314
|
+
|
|
315
|
+
在提交代码前,请检查以下几点:
|
|
316
|
+
|
|
317
|
+
- [ ] 所有 `ServiceDef` 都声明为独立变量,未内联在 `serviceDefs` 数组中
|
|
318
|
+
- [ ] 每个 `ServiceDef` 声明都紧挨着对应的实现类,在同一个文件中
|
|
319
|
+
- [ ] `serviceImpl` 使用具名类,不使用匿名类或内联箭头函数
|
|
320
|
+
- [ ] 模块入口文件(`server-module.ts` / `client-module.ts`)只做导入和组装,不包含 ServiceDef 声明
|
|
321
|
+
- [ ] 导入类型时包含 `IServiceDef`(或其子类型如 `IControllerServiceDef`),为声明提供类型标注
|
|
322
|
+
|
|
323
|
+
## 相关文档
|
|
324
|
+
|
|
325
|
+
- 📖 [服务端模块开发](../guides/server-module.md)
|
|
326
|
+
- 📖 [客户端模块开发](../guides/client-module.md)
|
|
327
|
+
- 📖 [命名规范](./naming-conventions.md)
|
|
328
|
+
- ⚠️ [错误处理](./error-handling.md)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
**上一篇**: [命名规范](./naming-conventions.md) | **下一篇**: [错误处理](./error-handling.md)
|
package/docs/faq.md
CHANGED
|
@@ -188,18 +188,18 @@ export class ArticleController implements IControllerService {
|
|
|
188
188
|
创建 `src/server/index.ts`:
|
|
189
189
|
|
|
190
190
|
```typescript
|
|
191
|
-
import type { IModule } from '@linyjs/server-module-interface';
|
|
191
|
+
import type { IModule, IServiceDef } from '@linyjs/server-module-interface';
|
|
192
192
|
import { ArticleController } from './controllers/ArticleController';
|
|
193
193
|
|
|
194
|
+
const articleControllerDef: IServiceDef = {
|
|
195
|
+
serviceTag: 'articleController',
|
|
196
|
+
serviceImpl: ArticleController,
|
|
197
|
+
meta: { usageType: 'controller' }
|
|
198
|
+
};
|
|
199
|
+
|
|
194
200
|
export const blogServerModule: IModule = {
|
|
195
201
|
name: 'blogServer',
|
|
196
|
-
serviceDefs: [
|
|
197
|
-
{
|
|
198
|
-
serviceTag: 'articleController',
|
|
199
|
-
serviceImpl: ArticleController,
|
|
200
|
-
meta: { usageType: 'controller' }
|
|
201
|
-
}
|
|
202
|
-
]
|
|
202
|
+
serviceDefs: [articleControllerDef]
|
|
203
203
|
};
|
|
204
204
|
```
|
|
205
205
|
|
|
@@ -308,15 +308,15 @@ class BlogRouteService {
|
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
const blogRouteDef: IServiceDef = {
|
|
312
|
+
serviceTag: 'blogRoute',
|
|
313
|
+
serviceImpl: BlogRouteService,
|
|
314
|
+
meta: { usageType: 'route' }
|
|
315
|
+
};
|
|
316
|
+
|
|
311
317
|
export const blogClientModule: IModule = {
|
|
312
318
|
name: 'blogClient',
|
|
313
|
-
serviceDefs: [
|
|
314
|
-
{
|
|
315
|
-
serviceTag: 'blogRoute',
|
|
316
|
-
serviceImpl: BlogRouteService,
|
|
317
|
-
meta: { usageType: 'route' }
|
|
318
|
-
}
|
|
319
|
-
]
|
|
319
|
+
serviceDefs: [blogRouteDef]
|
|
320
320
|
};
|
|
321
321
|
```
|
|
322
322
|
|
|
@@ -100,7 +100,7 @@ hello-plugin/
|
|
|
100
100
|
如果你需要自定义或创建新的服务端代码,编辑 `src/server/index.ts`:
|
|
101
101
|
|
|
102
102
|
```typescript
|
|
103
|
-
import type { IModule } from '@linyjs/server-module-interface';
|
|
103
|
+
import type { IModule, IServiceDef } from '@linyjs/server-module-interface';
|
|
104
104
|
|
|
105
105
|
class HelloController {
|
|
106
106
|
getRoutes() {
|
|
@@ -116,13 +116,15 @@ class HelloController {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
const helloControllerDef: IServiceDef = {
|
|
120
|
+
serviceTag: 'helloController',
|
|
121
|
+
serviceImpl: HelloController,
|
|
122
|
+
meta: { usageType: 'controller' }
|
|
123
|
+
};
|
|
124
|
+
|
|
119
125
|
export const helloServerModule: IModule = {
|
|
120
126
|
name: 'helloServer',
|
|
121
|
-
serviceDefs: [
|
|
122
|
-
serviceTag: 'helloController',
|
|
123
|
-
serviceImpl: HelloController,
|
|
124
|
-
meta: { usageType: 'controller' }
|
|
125
|
-
}]
|
|
127
|
+
serviceDefs: [helloControllerDef]
|
|
126
128
|
};
|
|
127
129
|
```
|
|
128
130
|
|
|
@@ -133,7 +135,7 @@ export const helloServerModule: IModule = {
|
|
|
133
135
|
如果你需要自定义或创建新的客户端代码,编辑 `src/client/index.tsx`:
|
|
134
136
|
|
|
135
137
|
```typescript
|
|
136
|
-
import type { IModule } from '@linyjs/client-module-interface';
|
|
138
|
+
import type { IModule, IServiceDef } from '@linyjs/client-module-interface';
|
|
137
139
|
import React from 'react';
|
|
138
140
|
|
|
139
141
|
function HelloPage() {
|
|
@@ -145,23 +147,27 @@ function HelloPage() {
|
|
|
145
147
|
);
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
class HelloRouteService {
|
|
151
|
+
basePath = '/hello';
|
|
152
|
+
getRoutes() {
|
|
153
|
+
return [{
|
|
154
|
+
path: '/',
|
|
155
|
+
component: HelloPage,
|
|
156
|
+
key: 'hello-page',
|
|
157
|
+
meta: { title: 'Hello' }
|
|
158
|
+
}];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const helloRouteDef: IServiceDef = {
|
|
163
|
+
serviceTag: 'helloRoute',
|
|
164
|
+
serviceImpl: HelloRouteService,
|
|
165
|
+
meta: { usageType: 'route' }
|
|
166
|
+
};
|
|
167
|
+
|
|
148
168
|
export const helloClientModule: IModule = {
|
|
149
169
|
name: 'helloClient',
|
|
150
|
-
serviceDefs: [
|
|
151
|
-
serviceTag: 'helloRoute',
|
|
152
|
-
serviceImpl: class {
|
|
153
|
-
basePath = '/hello';
|
|
154
|
-
getRoutes() {
|
|
155
|
-
return [{
|
|
156
|
-
path: '/',
|
|
157
|
-
component: HelloPage,
|
|
158
|
-
key: 'hello-page',
|
|
159
|
-
meta: { title: 'Hello' }
|
|
160
|
-
}];
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
meta: { usageType: 'route' }
|
|
164
|
-
}]
|
|
170
|
+
serviceDefs: [helloRouteDef]
|
|
165
171
|
};
|
|
166
172
|
```
|
|
167
173
|
|
|
@@ -16,20 +16,24 @@ linyjs 提供完整的用户认证系统,支持:
|
|
|
16
16
|
### 在服务端模块中注入依赖
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
import type { IModule } from '@linyjs/server-module-interface';
|
|
19
|
+
import type { IModule, IServiceDef } from '@linyjs/server-module-interface';
|
|
20
20
|
import { login, register, verifyToken } from '@linyjs/auth';
|
|
21
21
|
|
|
22
|
+
class AuthController {
|
|
23
|
+
// ... 控制器实现
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const authControllerDef: IServiceDef = {
|
|
27
|
+
serviceTag: 'authController',
|
|
28
|
+
serviceImpl: AuthController,
|
|
29
|
+
dependencies: [],
|
|
30
|
+
meta: { usageType: 'controller' }
|
|
31
|
+
};
|
|
32
|
+
|
|
22
33
|
export const myServerModule: IModule = {
|
|
23
34
|
name: 'myServer',
|
|
24
|
-
moduleDependencies: ['auth'],
|
|
25
|
-
serviceDefs: [
|
|
26
|
-
{
|
|
27
|
-
serviceTag: 'authController',
|
|
28
|
-
serviceImpl: AuthController,
|
|
29
|
-
dependencies: [], // 依赖注入将在类构造函数中使用
|
|
30
|
-
meta: { usageType: 'controller' }
|
|
31
|
-
}
|
|
32
|
-
]
|
|
35
|
+
moduleDependencies: ['auth'],
|
|
36
|
+
serviceDefs: [authControllerDef]
|
|
33
37
|
};
|
|
34
38
|
```
|
|
35
39
|
|
|
@@ -276,22 +280,26 @@ function LoginForm() {
|
|
|
276
280
|
);
|
|
277
281
|
}
|
|
278
282
|
|
|
283
|
+
class LoginFormService {
|
|
284
|
+
getComponents() {
|
|
285
|
+
return {
|
|
286
|
+
LoginForm: {
|
|
287
|
+
component: LoginForm,
|
|
288
|
+
meta: { usageType: 'normal_component' }
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const loginFormDef: IServiceDef = {
|
|
295
|
+
serviceTag: 'loginForm',
|
|
296
|
+
serviceImpl: LoginFormService,
|
|
297
|
+
meta: { usageType: 'normal_service' }
|
|
298
|
+
};
|
|
299
|
+
|
|
279
300
|
export const authClientModule: IModule = {
|
|
280
301
|
name: 'authClient',
|
|
281
|
-
serviceDefs: [
|
|
282
|
-
serviceTag: 'loginForm',
|
|
283
|
-
serviceImpl: function() {
|
|
284
|
-
getComponents() {
|
|
285
|
-
return {
|
|
286
|
-
LoginForm: {
|
|
287
|
-
component: LoginForm,
|
|
288
|
-
meta: { usageType: 'normal_component' }
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
meta: { usageType: 'normal_service' }
|
|
294
|
-
}]
|
|
302
|
+
serviceDefs: [loginFormDef]
|
|
295
303
|
};
|
|
296
304
|
```
|
|
297
305
|
|
|
@@ -545,6 +545,12 @@ function MyPage() {
|
|
|
545
545
|
|
|
546
546
|
## 最佳实践
|
|
547
547
|
|
|
548
|
+
### 0. 遵循 ServiceDef 代码风格规范
|
|
549
|
+
|
|
550
|
+
> 📐 **重要**: 请阅读 [ServiceDef 代码风格规范](../best-practices/service-definition.md),了解两条核心规则:
|
|
551
|
+
> 1. ServiceDef 必须声明为独立变量,禁止内联在 `serviceDefs` 数组中
|
|
552
|
+
> 2. ServiceDef 声明必须与实现类放在同一个文件中
|
|
553
|
+
|
|
548
554
|
### 1. 组件拆分
|
|
549
555
|
|
|
550
556
|
```
|