chanjs 1.0.27 → 1.0.28
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/core/chan.js +29 -89
- package/core/lib/extend/helper.js +78 -0
- package/core/lib/middleware/template.js +1 -0
- package/core/lib/service/service.js +1 -5
- package/package.json +1 -1
- package/core/lib/extend/bindClass.js +0 -22
- package/core/lib/extend/router.js +0 -16
- package/core/lib/utils/fsExtend.js +0 -135
package/core/chan.js
CHANGED
@@ -1,50 +1,37 @@
|
|
1
1
|
const express = require("express");
|
2
|
+
const path = require("path");
|
3
|
+
const fs = require("fs");
|
4
|
+
const cors = require("cors");
|
2
5
|
const config = require("./lib/config/config.js");
|
3
|
-
const bindClass = require("./lib/extend/
|
6
|
+
const {bindClass,createKnex,loadWebToEnd} = require("./lib/extend/helper.js");
|
4
7
|
const Controller = require("./lib/controller/controller.js");
|
5
8
|
const Service = require("./lib/service/service.js");
|
6
|
-
const path = require("path");
|
7
|
-
const fs = require("fs");
|
8
9
|
const core = require("./lib/index.js");
|
9
|
-
const cors = require("cors");
|
10
|
-
|
11
10
|
/**
|
12
11
|
* @description 基于express封装的mvc框架,遵循约定优于配置原则
|
13
12
|
*/
|
14
13
|
class Chan {
|
15
|
-
static
|
16
|
-
//模块
|
14
|
+
static helper = {};
|
17
15
|
static modules = {};
|
18
|
-
//插件
|
19
16
|
static plugins = {};
|
20
|
-
|
21
|
-
static
|
22
|
-
static
|
23
|
-
|
24
|
-
constructor(options = {}) {
|
25
|
-
//配置
|
26
|
-
Chan.config = { ...config, ...options };
|
27
|
-
//控制器基类
|
28
|
-
Chan.Controller = Controller;
|
17
|
+
static config = config;
|
18
|
+
static Controller = Controller;
|
19
|
+
static Service = Service;
|
20
|
+
constructor() {
|
29
21
|
this.init();
|
30
22
|
}
|
31
23
|
|
32
24
|
init() {
|
33
25
|
this.app = express();
|
34
26
|
this.router = express.Router();
|
35
|
-
//加载配置
|
36
27
|
this.loadConfig();
|
37
|
-
//加载扩展
|
38
28
|
this.loadExtends();
|
39
29
|
//加载核心(日志、favicon 图标、cookie、json、url、模板引擎、静态资源)
|
40
30
|
this.loadCore();
|
41
|
-
//加载实例化数据库
|
42
31
|
this.loadKnex();
|
43
|
-
//解决跨域
|
44
32
|
this.loadCors();
|
45
33
|
}
|
46
34
|
|
47
|
-
// 加载配置
|
48
35
|
loadConfig() {
|
49
36
|
const configPath = path.join(Chan.config.APP_PATH, "config/index.js");
|
50
37
|
if (fs.existsSync(configPath)) {
|
@@ -53,7 +40,6 @@ class Chan {
|
|
53
40
|
}
|
54
41
|
}
|
55
42
|
|
56
|
-
// 加载扩展
|
57
43
|
loadExtends() {
|
58
44
|
const extendPath = path.join(Chan.config.APP_PATH, "extend");
|
59
45
|
if (fs.existsSync(extendPath)) {
|
@@ -69,65 +55,35 @@ class Chan {
|
|
69
55
|
}
|
70
56
|
}
|
71
57
|
|
58
|
+
/**
|
59
|
+
* @description app核心模块:日志、favicon 图标、cookie、json、url、模板引擎、静态资源
|
60
|
+
*/
|
61
|
+
loadCore() {
|
62
|
+
core(this.app, Chan.config);
|
63
|
+
}
|
64
|
+
|
72
65
|
//数据库操作
|
73
66
|
loadKnex() {
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
} = Chan.config.database;
|
84
|
-
|
85
|
-
const knex = require("knex")({
|
86
|
-
client: client,
|
87
|
-
connection: {
|
88
|
-
host,
|
89
|
-
port,
|
90
|
-
user,
|
91
|
-
password,
|
92
|
-
database,
|
93
|
-
charset,
|
94
|
-
},
|
95
|
-
debug: Chan.config.SqlDebug, //指明是否开启debug模式,默认为true表示开启
|
96
|
-
pool: {
|
97
|
-
//指明数据库连接池的大小,默认为{min: 2, max: 10}
|
98
|
-
min: 0,
|
99
|
-
max: 2,
|
100
|
-
},
|
101
|
-
log: {
|
102
|
-
warn(message) {
|
103
|
-
console.error("[knex warn]", message);
|
104
|
-
},
|
105
|
-
error(message) {
|
106
|
-
console.error("[knex error]", message);
|
107
|
-
},
|
108
|
-
},
|
109
|
-
});
|
110
|
-
|
111
|
-
//数据库操作实例
|
112
|
-
Chan.knex = knex;
|
113
|
-
//数据库操作基类
|
114
|
-
Chan.Service = Service(knex);
|
67
|
+
if(Chan.config?.db?.length > 0){
|
68
|
+
Chan.config.db.map((item,index) => {
|
69
|
+
if(index ==0){
|
70
|
+
Chan.knex = createKnex(item);
|
71
|
+
}else{
|
72
|
+
Chan[`knex${index}`] = createKnex(item);
|
73
|
+
}
|
74
|
+
})
|
75
|
+
}
|
115
76
|
}
|
116
77
|
|
117
78
|
//开始启动
|
118
79
|
beforeStart(cb) {
|
119
|
-
|
120
80
|
cb && cb();
|
121
81
|
}
|
122
82
|
//启动
|
123
83
|
start(cb) {
|
124
|
-
//加载插件
|
125
84
|
this.loadPlugins();
|
126
|
-
//加载模块
|
127
85
|
this.loadModules();
|
128
|
-
//加载通用路由
|
129
86
|
this.loadCommonRouter();
|
130
|
-
// 初始化一些配置
|
131
87
|
cb && cb();
|
132
88
|
}
|
133
89
|
|
@@ -141,25 +97,15 @@ class Chan {
|
|
141
97
|
this.loadModules("plugins");
|
142
98
|
}
|
143
99
|
|
144
|
-
/**
|
145
|
-
* @description app核心模块:日志、favicon 图标、cookie、json、url、模板引擎、静态资源
|
146
|
-
*/
|
147
|
-
loadCore() {
|
148
|
-
core(this.app, Chan.config);
|
149
|
-
}
|
150
|
-
|
151
100
|
/**
|
152
101
|
* @description 模块加载入口(路由&控制器& 服务)
|
153
102
|
*/
|
154
103
|
loadModules(modules = "modules") {
|
155
104
|
const configPath = path.join(Chan.config.APP_PATH, modules);
|
156
105
|
if (fs.existsSync(configPath)) {
|
157
|
-
|
158
|
-
|
159
|
-
.filter((dirent) => dirent.isDirectory())
|
160
|
-
.map((dirent) => dirent.name);
|
106
|
+
//模块名称
|
107
|
+
const dirs = loadWebToEnd(Chan.config[modules]);
|
161
108
|
Chan[modules] = {};
|
162
|
-
|
163
109
|
// 先加载所有服务
|
164
110
|
dirs.forEach((item) => {
|
165
111
|
Chan[modules][item] = {
|
@@ -173,9 +119,6 @@ class Chan {
|
|
173
119
|
dirs.forEach((item) => {
|
174
120
|
this.loadModule(modules, item);
|
175
121
|
});
|
176
|
-
|
177
|
-
//执行路由
|
178
|
-
// this.app.use(this.router);
|
179
122
|
}
|
180
123
|
}
|
181
124
|
|
@@ -209,8 +152,7 @@ class Chan {
|
|
209
152
|
const Service = require(path.join(servicesDir, file));
|
210
153
|
const serviceName = file.replace(".js", "");
|
211
154
|
//模块文件夹-模块文件名-服务-方法
|
212
|
-
Chan[modules][moduleName].service[serviceName] = {};
|
213
|
-
Chan[modules][moduleName].service[serviceName] = bindClass(Service);
|
155
|
+
Chan[modules][moduleName].service[serviceName] = {...bindClass(Service)};
|
214
156
|
}
|
215
157
|
}
|
216
158
|
}
|
@@ -235,9 +177,7 @@ class Chan {
|
|
235
177
|
file = controllers[i];
|
236
178
|
const controller = require(path.join(controllersDir, file));
|
237
179
|
const controllerName = file.replace(".js", "");
|
238
|
-
Chan[modules][moduleName].controller[controllerName] = {};
|
239
|
-
Chan[modules][moduleName].controller[controllerName] =
|
240
|
-
bindClass(controller);
|
180
|
+
Chan[modules][moduleName].controller[controllerName] = {...bindClass(controller)};
|
241
181
|
}
|
242
182
|
}
|
243
183
|
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
const knex = require('knex');
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @description 实例化一个类,并将该类的所有方法绑定到一个新的对象上。
|
5
|
+
* @param {Function} className - 需要实例化的类。
|
6
|
+
*@returns {Object} 包含绑定方法的对象。
|
7
|
+
*/
|
8
|
+
function bindClass(className) {
|
9
|
+
let obj = {};
|
10
|
+
const cls = new className();
|
11
|
+
Object.getOwnPropertyNames(cls.constructor.prototype).forEach(
|
12
|
+
(methodName) => {
|
13
|
+
if (
|
14
|
+
methodName !== "constructor" &&
|
15
|
+
typeof cls[methodName] === "function"
|
16
|
+
) {
|
17
|
+
obj[methodName] = cls[methodName].bind(cls);
|
18
|
+
}
|
19
|
+
}
|
20
|
+
);
|
21
|
+
return obj;
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
function createKnex(opt) {
|
26
|
+
let config = {
|
27
|
+
host:"localhost",
|
28
|
+
port:"3306",
|
29
|
+
client:"mysql2",
|
30
|
+
charset:"utf8mb4",
|
31
|
+
debug:false,
|
32
|
+
...opt
|
33
|
+
};
|
34
|
+
return knex({
|
35
|
+
client: config.client,
|
36
|
+
connection: {
|
37
|
+
host:config.host,
|
38
|
+
port:config.port,
|
39
|
+
user:config.user,
|
40
|
+
password:config.password,
|
41
|
+
database:config.database,
|
42
|
+
charset:config.charset,
|
43
|
+
},
|
44
|
+
debug: config.debug,
|
45
|
+
//默认为{min: 2, max: 10}
|
46
|
+
pool: {
|
47
|
+
min: 0,
|
48
|
+
max: 2,
|
49
|
+
},
|
50
|
+
log: {
|
51
|
+
warn(message) {
|
52
|
+
console.error("[knex warn]", message);
|
53
|
+
},
|
54
|
+
error(message) {
|
55
|
+
console.error("[knex error]", message);
|
56
|
+
},
|
57
|
+
},
|
58
|
+
});
|
59
|
+
}
|
60
|
+
/**
|
61
|
+
*
|
62
|
+
* @param {*} module 模块目录
|
63
|
+
* @returns Array
|
64
|
+
* @description 将web模块放到最后加载
|
65
|
+
*/
|
66
|
+
function loadWebToEnd(module=[]){
|
67
|
+
const index = module.indexOf('web');
|
68
|
+
if (index !== -1) {
|
69
|
+
const web = module.splice(index, 1);
|
70
|
+
module.push(web[0]);
|
71
|
+
}
|
72
|
+
return module;
|
73
|
+
}
|
74
|
+
module.exports = {
|
75
|
+
bindClass,
|
76
|
+
createKnex,
|
77
|
+
loadWebToEnd
|
78
|
+
};
|
package/package.json
CHANGED
@@ -1,22 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @description 实例化一个类,并将该类的所有方法绑定到一个新的对象上。
|
3
|
-
* @param {Function} className - 需要实例化的类。
|
4
|
-
*@returns {Object} 包含绑定方法的对象。
|
5
|
-
*/
|
6
|
-
function bindClass(className) {
|
7
|
-
let obj = {};
|
8
|
-
const cls = new className();
|
9
|
-
Object.getOwnPropertyNames(cls.constructor.prototype).forEach(
|
10
|
-
(methodName) => {
|
11
|
-
if (
|
12
|
-
methodName !== "constructor" &&
|
13
|
-
typeof cls[methodName] === "function"
|
14
|
-
) {
|
15
|
-
obj[methodName] = cls[methodName].bind(cls);
|
16
|
-
}
|
17
|
-
}
|
18
|
-
);
|
19
|
-
return obj;
|
20
|
-
}
|
21
|
-
|
22
|
-
module.exports = bindClass;
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
/**
|
3
|
-
* @description 给路由加前缀
|
4
|
-
* @returns viod 0
|
5
|
-
*/
|
6
|
-
addRoutePrefix: () => {
|
7
|
-
return function (req, res, next) {
|
8
|
-
req.baseUrl = `${prefix}${req.baseUrl || ""}`;
|
9
|
-
// 如果有 query 参数,则保留原有参数
|
10
|
-
req.url = `${req.baseUrl}${
|
11
|
-
req.url.includes("?") ? req.url.split("?")[1] : ""
|
12
|
-
}`;
|
13
|
-
next();
|
14
|
-
};
|
15
|
-
},
|
16
|
-
};
|
@@ -1,135 +0,0 @@
|
|
1
|
-
const fs = require("fs");
|
2
|
-
const path = require("path");
|
3
|
-
|
4
|
-
/**
|
5
|
-
* @description 是否存在
|
6
|
-
* @param {*} dir 目录
|
7
|
-
* @returns {Boolean} 返回true false
|
8
|
-
*/
|
9
|
-
function isExist(dir) {
|
10
|
-
let formatDir = path.normalize(dir);
|
11
|
-
try {
|
12
|
-
fs.accessSync(formatDir, fs.R_OK);
|
13
|
-
return true;
|
14
|
-
} catch (e) {
|
15
|
-
return false;
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
exports.isExist = isExist;
|
20
|
-
|
21
|
-
/**
|
22
|
-
* @description 是否是文件
|
23
|
-
* @param {*} filePath
|
24
|
-
* @returns {Boolean} true 是文件 false 不是文件
|
25
|
-
*/
|
26
|
-
function isFile(filePath) {
|
27
|
-
if (!isExist(filePath)) return false;
|
28
|
-
try {
|
29
|
-
const stat = fs.statSync(filePath);
|
30
|
-
return stat.isFile();
|
31
|
-
} catch (e) {
|
32
|
-
return false;
|
33
|
-
}
|
34
|
-
}
|
35
|
-
exports.isFile = isFile;
|
36
|
-
|
37
|
-
/**
|
38
|
-
* @description 是否是目录
|
39
|
-
* @param {*} filePath
|
40
|
-
* @returns {Boolean} 返回true false
|
41
|
-
*/
|
42
|
-
function isDirectory(filePath) {
|
43
|
-
if (!isExist(filePath)) return false;
|
44
|
-
try {
|
45
|
-
const stat = fs.statSync(filePath);
|
46
|
-
return stat.isDirectory();
|
47
|
-
} catch (e) {
|
48
|
-
return false;
|
49
|
-
}
|
50
|
-
}
|
51
|
-
exports.isDirectory = isDirectory;
|
52
|
-
|
53
|
-
/**
|
54
|
-
* @description 修改指定路径 `p` 的权限模式为给定的 `mode`。这是一个同步版本的文件权限更改方法
|
55
|
-
* 如果成功修改权限,则返回 `true`,否则在发生错误时捕获异常并返回 `false`。
|
56
|
-
* @param {String} p - 要更改权限的文件或目录的绝对路径。
|
57
|
-
* @param {String|Number} mode - 指定的新权限模式,可以是八进制数字表示(如0o755)或字符串形式(如"755")
|
58
|
-
* @return {Boolean} - 根据操作是否成功,返回 `true` 表示成功,`false` 表示失败。
|
59
|
-
*/
|
60
|
-
function chmod(p, mode) {
|
61
|
-
try {
|
62
|
-
fs.chmodSync(p, mode);
|
63
|
-
return true;
|
64
|
-
} catch (e) {
|
65
|
-
return false;
|
66
|
-
}
|
67
|
-
}
|
68
|
-
exports.chmod = chmod;
|
69
|
-
|
70
|
-
/**
|
71
|
-
* @function mkdir
|
72
|
-
* @description 递归创建目录
|
73
|
-
* @param {string} dir - 要创建的目录路径。
|
74
|
-
* @param {string|number} - 默认为 0o777。可以是八进制数字表示或字符串形式。
|
75
|
-
* @returns {boolean} - 返回 `true` 表示成功,`false` 表示失败。
|
76
|
-
*/
|
77
|
-
function mkdir(dir, mode) {
|
78
|
-
if (isExist(dir)) {
|
79
|
-
if (mode) return chmod(dir, mode);
|
80
|
-
return true;
|
81
|
-
}
|
82
|
-
const pp = path.dirname(dir);
|
83
|
-
if (isExist(pp)) {
|
84
|
-
try {
|
85
|
-
fs.mkdirSync(dir, mode);
|
86
|
-
return true;
|
87
|
-
} catch (e) {
|
88
|
-
return false;
|
89
|
-
}
|
90
|
-
}
|
91
|
-
if (mkdir(pp, mode)) return mkdir(dir, mode);
|
92
|
-
return false;
|
93
|
-
}
|
94
|
-
exports.mkdir = mkdir;
|
95
|
-
|
96
|
-
function getdirFiles(dir, prefix = "") {
|
97
|
-
dir = path.normalize(dir);
|
98
|
-
if (!fs.existsSync(dir)) return [];
|
99
|
-
const files = fs.readdirSync(dir);
|
100
|
-
let result = [];
|
101
|
-
files.forEach((item) => {
|
102
|
-
const currentDir = path.join(dir, item);
|
103
|
-
const stat = fs.statSync(currentDir);
|
104
|
-
if (stat.isFile()) {
|
105
|
-
result.push(path.join(prefix, item));
|
106
|
-
} else if (stat.isDirectory()) {
|
107
|
-
const cFiles = getdirFiles(currentDir, path.join(prefix, item));
|
108
|
-
result = result.concat(cFiles);
|
109
|
-
}
|
110
|
-
});
|
111
|
-
return result;
|
112
|
-
}
|
113
|
-
|
114
|
-
exports.getdirFiles = getdirFiles;
|
115
|
-
|
116
|
-
/**
|
117
|
-
* remove dir aync
|
118
|
-
* @param {String} p [path]
|
119
|
-
* @param {Boolean} reserve []
|
120
|
-
* @return {Promise} []
|
121
|
-
*/
|
122
|
-
function rmdir(p, reserve) {
|
123
|
-
if (!isDirectory(p)) return Promise.resolve();
|
124
|
-
return fsReaddir(p).then((files) => {
|
125
|
-
const promises = files.map((item) => {
|
126
|
-
const filepath = path.join(p, item);
|
127
|
-
if (isDirectory(filepath)) return rmdir(filepath, false);
|
128
|
-
return fsUnlink(filepath);
|
129
|
-
});
|
130
|
-
return Promise.all(promises).then(() => {
|
131
|
-
if (!reserve) return fsRmdir(p);
|
132
|
-
});
|
133
|
-
});
|
134
|
-
}
|
135
|
-
exports.rmdir = rmdir;
|