chanjs 1.0.27 → 1.0.29
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 -90
- package/core/lib/config/config.js +5 -2
- 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/publish.bat +4 -0
- 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,36 @@
|
|
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
|
-
//加载核心(日志、favicon 图标、cookie、json、url、模板引擎、静态资源)
|
40
29
|
this.loadCore();
|
41
|
-
//加载实例化数据库
|
42
30
|
this.loadKnex();
|
43
|
-
//解决跨域
|
44
31
|
this.loadCors();
|
45
32
|
}
|
46
33
|
|
47
|
-
// 加载配置
|
48
34
|
loadConfig() {
|
49
35
|
const configPath = path.join(Chan.config.APP_PATH, "config/index.js");
|
50
36
|
if (fs.existsSync(configPath)) {
|
@@ -53,7 +39,6 @@ class Chan {
|
|
53
39
|
}
|
54
40
|
}
|
55
41
|
|
56
|
-
// 加载扩展
|
57
42
|
loadExtends() {
|
58
43
|
const extendPath = path.join(Chan.config.APP_PATH, "extend");
|
59
44
|
if (fs.existsSync(extendPath)) {
|
@@ -69,65 +54,35 @@ class Chan {
|
|
69
54
|
}
|
70
55
|
}
|
71
56
|
|
57
|
+
/**
|
58
|
+
* @description app核心模块:日志、favicon 图标、cookie、json、url、模板引擎、静态资源
|
59
|
+
*/
|
60
|
+
loadCore() {
|
61
|
+
core(this.app, Chan.config);
|
62
|
+
}
|
63
|
+
|
72
64
|
//数据库操作
|
73
65
|
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);
|
66
|
+
if(Chan.config?.db?.length > 0){
|
67
|
+
Chan.config.db.map((item,index) => {
|
68
|
+
if(index ==0){
|
69
|
+
Chan.knex = createKnex(item);
|
70
|
+
}else{
|
71
|
+
Chan[`knex${index}`] = createKnex(item);
|
72
|
+
}
|
73
|
+
})
|
74
|
+
}
|
115
75
|
}
|
116
76
|
|
117
77
|
//开始启动
|
118
78
|
beforeStart(cb) {
|
119
|
-
|
120
79
|
cb && cb();
|
121
80
|
}
|
122
81
|
//启动
|
123
82
|
start(cb) {
|
124
|
-
//加载插件
|
125
83
|
this.loadPlugins();
|
126
|
-
//加载模块
|
127
84
|
this.loadModules();
|
128
|
-
//加载通用路由
|
129
85
|
this.loadCommonRouter();
|
130
|
-
// 初始化一些配置
|
131
86
|
cb && cb();
|
132
87
|
}
|
133
88
|
|
@@ -141,25 +96,15 @@ class Chan {
|
|
141
96
|
this.loadModules("plugins");
|
142
97
|
}
|
143
98
|
|
144
|
-
/**
|
145
|
-
* @description app核心模块:日志、favicon 图标、cookie、json、url、模板引擎、静态资源
|
146
|
-
*/
|
147
|
-
loadCore() {
|
148
|
-
core(this.app, Chan.config);
|
149
|
-
}
|
150
|
-
|
151
99
|
/**
|
152
100
|
* @description 模块加载入口(路由&控制器& 服务)
|
153
101
|
*/
|
154
102
|
loadModules(modules = "modules") {
|
155
103
|
const configPath = path.join(Chan.config.APP_PATH, modules);
|
156
104
|
if (fs.existsSync(configPath)) {
|
157
|
-
|
158
|
-
|
159
|
-
.filter((dirent) => dirent.isDirectory())
|
160
|
-
.map((dirent) => dirent.name);
|
105
|
+
//模块名称
|
106
|
+
const dirs = loadWebToEnd(Chan.config[modules]);
|
161
107
|
Chan[modules] = {};
|
162
|
-
|
163
108
|
// 先加载所有服务
|
164
109
|
dirs.forEach((item) => {
|
165
110
|
Chan[modules][item] = {
|
@@ -173,9 +118,6 @@ class Chan {
|
|
173
118
|
dirs.forEach((item) => {
|
174
119
|
this.loadModule(modules, item);
|
175
120
|
});
|
176
|
-
|
177
|
-
//执行路由
|
178
|
-
// this.app.use(this.router);
|
179
121
|
}
|
180
122
|
}
|
181
123
|
|
@@ -209,8 +151,7 @@ class Chan {
|
|
209
151
|
const Service = require(path.join(servicesDir, file));
|
210
152
|
const serviceName = file.replace(".js", "");
|
211
153
|
//模块文件夹-模块文件名-服务-方法
|
212
|
-
Chan[modules][moduleName].service[serviceName] = {};
|
213
|
-
Chan[modules][moduleName].service[serviceName] = bindClass(Service);
|
154
|
+
Chan[modules][moduleName].service[serviceName] = {...bindClass(Service)};
|
214
155
|
}
|
215
156
|
}
|
216
157
|
}
|
@@ -235,9 +176,7 @@ class Chan {
|
|
235
176
|
file = controllers[i];
|
236
177
|
const controller = require(path.join(controllersDir, file));
|
237
178
|
const controllerName = file.replace(".js", "");
|
238
|
-
Chan[modules][moduleName].controller[controllerName] = {};
|
239
|
-
Chan[modules][moduleName].controller[controllerName] =
|
240
|
-
bindClass(controller);
|
179
|
+
Chan[modules][moduleName].controller[controllerName] = {...bindClass(controller)};
|
241
180
|
}
|
242
181
|
}
|
243
182
|
}
|
@@ -4,6 +4,8 @@ const path = require('path');
|
|
4
4
|
* @description 根目录
|
5
5
|
*/
|
6
6
|
const ROOT_PATH = process.cwd();
|
7
|
+
// 读取package.json文件
|
8
|
+
const {version='1.0.0',author='明空'} = require(path.join(ROOT_PATH, 'package.json'));
|
7
9
|
|
8
10
|
/**
|
9
11
|
* @description 程序目录
|
@@ -12,10 +14,11 @@ const APP_PATH = path.join(ROOT_PATH, 'app');
|
|
12
14
|
|
13
15
|
let config = {
|
14
16
|
JSON_LIMIT:"100kb",
|
15
|
-
SqlDebug:true,
|
16
17
|
logger : {
|
17
18
|
level: 'dev',
|
18
19
|
},
|
20
|
+
version,
|
21
|
+
author,
|
19
22
|
env:'dev',
|
20
23
|
template:'default',
|
21
24
|
views:[], //模板路径
|
@@ -30,7 +33,7 @@ let config = {
|
|
30
33
|
port: "3306",
|
31
34
|
user: "root",
|
32
35
|
password: "123456",
|
33
|
-
database: "
|
36
|
+
database: "chancms",
|
34
37
|
charset: "utf8mb4",
|
35
38
|
}
|
36
39
|
}
|
@@ -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
package/publish.bat
ADDED
@@ -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;
|