koa3-cli 1.0.5 → 1.0.7
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 +95 -2
- package/app/controller/user.js +99 -99
- package/app/lib/logger.js +141 -141
- package/app/lib/validator.js +49 -0
- package/app/middleware/errorHandler.js +29 -0
- package/app/middleware/notFound.js +11 -0
- package/app/middleware/requestLogger.js +27 -27
- package/app/processEvents.js +14 -0
- package/app/router.js +7 -4
- package/app/schema/user.js +29 -0
- package/app/setup.js +48 -0
- package/app.js +37 -118
- package/config/config.default.js +82 -82
- package/config/loader.js +25 -0
- package/package.json +2 -1
- package/public/index.html +104 -18
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 全局错误处理中间件:捕获异常、记录日志、统一错误响应
|
|
3
|
+
*/
|
|
4
|
+
module.exports = function createErrorHandler(config, logger) {
|
|
5
|
+
return async function errorHandler(ctx, next) {
|
|
6
|
+
try {
|
|
7
|
+
await next();
|
|
8
|
+
} catch (err) {
|
|
9
|
+
ctx.status = err.status || 500;
|
|
10
|
+
const firstDetailMessage = err.details && err.details[0] && err.details[0].message;
|
|
11
|
+
ctx.body = {
|
|
12
|
+
success: false,
|
|
13
|
+
message: firstDetailMessage || err.message || 'Internal Server Error',
|
|
14
|
+
...(err.details && { errors: err.details })
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
logger.error('Request failed', {
|
|
18
|
+
requestId: ctx.state && ctx.state.requestId,
|
|
19
|
+
method: ctx.method,
|
|
20
|
+
url: ctx.originalUrl || ctx.url,
|
|
21
|
+
status: ctx.status,
|
|
22
|
+
message: err.message,
|
|
23
|
+
stack: err.stack
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
ctx.app.emit('error', err, ctx);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
function createRequestId() {
|
|
2
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
module.exports = function requestLogger(logger) {
|
|
6
|
-
return async function requestLoggerMiddleware(ctx, next) {
|
|
7
|
-
const start = Date.now();
|
|
8
|
-
const requestId = ctx.get('x-request-id') || createRequestId();
|
|
9
|
-
|
|
10
|
-
ctx.state.requestId = requestId;
|
|
11
|
-
ctx.set('x-request-id', requestId);
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
await next();
|
|
15
|
-
} finally {
|
|
16
|
-
const duration = Date.now() - start;
|
|
17
|
-
logger.access({
|
|
18
|
-
requestId,
|
|
19
|
-
method: ctx.method,
|
|
20
|
-
url: ctx.originalUrl || ctx.url,
|
|
21
|
-
status: ctx.status,
|
|
22
|
-
duration,
|
|
23
|
-
ip: ctx.ip
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
};
|
|
1
|
+
function createRequestId() {
|
|
2
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
module.exports = function requestLogger(logger) {
|
|
6
|
+
return async function requestLoggerMiddleware(ctx, next) {
|
|
7
|
+
const start = Date.now();
|
|
8
|
+
const requestId = ctx.get('x-request-id') || createRequestId();
|
|
9
|
+
|
|
10
|
+
ctx.state.requestId = requestId;
|
|
11
|
+
ctx.set('x-request-id', requestId);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
await next();
|
|
15
|
+
} finally {
|
|
16
|
+
const duration = Date.now() - start;
|
|
17
|
+
logger.access({
|
|
18
|
+
requestId,
|
|
19
|
+
method: ctx.method,
|
|
20
|
+
url: ctx.originalUrl || ctx.url,
|
|
21
|
+
status: ctx.status,
|
|
22
|
+
duration,
|
|
23
|
+
ip: ctx.ip
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 进程级错误监听:未捕获的 Promise 与异常
|
|
3
|
+
*/
|
|
4
|
+
function setupProcessEvents(logger) {
|
|
5
|
+
process.on('unhandledRejection', (reason) => {
|
|
6
|
+
logger.error('Unhandled promise rejection', reason);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
process.on('uncaughtException', (error) => {
|
|
10
|
+
logger.error('Uncaught exception', error);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = setupProcessEvents;
|
package/app/router.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
const { Router } = require('@koa/router');
|
|
2
|
+
const { validate } = require('./lib/validator');
|
|
3
|
+
const userSchema = require('./schema/user');
|
|
4
|
+
|
|
2
5
|
const router = new Router();
|
|
3
6
|
|
|
4
7
|
// 加载控制器
|
|
@@ -11,9 +14,9 @@ router.get('/', homeController.index);
|
|
|
11
14
|
|
|
12
15
|
// 用户相关路由
|
|
13
16
|
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);
|
|
17
|
+
router.get('/api/user/:id', validate({ params: userSchema.idParam }), userController.detail);
|
|
18
|
+
router.post('/api/user', validate({ body: userSchema.createUserBody }), userController.create);
|
|
19
|
+
router.put('/api/user/:id', validate({ params: userSchema.idParam, body: userSchema.updateUserBody }), userController.update);
|
|
20
|
+
router.delete('/api/user/:id', validate({ params: userSchema.idParam }), userController.delete);
|
|
18
21
|
|
|
19
22
|
module.exports = router;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { Joi } = require('../lib/validator');
|
|
2
|
+
|
|
3
|
+
const idParam = Joi.object({
|
|
4
|
+
id: Joi.string().required().messages({ 'any.required': '用户 id 不能为空' })
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
const createUserBody = Joi.object({
|
|
8
|
+
name: Joi.string().trim().min(1).max(100).required().messages({
|
|
9
|
+
'any.required': '用户名为必填',
|
|
10
|
+
'string.empty': '用户名不能为空',
|
|
11
|
+
'string.max': '用户名不能超过 100 个字符'
|
|
12
|
+
}),
|
|
13
|
+
email: Joi.string().email().allow('').optional(),
|
|
14
|
+
age: Joi.number().integer().min(0).max(150).optional()
|
|
15
|
+
}).options({ stripUnknown: true });
|
|
16
|
+
|
|
17
|
+
const updateUserBody = Joi.object({
|
|
18
|
+
name: Joi.string().trim().min(1).max(100).optional(),
|
|
19
|
+
email: Joi.string().email().allow('').optional(),
|
|
20
|
+
age: Joi.number().integer().min(0).max(150).optional()
|
|
21
|
+
}).min(1).messages({
|
|
22
|
+
'object.min': '至少需要提供一个要更新的字段'
|
|
23
|
+
}).options({ stripUnknown: true });
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
idParam,
|
|
27
|
+
createUserBody,
|
|
28
|
+
updateUserBody
|
|
29
|
+
};
|
package/app/setup.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 应用挂载:静态资源、视图、中间件、路由等
|
|
3
|
+
* 保持 app.js 只做「创建实例 + 调用 setup + 监听 + 启动」
|
|
4
|
+
*/
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const bodyParser = require('koa-bodyparser');
|
|
8
|
+
const serveStatic = require('koa-static');
|
|
9
|
+
const views = require('@ladjs/koa-views');
|
|
10
|
+
|
|
11
|
+
const createRequestLogger = require('./middleware/requestLogger');
|
|
12
|
+
const createErrorHandler = require('./middleware/errorHandler');
|
|
13
|
+
const notFound = require('./middleware/notFound');
|
|
14
|
+
const middleware = require('./middleware');
|
|
15
|
+
const router = require('./router');
|
|
16
|
+
|
|
17
|
+
const rootDir = path.join(__dirname, '..');
|
|
18
|
+
|
|
19
|
+
function setup(app, config, logger) {
|
|
20
|
+
// 静态资源
|
|
21
|
+
if (config.static && config.static.enable !== false) {
|
|
22
|
+
const staticPath = path.join(rootDir, config.static.dir || 'public');
|
|
23
|
+
if (fs.existsSync(staticPath)) {
|
|
24
|
+
app.use(serveStatic(staticPath, config.static.options || {}));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 视图
|
|
29
|
+
if (config.view && config.view.enable !== false) {
|
|
30
|
+
const viewPath = path.join(rootDir, config.view.root || 'app/view');
|
|
31
|
+
if (fs.existsSync(viewPath)) {
|
|
32
|
+
app.use(views(viewPath, config.view.options || { extension: 'ejs' }));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
app.use(bodyParser(config.bodyParser || {}));
|
|
37
|
+
app.use(createRequestLogger(logger));
|
|
38
|
+
|
|
39
|
+
if (middleware && typeof middleware === 'function') {
|
|
40
|
+
app.use(middleware);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
app.use(createErrorHandler(config, logger));
|
|
44
|
+
app.use(router.routes()).use(router.allowedMethods());
|
|
45
|
+
app.use(notFound);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = setup;
|
package/app.js
CHANGED
|
@@ -1,119 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
|
|
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(serveStatic(staticPath, config.static.options || {}));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (config.view && config.view.enable !== false) {
|
|
47
|
-
const viewPath = path.join(__dirname, config.view.root || 'app/view');
|
|
48
|
-
if (fs.existsSync(viewPath)) {
|
|
49
|
-
app.use(views(viewPath, config.view.options || {
|
|
50
|
-
extension: 'ejs'
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
app.use(bodyParser(config.bodyParser || {}));
|
|
56
|
-
app.use(createRequestLogger(logger));
|
|
57
|
-
|
|
58
|
-
if (middleware && typeof middleware === 'function') {
|
|
59
|
-
app.use(middleware);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
app.use(async (ctx, next) => {
|
|
63
|
-
try {
|
|
64
|
-
await next();
|
|
65
|
-
} catch (err) {
|
|
66
|
-
ctx.status = err.status || 500;
|
|
67
|
-
ctx.body = {
|
|
68
|
-
success: false,
|
|
69
|
-
message: err.message || 'Internal Server Error',
|
|
70
|
-
...(config.env === 'development' && { stack: err.stack })
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
logger.error('Request failed', {
|
|
74
|
-
requestId: ctx.state && ctx.state.requestId,
|
|
75
|
-
method: ctx.method,
|
|
76
|
-
url: ctx.originalUrl || ctx.url,
|
|
77
|
-
status: ctx.status,
|
|
78
|
-
message: err.message,
|
|
79
|
-
stack: err.stack
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
ctx.app.emit('error', err, ctx);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
app.use(router.routes()).use(router.allowedMethods());
|
|
87
|
-
|
|
88
|
-
app.use(async (ctx) => {
|
|
89
|
-
if (ctx.status === 404) {
|
|
90
|
-
ctx.body = {
|
|
91
|
-
success: false,
|
|
92
|
-
message: 'Not Found'
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
app.on('error', (err, ctx) => {
|
|
98
|
-
logger.error('Server error event', {
|
|
99
|
-
requestId: ctx && ctx.state && ctx.state.requestId,
|
|
100
|
-
message: err.message,
|
|
101
|
-
stack: err.stack
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
process.on('unhandledRejection', (reason) => {
|
|
106
|
-
logger.error('Unhandled promise rejection', reason);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
process.on('uncaughtException', (error) => {
|
|
110
|
-
logger.error('Uncaught exception', error);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const port = config.port || 3000;
|
|
114
|
-
app.listen(port, () => {
|
|
115
|
-
logger.info(`Server is running on http://localhost:${port}`);
|
|
116
|
-
logger.info(`Environment: ${config.env}`);
|
|
117
|
-
});
|
|
118
|
-
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
|
|
3
|
+
const Koa = require('koa');
|
|
4
|
+
const { loadConfig } = require('./config/loader');
|
|
5
|
+
const { createLogger } = require('./app/lib/logger');
|
|
6
|
+
const setup = require('./app/setup');
|
|
7
|
+
const setupProcessEvents = require('./app/processEvents');
|
|
8
|
+
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const app = new Koa();
|
|
11
|
+
const logger = createLogger({
|
|
12
|
+
...(config.logger || {}),
|
|
13
|
+
appName: config.name || 'koa3-cli',
|
|
14
|
+
cwd: __dirname
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
app.keys = config.keys || ['koa3-cli-secret-key'];
|
|
18
|
+
app.context.logger = logger;
|
|
19
|
+
|
|
20
|
+
setup(app, config, logger);
|
|
21
|
+
|
|
22
|
+
app.on('error', (err, ctx) => {
|
|
23
|
+
logger.error('Server error event', {
|
|
24
|
+
requestId: ctx && ctx.state && ctx.state.requestId,
|
|
25
|
+
message: err.message,
|
|
26
|
+
stack: err.stack
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
setupProcessEvents(logger);
|
|
31
|
+
|
|
32
|
+
const port = config.port || 3000;
|
|
33
|
+
app.listen(port, () => {
|
|
34
|
+
logger.info(`Server is running on http://localhost:${port}`);
|
|
35
|
+
logger.info(`Environment: ${config.env}`);
|
|
36
|
+
});
|
|
37
|
+
|
|
119
38
|
module.exports = app;
|
package/config/config.default.js
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default config loaded in all environments.
|
|
3
|
-
*/
|
|
4
|
-
module.exports = {
|
|
5
|
-
// Application name
|
|
6
|
-
name: 'koa3-cli',
|
|
7
|
-
|
|
8
|
-
// Runtime env: development, production, test
|
|
9
|
-
env: process.env.NODE_ENV || 'development',
|
|
10
|
-
|
|
11
|
-
// Server port
|
|
12
|
-
port: process.env.PORT || 3000,
|
|
13
|
-
|
|
14
|
-
// Cookie signing keys
|
|
15
|
-
keys: process.env.KEYS ? process.env.KEYS.split(',') : ['koa3-cli-secret-key'],
|
|
16
|
-
|
|
17
|
-
// Static assets
|
|
18
|
-
static: {
|
|
19
|
-
enable: true,
|
|
20
|
-
dir: 'public',
|
|
21
|
-
options: {
|
|
22
|
-
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
23
|
-
gzip: true
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
// Docs build config
|
|
28
|
-
docs: {
|
|
29
|
-
enable: true,
|
|
30
|
-
buildDir: 'public/docs'
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
// View engine
|
|
34
|
-
view: {
|
|
35
|
-
enable: true,
|
|
36
|
-
root: 'app/view',
|
|
37
|
-
options: {
|
|
38
|
-
extension: 'ejs',
|
|
39
|
-
map: {
|
|
40
|
-
html: 'ejs'
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
// bodyParser
|
|
46
|
-
bodyParser: {
|
|
47
|
-
enableTypes: ['json', 'form', 'text'],
|
|
48
|
-
jsonLimit: '10mb',
|
|
49
|
-
formLimit: '10mb'
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
// Database (example)
|
|
53
|
-
database: {
|
|
54
|
-
client: 'mysql',
|
|
55
|
-
connection: {
|
|
56
|
-
host: process.env.DB_HOST || 'localhost',
|
|
57
|
-
port: process.env.DB_PORT || 3306,
|
|
58
|
-
user: process.env.DB_USER || 'root',
|
|
59
|
-
password: process.env.DB_PASSWORD || '',
|
|
60
|
-
database: process.env.DB_NAME || 'test'
|
|
61
|
-
},
|
|
62
|
-
pool: {
|
|
63
|
-
min: 2,
|
|
64
|
-
max: 10
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
// Redis (example)
|
|
69
|
-
redis: {
|
|
70
|
-
host: process.env.REDIS_HOST || 'localhost',
|
|
71
|
-
port: process.env.REDIS_PORT || 6379,
|
|
72
|
-
password: process.env.REDIS_PASSWORD || '',
|
|
73
|
-
db: process.env.REDIS_DB || 0
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
// Logger
|
|
77
|
-
logger: {
|
|
78
|
-
level: process.env.LOG_LEVEL || 'info',
|
|
79
|
-
dir: process.env.LOG_DIR || 'logs',
|
|
80
|
-
enableConsole: process.env.LOG_ENABLE_CONSOLE !== 'false',
|
|
81
|
-
enableFile: process.env.LOG_ENABLE_FILE !== 'false'
|
|
82
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Default config loaded in all environments.
|
|
3
|
+
*/
|
|
4
|
+
module.exports = {
|
|
5
|
+
// Application name
|
|
6
|
+
name: 'koa3-cli',
|
|
7
|
+
|
|
8
|
+
// Runtime env: development, production, test
|
|
9
|
+
env: process.env.NODE_ENV || 'development',
|
|
10
|
+
|
|
11
|
+
// Server port
|
|
12
|
+
port: process.env.PORT || 3000,
|
|
13
|
+
|
|
14
|
+
// Cookie signing keys
|
|
15
|
+
keys: process.env.KEYS ? process.env.KEYS.split(',') : ['koa3-cli-secret-key'],
|
|
16
|
+
|
|
17
|
+
// Static assets
|
|
18
|
+
static: {
|
|
19
|
+
enable: true,
|
|
20
|
+
dir: 'public',
|
|
21
|
+
options: {
|
|
22
|
+
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
23
|
+
gzip: true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Docs build config
|
|
28
|
+
docs: {
|
|
29
|
+
enable: true,
|
|
30
|
+
buildDir: 'public/docs'
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// View engine
|
|
34
|
+
view: {
|
|
35
|
+
enable: true,
|
|
36
|
+
root: 'app/view',
|
|
37
|
+
options: {
|
|
38
|
+
extension: 'ejs',
|
|
39
|
+
map: {
|
|
40
|
+
html: 'ejs'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// bodyParser
|
|
46
|
+
bodyParser: {
|
|
47
|
+
enableTypes: ['json', 'form', 'text'],
|
|
48
|
+
jsonLimit: '10mb',
|
|
49
|
+
formLimit: '10mb'
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Database (example)
|
|
53
|
+
database: {
|
|
54
|
+
client: 'mysql',
|
|
55
|
+
connection: {
|
|
56
|
+
host: process.env.DB_HOST || 'localhost',
|
|
57
|
+
port: process.env.DB_PORT || 3306,
|
|
58
|
+
user: process.env.DB_USER || 'root',
|
|
59
|
+
password: process.env.DB_PASSWORD || '',
|
|
60
|
+
database: process.env.DB_NAME || 'test'
|
|
61
|
+
},
|
|
62
|
+
pool: {
|
|
63
|
+
min: 2,
|
|
64
|
+
max: 10
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Redis (example)
|
|
69
|
+
redis: {
|
|
70
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
71
|
+
port: process.env.REDIS_PORT || 6379,
|
|
72
|
+
password: process.env.REDIS_PASSWORD || '',
|
|
73
|
+
db: process.env.REDIS_DB || 0
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// Logger
|
|
77
|
+
logger: {
|
|
78
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
79
|
+
dir: process.env.LOG_DIR || 'logs',
|
|
80
|
+
enableConsole: process.env.LOG_ENABLE_CONSOLE !== 'false',
|
|
81
|
+
enableFile: process.env.LOG_ENABLE_FILE !== 'false'
|
|
82
|
+
}
|
|
83
83
|
};
|
package/config/loader.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置加载器:合并 default + 环境配置
|
|
3
|
+
*/
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const defaultConfig = require('./config.default');
|
|
7
|
+
|
|
8
|
+
function loadConfig() {
|
|
9
|
+
const env = process.env.NODE_ENV || 'development';
|
|
10
|
+
let envConfig = {};
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
if (env === 'production') {
|
|
14
|
+
envConfig = require('./config.prod');
|
|
15
|
+
} else if (env === 'local' || env === 'development') {
|
|
16
|
+
envConfig = require('./config.local');
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
// 忽略缺失的环境配置文件
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return Object.assign({}, defaultConfig, envConfig);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { loadConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa3-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Koa3脚手架",
|
|
5
5
|
"main": "app.js",
|
|
6
6
|
"bin": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"@ladjs/koa-views": "^9.0.0",
|
|
30
30
|
"dotenv": "^17.3.1",
|
|
31
31
|
"ejs": "^4.0.1",
|
|
32
|
+
"joi": "^17.13.3",
|
|
32
33
|
"koa": "^3.1.2",
|
|
33
34
|
"koa-bodyparser": "^4.4.1",
|
|
34
35
|
"koa-cors": "^0.0.16",
|