koa3-cli 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/LICENSE +9 -0
- package/README.md +177 -0
- package/app/controller/home.js +17 -0
- package/app/controller/user.js +89 -0
- package/app/middleware/auth.js +30 -0
- package/app/middleware/index.js +24 -0
- package/app/model/user.js +70 -0
- package/app/router.js +19 -0
- package/app/service/user.js +50 -0
- package/app.js +112 -0
- package/config/config.default.js +82 -0
- package/config/config.local.js +24 -0
- package/config/config.prod.js +22 -0
- package/env.example +27 -0
- package/koa3-cli-1.0.0.tgz +0 -0
- package/package.json +39 -0
- package/public/README.md +134 -0
- package/public/index.html +608 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 WZC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Koa3 CLI
|
|
2
|
+
|
|
3
|
+
基于 Koa3 的脚手架项目。
|
|
4
|
+
|
|
5
|
+
- 📖 文档地址:https://atwzc.cn/
|
|
6
|
+
- 🔗 Gitee 地址:https://gitee.com/wangziwl/koa3-cli
|
|
7
|
+
|
|
8
|
+
## 项目结构
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
koa2-cli/
|
|
12
|
+
├── app/ # 应用代码目录
|
|
13
|
+
│ ├── controller/ # 控制器目录
|
|
14
|
+
│ │ ├── home.js # 首页控制器
|
|
15
|
+
│ │ └── user.js # 用户控制器
|
|
16
|
+
│ ├── service/ # 服务层目录
|
|
17
|
+
│ │ └── user.js # 用户服务
|
|
18
|
+
│ ├── model/ # 数据模型目录
|
|
19
|
+
│ │ └── user.js # 用户模型
|
|
20
|
+
│ ├── middleware/ # 中间件目录
|
|
21
|
+
│ │ ├── index.js # 中间件入口
|
|
22
|
+
│ │ └── auth.js # 认证中间件示例
|
|
23
|
+
│ └── router.js # 路由配置
|
|
24
|
+
├── config/ # 配置文件目录
|
|
25
|
+
│ ├── config.default.js # 默认配置
|
|
26
|
+
│ ├── config.local.js # 本地开发配置
|
|
27
|
+
│ └── config.prod.js # 生产环境配置
|
|
28
|
+
├── public/ # 静态资源目录
|
|
29
|
+
│ └── index.html # 首页
|
|
30
|
+
├── app.js # 应用入口文件
|
|
31
|
+
├── package.json # 项目配置
|
|
32
|
+
└── README.md # 项目说明
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 特性
|
|
36
|
+
|
|
37
|
+
- ✅ 基于 Koa2,轻量高效
|
|
38
|
+
- ✅ 项目结构,清晰规范
|
|
39
|
+
- ✅ 支持多环境配置(development/production)
|
|
40
|
+
- ✅ MVC 架构(Controller/Service/Model)
|
|
41
|
+
- ✅ 中间件支持
|
|
42
|
+
- ✅ 统一的错误处理
|
|
43
|
+
- ✅ RESTful API 示例
|
|
44
|
+
|
|
45
|
+
## 快速开始
|
|
46
|
+
|
|
47
|
+
### 安装依赖
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 启动项目
|
|
54
|
+
|
|
55
|
+
开发环境(使用 nodemon 自动重启):
|
|
56
|
+
```bash
|
|
57
|
+
npm run dev
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
生产环境:
|
|
61
|
+
```bash
|
|
62
|
+
npm start
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 访问应用
|
|
66
|
+
|
|
67
|
+
- 首页: http://localhost:3000
|
|
68
|
+
- API 示例: http://localhost:3000/api/user
|
|
69
|
+
- 文档: http://localhost:3000/index.html
|
|
70
|
+
|
|
71
|
+
### 文档开发
|
|
72
|
+
|
|
73
|
+
启动 VuePress 文档开发服务器:
|
|
74
|
+
```bash
|
|
75
|
+
npm run docs:dev
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
构建文档为静态文件:
|
|
79
|
+
```bash
|
|
80
|
+
npm run docs:build
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 环境配置
|
|
84
|
+
|
|
85
|
+
项目支持多环境配置,通过 `NODE_ENV` 环境变量控制:
|
|
86
|
+
|
|
87
|
+
- `development` 或 `local`: 加载 `config.local.js`
|
|
88
|
+
- `production`: 加载 `config.prod.js`
|
|
89
|
+
- 默认: 加载 `config.default.js`
|
|
90
|
+
|
|
91
|
+
可以通过 `.env` 文件配置环境变量(参考 `.env.example`)。
|
|
92
|
+
|
|
93
|
+
## API 示例
|
|
94
|
+
|
|
95
|
+
### 获取用户列表
|
|
96
|
+
```bash
|
|
97
|
+
GET /api/user
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 获取用户详情
|
|
101
|
+
```bash
|
|
102
|
+
GET /api/user/:id
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 创建用户
|
|
106
|
+
```bash
|
|
107
|
+
POST /api/user
|
|
108
|
+
Content-Type: application/json
|
|
109
|
+
|
|
110
|
+
{
|
|
111
|
+
"name": "张三",
|
|
112
|
+
"email": "zhangsan@example.com"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 更新用户
|
|
117
|
+
```bash
|
|
118
|
+
PUT /api/user/:id
|
|
119
|
+
Content-Type: application/json
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
"name": "李四",
|
|
123
|
+
"email": "lisi@example.com"
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 删除用户
|
|
128
|
+
```bash
|
|
129
|
+
DELETE /api/user/:id
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 开发指南
|
|
133
|
+
|
|
134
|
+
### 添加新的控制器
|
|
135
|
+
|
|
136
|
+
1. 在 `app/controller/` 目录下创建控制器文件
|
|
137
|
+
2. 在 `app/router.js` 中注册路由
|
|
138
|
+
|
|
139
|
+
示例:
|
|
140
|
+
```javascript
|
|
141
|
+
// app/controller/product.js
|
|
142
|
+
class ProductController {
|
|
143
|
+
async list(ctx) {
|
|
144
|
+
ctx.body = await productService.getList();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
module.exports = new ProductController();
|
|
148
|
+
|
|
149
|
+
// app/router.js
|
|
150
|
+
const productController = require('./controller/product');
|
|
151
|
+
router.get('/api/product', productController.list);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 添加新的服务
|
|
155
|
+
|
|
156
|
+
在 `app/service/` 目录下创建服务文件,处理业务逻辑。
|
|
157
|
+
|
|
158
|
+
### 添加新的模型
|
|
159
|
+
|
|
160
|
+
在 `app/model/` 目录下创建模型文件,处理数据访问。
|
|
161
|
+
|
|
162
|
+
### 添加中间件
|
|
163
|
+
|
|
164
|
+
在 `app/middleware/` 目录下创建中间件文件,然后在 `app/middleware/index.js` 中引入使用。
|
|
165
|
+
|
|
166
|
+
## 技术栈
|
|
167
|
+
|
|
168
|
+
- **Koa2**: Web 框架
|
|
169
|
+
- **koa-router**: 路由
|
|
170
|
+
- **koa-bodyparser**: 请求体解析
|
|
171
|
+
- **koa-static**: 静态资源服务
|
|
172
|
+
- **koa-views**: 模板引擎支持
|
|
173
|
+
- **dotenv**: 环境变量管理
|
|
174
|
+
|
|
175
|
+
## 许可证
|
|
176
|
+
|
|
177
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 首页控制器
|
|
3
|
+
*/
|
|
4
|
+
class HomeController {
|
|
5
|
+
/**
|
|
6
|
+
* 首页
|
|
7
|
+
*/
|
|
8
|
+
async index(ctx) {
|
|
9
|
+
ctx.body = {
|
|
10
|
+
message: 'Welcome to Koa2 CLI',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
timestamp: new Date().toISOString()
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = new HomeController();
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户控制器
|
|
3
|
+
*/
|
|
4
|
+
const userService = require('../service/user');
|
|
5
|
+
|
|
6
|
+
class UserController {
|
|
7
|
+
/**
|
|
8
|
+
* 获取用户列表
|
|
9
|
+
*/
|
|
10
|
+
async list(ctx) {
|
|
11
|
+
try {
|
|
12
|
+
const users = await userService.getUserList();
|
|
13
|
+
ctx.body = users;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
ctx.throw(500, error.message);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获取用户详情
|
|
21
|
+
*/
|
|
22
|
+
async detail(ctx) {
|
|
23
|
+
try {
|
|
24
|
+
const { id } = ctx.params;
|
|
25
|
+
const user = await userService.getUserById(id);
|
|
26
|
+
if (!user) {
|
|
27
|
+
ctx.status = 404;
|
|
28
|
+
ctx.body = { message: 'User not found' };
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
ctx.body = user;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
ctx.throw(500, error.message);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 创建用户
|
|
39
|
+
*/
|
|
40
|
+
async create(ctx) {
|
|
41
|
+
try {
|
|
42
|
+
const userData = ctx.request.body;
|
|
43
|
+
const user = await userService.createUser(userData);
|
|
44
|
+
ctx.status = 201;
|
|
45
|
+
ctx.body = user;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
ctx.throw(500, error.message);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 更新用户
|
|
53
|
+
*/
|
|
54
|
+
async update(ctx) {
|
|
55
|
+
try {
|
|
56
|
+
const { id } = ctx.params;
|
|
57
|
+
const userData = ctx.request.body;
|
|
58
|
+
const user = await userService.updateUser(id, userData);
|
|
59
|
+
if (!user) {
|
|
60
|
+
ctx.status = 404;
|
|
61
|
+
ctx.body = { message: 'User not found' };
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
ctx.body = user;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
ctx.throw(500, error.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 删除用户
|
|
72
|
+
*/
|
|
73
|
+
async delete(ctx) {
|
|
74
|
+
try {
|
|
75
|
+
const { id } = ctx.params;
|
|
76
|
+
const result = await userService.deleteUser(id);
|
|
77
|
+
if (!result) {
|
|
78
|
+
ctx.status = 404;
|
|
79
|
+
ctx.body = { message: 'User not found' };
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
ctx.status = 204;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
ctx.throw(500, error.message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = new UserController();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 认证中间件示例
|
|
3
|
+
* 可以根据需要启用
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = async (ctx, next) => {
|
|
7
|
+
// 示例:简单的token验证
|
|
8
|
+
const token = ctx.headers.authorization;
|
|
9
|
+
|
|
10
|
+
if (!token && ctx.path.startsWith('/api')) {
|
|
11
|
+
// 某些公开接口可以跳过认证
|
|
12
|
+
const publicPaths = ['/api/user'];
|
|
13
|
+
if (!publicPaths.includes(ctx.path)) {
|
|
14
|
+
ctx.status = 401;
|
|
15
|
+
ctx.body = {
|
|
16
|
+
success: false,
|
|
17
|
+
message: 'Unauthorized'
|
|
18
|
+
};
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 验证token逻辑(示例)
|
|
24
|
+
if (token) {
|
|
25
|
+
// 这里应该验证token的有效性
|
|
26
|
+
// ctx.user = await verifyToken(token);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await next();
|
|
30
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 中间件入口文件
|
|
3
|
+
* 可以在这里统一管理和导出所有中间件
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// 组合中间件:按顺序执行,确保 next 链正确传递
|
|
7
|
+
module.exports = async (ctx, next) => {
|
|
8
|
+
// 1. 请求时间中间件
|
|
9
|
+
ctx.requestTime = Date.now();
|
|
10
|
+
|
|
11
|
+
// 2. 等待后续中间件执行
|
|
12
|
+
await next();
|
|
13
|
+
|
|
14
|
+
// 3. API响应格式中间件(在响应返回前处理)
|
|
15
|
+
// 如果是API请求,统一响应格式
|
|
16
|
+
if (ctx.path.startsWith('/api')) {
|
|
17
|
+
if (ctx.body && typeof ctx.body === 'object' && !ctx.body.success) {
|
|
18
|
+
ctx.body = {
|
|
19
|
+
success: true,
|
|
20
|
+
data: ctx.body
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户数据模型
|
|
3
|
+
* 负责与数据库交互
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// 示例:模拟数据存储(实际项目中应该连接真实数据库)
|
|
7
|
+
let users = [
|
|
8
|
+
{ id: 1, name: '张三', email: 'zhangsan@example.com', createdAt: new Date() },
|
|
9
|
+
{ id: 2, name: '李四', email: 'lisi@example.com', createdAt: new Date() }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
class UserModel {
|
|
13
|
+
/**
|
|
14
|
+
* 查找所有用户
|
|
15
|
+
*/
|
|
16
|
+
async findAll() {
|
|
17
|
+
// 实际项目中应该查询数据库
|
|
18
|
+
return users;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 根据ID查找用户
|
|
23
|
+
*/
|
|
24
|
+
async findById(id) {
|
|
25
|
+
return users.find(user => user.id === parseInt(id));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 创建用户
|
|
30
|
+
*/
|
|
31
|
+
async create(userData) {
|
|
32
|
+
const newUser = {
|
|
33
|
+
id: users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1,
|
|
34
|
+
...userData,
|
|
35
|
+
createdAt: new Date()
|
|
36
|
+
};
|
|
37
|
+
users.push(newUser);
|
|
38
|
+
return newUser;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 更新用户
|
|
43
|
+
*/
|
|
44
|
+
async update(id, userData) {
|
|
45
|
+
const index = users.findIndex(user => user.id === parseInt(id));
|
|
46
|
+
if (index === -1) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
users[index] = {
|
|
50
|
+
...users[index],
|
|
51
|
+
...userData,
|
|
52
|
+
updatedAt: new Date()
|
|
53
|
+
};
|
|
54
|
+
return users[index];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 删除用户
|
|
59
|
+
*/
|
|
60
|
+
async delete(id) {
|
|
61
|
+
const index = users.findIndex(user => user.id === parseInt(id));
|
|
62
|
+
if (index === -1) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
users.splice(index, 1);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = new UserModel();
|
package/app/router.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const Router = require('koa-router');
|
|
2
|
+
const router = new Router();
|
|
3
|
+
|
|
4
|
+
// 加载控制器
|
|
5
|
+
const homeController = require('./controller/home');
|
|
6
|
+
const userController = require('./controller/user');
|
|
7
|
+
|
|
8
|
+
// 路由配置
|
|
9
|
+
// 首页
|
|
10
|
+
router.get('/', homeController.index);
|
|
11
|
+
|
|
12
|
+
// 用户相关路由
|
|
13
|
+
router.get('/api/user', userController.list);
|
|
14
|
+
router.get('/api/user/:id', userController.detail);
|
|
15
|
+
router.post('/api/user', userController.create);
|
|
16
|
+
router.put('/api/user/:id', userController.update);
|
|
17
|
+
router.delete('/api/user/:id', userController.delete);
|
|
18
|
+
|
|
19
|
+
module.exports = router;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户服务层
|
|
3
|
+
* 处理业务逻辑,与数据模型交互
|
|
4
|
+
*/
|
|
5
|
+
const userModel = require('../model/user');
|
|
6
|
+
|
|
7
|
+
class UserService {
|
|
8
|
+
/**
|
|
9
|
+
* 获取用户列表
|
|
10
|
+
*/
|
|
11
|
+
async getUserList() {
|
|
12
|
+
// 这里应该从数据库获取数据
|
|
13
|
+
// 示例:返回模拟数据
|
|
14
|
+
return await userModel.findAll();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 根据ID获取用户
|
|
19
|
+
*/
|
|
20
|
+
async getUserById(id) {
|
|
21
|
+
return await userModel.findById(id);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 创建用户
|
|
26
|
+
*/
|
|
27
|
+
async createUser(userData) {
|
|
28
|
+
// 数据验证
|
|
29
|
+
if (!userData.name || !userData.email) {
|
|
30
|
+
throw new Error('Name and email are required');
|
|
31
|
+
}
|
|
32
|
+
return await userModel.create(userData);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 更新用户
|
|
37
|
+
*/
|
|
38
|
+
async updateUser(id, userData) {
|
|
39
|
+
return await userModel.update(id, userData);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 删除用户
|
|
44
|
+
*/
|
|
45
|
+
async deleteUser(id) {
|
|
46
|
+
return await userModel.delete(id);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = new UserService();
|
package/app.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const Koa = require('koa');
|
|
2
|
+
const Router = require('koa-router');
|
|
3
|
+
const bodyParser = require('koa-bodyparser');
|
|
4
|
+
const static = require('koa-static');
|
|
5
|
+
const views = require('koa-views');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
// 加载环境变量
|
|
10
|
+
require('dotenv').config();
|
|
11
|
+
|
|
12
|
+
// 加载配置(支持环境配置覆盖)
|
|
13
|
+
const env = process.env.NODE_ENV || 'development';
|
|
14
|
+
const defaultConfig = require('./config/config.default');
|
|
15
|
+
let envConfig = {};
|
|
16
|
+
try {
|
|
17
|
+
if (env === 'production') {
|
|
18
|
+
envConfig = require('./config/config.prod');
|
|
19
|
+
} else if (env === 'local' || env === 'development') {
|
|
20
|
+
envConfig = require('./config/config.local');
|
|
21
|
+
}
|
|
22
|
+
} catch (e) {
|
|
23
|
+
// 环境配置文件不存在时忽略
|
|
24
|
+
}
|
|
25
|
+
const config = Object.assign({}, defaultConfig, envConfig);
|
|
26
|
+
|
|
27
|
+
// 加载中间件
|
|
28
|
+
const middleware = require('./app/middleware');
|
|
29
|
+
|
|
30
|
+
// 加载路由
|
|
31
|
+
const router = require('./app/router');
|
|
32
|
+
|
|
33
|
+
const app = new Koa();
|
|
34
|
+
|
|
35
|
+
// 应用配置
|
|
36
|
+
app.keys = config.keys || ['koa2-cli-secret-key'];
|
|
37
|
+
|
|
38
|
+
// 静态资源
|
|
39
|
+
if (config.static && config.static.enable !== false) {
|
|
40
|
+
const staticPath = path.join(__dirname, config.static.dir || 'public');
|
|
41
|
+
if (fs.existsSync(staticPath)) {
|
|
42
|
+
app.use(static(staticPath, config.static.options || {}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 模板引擎
|
|
47
|
+
if (config.view && config.view.enable !== false) {
|
|
48
|
+
const viewPath = path.join(__dirname, config.view.root || 'app/view');
|
|
49
|
+
if (fs.existsSync(viewPath)) {
|
|
50
|
+
app.use(views(viewPath, config.view.options || {
|
|
51
|
+
extension: 'ejs'
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 请求体解析
|
|
57
|
+
app.use(bodyParser(config.bodyParser || {}));
|
|
58
|
+
|
|
59
|
+
// 自定义中间件
|
|
60
|
+
if (middleware && typeof middleware === 'function') {
|
|
61
|
+
app.use(middleware);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 错误处理中间件
|
|
65
|
+
app.use(async (ctx, next) => {
|
|
66
|
+
try {
|
|
67
|
+
await next();
|
|
68
|
+
} catch (err) {
|
|
69
|
+
ctx.status = err.status || 500;
|
|
70
|
+
ctx.body = {
|
|
71
|
+
success: false,
|
|
72
|
+
message: err.message || 'Internal Server Error',
|
|
73
|
+
...(config.env === 'development' && { stack: err.stack })
|
|
74
|
+
};
|
|
75
|
+
ctx.app.emit('error', err, ctx);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 日志中间件
|
|
80
|
+
app.use(async (ctx, next) => {
|
|
81
|
+
const start = Date.now();
|
|
82
|
+
await next();
|
|
83
|
+
const ms = Date.now() - start;
|
|
84
|
+
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// 注册路由
|
|
88
|
+
app.use(router.routes()).use(router.allowedMethods());
|
|
89
|
+
|
|
90
|
+
// 404 处理(必须在路由之后)
|
|
91
|
+
app.use(async (ctx) => {
|
|
92
|
+
if (ctx.status === 404) {
|
|
93
|
+
ctx.body = {
|
|
94
|
+
success: false,
|
|
95
|
+
message: 'Not Found'
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// 错误事件监听
|
|
101
|
+
app.on('error', (err, ctx) => {
|
|
102
|
+
console.error('Server error:', err);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 启动服务器
|
|
106
|
+
const port = config.port || 3000;
|
|
107
|
+
app.listen(port, () => {
|
|
108
|
+
console.log(`Server is running on http://localhost:${port}`);
|
|
109
|
+
console.log(`Environment: ${config.env}`);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
module.exports = app;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 默认配置文件
|
|
3
|
+
* 所有环境都会加载此配置
|
|
4
|
+
*/
|
|
5
|
+
module.exports = {
|
|
6
|
+
// 应用名称
|
|
7
|
+
name: 'koa2-cli',
|
|
8
|
+
|
|
9
|
+
// 运行环境: development, production, test
|
|
10
|
+
env: process.env.NODE_ENV || 'development',
|
|
11
|
+
|
|
12
|
+
// 服务端口
|
|
13
|
+
port: process.env.PORT || 3000,
|
|
14
|
+
|
|
15
|
+
// 密钥,用于加密cookie等
|
|
16
|
+
keys: process.env.KEYS ? process.env.KEYS.split(',') : ['koa2-cli-secret-key'],
|
|
17
|
+
|
|
18
|
+
// 静态资源配置
|
|
19
|
+
static: {
|
|
20
|
+
enable: true,
|
|
21
|
+
dir: 'public',
|
|
22
|
+
options: {
|
|
23
|
+
maxAge: 365 * 24 * 60 * 60 * 1000, // 1年
|
|
24
|
+
gzip: true
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// VuePress 文档配置
|
|
29
|
+
docs: {
|
|
30
|
+
enable: true,
|
|
31
|
+
buildDir: 'public/docs'
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// 视图配置
|
|
35
|
+
view: {
|
|
36
|
+
enable: true,
|
|
37
|
+
root: 'app/view',
|
|
38
|
+
options: {
|
|
39
|
+
extension: 'ejs',
|
|
40
|
+
map: {
|
|
41
|
+
html: 'ejs'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// bodyParser配置
|
|
47
|
+
bodyParser: {
|
|
48
|
+
enableTypes: ['json', 'form', 'text'],
|
|
49
|
+
jsonLimit: '10mb',
|
|
50
|
+
formLimit: '10mb'
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// 数据库配置(示例)
|
|
54
|
+
database: {
|
|
55
|
+
client: 'mysql',
|
|
56
|
+
connection: {
|
|
57
|
+
host: process.env.DB_HOST || 'localhost',
|
|
58
|
+
port: process.env.DB_PORT || 3306,
|
|
59
|
+
user: process.env.DB_USER || 'root',
|
|
60
|
+
password: process.env.DB_PASSWORD || '',
|
|
61
|
+
database: process.env.DB_NAME || 'test'
|
|
62
|
+
},
|
|
63
|
+
pool: {
|
|
64
|
+
min: 2,
|
|
65
|
+
max: 10
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Redis配置(示例)
|
|
70
|
+
redis: {
|
|
71
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
72
|
+
port: process.env.REDIS_PORT || 6379,
|
|
73
|
+
password: process.env.REDIS_PASSWORD || '',
|
|
74
|
+
db: process.env.REDIS_DB || 0
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// 日志配置
|
|
78
|
+
logger: {
|
|
79
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
80
|
+
dir: 'logs'
|
|
81
|
+
}
|
|
82
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本地开发环境配置
|
|
3
|
+
* 只在本地开发时加载,会覆盖 config.default.js 中的配置
|
|
4
|
+
*/
|
|
5
|
+
module.exports = {
|
|
6
|
+
env: 'development',
|
|
7
|
+
port: 3000,
|
|
8
|
+
|
|
9
|
+
// 开发环境可以开启更详细的日志
|
|
10
|
+
logger: {
|
|
11
|
+
level: 'debug'
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// 开发环境数据库配置示例
|
|
15
|
+
database: {
|
|
16
|
+
connection: {
|
|
17
|
+
host: 'localhost',
|
|
18
|
+
port: 3306,
|
|
19
|
+
user: 'root',
|
|
20
|
+
password: '',
|
|
21
|
+
database: 'test_dev'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|