chanjs 1.0.46 → 1.1.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/core/config.js +25 -17
- package/core/helper.js +4 -4
- package/core/lib/cache.js +1 -1
- package/core/lib/controller.js +1 -1
- package/core/lib/extend.js +5 -3
- package/core/lib/index.js +11 -10
- package/core/lib/service.js +1 -2
- package/core/lib/view.js +7 -4
- package/index.js +73 -78
- package/package.json +3 -1
package/core/config.js
CHANGED
@@ -1,33 +1,40 @@
|
|
1
|
-
|
1
|
+
import path from 'path';
|
2
|
+
import { createRequire } from 'module';
|
3
|
+
import { pathToFileURL } from 'url';
|
2
4
|
|
3
5
|
/**
|
4
|
-
* @description
|
6
|
+
* @description 根目录(ESM 兼容写法)
|
5
7
|
*/
|
8
|
+
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
9
|
+
console.log(__dirname)
|
6
10
|
const ROOT_PATH = process.cwd();
|
7
|
-
|
8
|
-
|
11
|
+
|
12
|
+
// 异步读取 package.json(ESM 标准方式)
|
13
|
+
const packageUrl = pathToFileURL(path.join(ROOT_PATH, 'package.json')).href;
|
14
|
+
const { default: pkg } = await import(packageUrl,{ assert: { type: 'json' } });
|
15
|
+
const { version = '1.0.0', author = '明空' } = pkg;
|
9
16
|
|
10
17
|
/**
|
11
18
|
* @description 程序目录
|
12
19
|
*/
|
13
20
|
const APP_PATH = path.join(ROOT_PATH, 'app');
|
14
21
|
|
15
|
-
|
16
|
-
JSON_LIMIT:"100kb",
|
17
|
-
logger
|
22
|
+
const baseConfig = {
|
23
|
+
JSON_LIMIT: "100kb",
|
24
|
+
logger: {
|
18
25
|
level: 'dev',
|
19
26
|
},
|
20
27
|
version,
|
21
28
|
author,
|
22
|
-
env:'dev',
|
23
|
-
template:'default',
|
24
|
-
views:[],
|
25
|
-
static:[{
|
29
|
+
env: 'dev',
|
30
|
+
template: 'default',
|
31
|
+
views: [],
|
32
|
+
static: [{
|
26
33
|
prefix: "/public/",
|
27
34
|
dir: ["app/public"],
|
28
35
|
maxAge: 0,
|
29
36
|
}],
|
30
|
-
database:{
|
37
|
+
database: {
|
31
38
|
client: "mysql2",
|
32
39
|
host: "localhost",
|
33
40
|
port: "3306",
|
@@ -36,10 +43,11 @@ let config = {
|
|
36
43
|
database: "chancms",
|
37
44
|
charset: "utf8mb4",
|
38
45
|
}
|
39
|
-
}
|
46
|
+
};
|
40
47
|
|
41
|
-
|
48
|
+
// 导出配置对象
|
49
|
+
export default {
|
42
50
|
ROOT_PATH,
|
43
|
-
APP_PATH,
|
44
|
-
...
|
45
|
-
}
|
51
|
+
APP_PATH,
|
52
|
+
...baseConfig
|
53
|
+
};
|
package/core/helper.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
|
1
|
+
import knex from 'knex';
|
2
2
|
|
3
3
|
/**
|
4
4
|
* @description 实例化一个类,并将该类的所有方法绑定到一个新的对象上。
|
5
5
|
* @param {Function} className - 需要实例化的类。
|
6
6
|
*@returns {Object} 包含绑定方法的对象。
|
7
7
|
*/
|
8
|
-
|
8
|
+
export const bindClass = function(className) {
|
9
9
|
let obj = {};
|
10
10
|
const cls = new className();
|
11
11
|
Object.getOwnPropertyNames(cls.constructor.prototype).forEach(
|
@@ -22,7 +22,7 @@ exports.bindClass = function(className) {
|
|
22
22
|
}
|
23
23
|
|
24
24
|
|
25
|
-
|
25
|
+
export const createKnex = function(opt) {
|
26
26
|
let config = {
|
27
27
|
host:"localhost",
|
28
28
|
port:"3306",
|
@@ -63,7 +63,7 @@ exports.createKnex = function(opt) {
|
|
63
63
|
* @returns Array
|
64
64
|
* @description 将web模块放到最后加载
|
65
65
|
*/
|
66
|
-
|
66
|
+
export const loadWebToEnd = function(module=[]){
|
67
67
|
const index = module.indexOf('web');
|
68
68
|
if (index !== -1) {
|
69
69
|
const web = module.splice(index, 1);
|
package/core/lib/cache.js
CHANGED
package/core/lib/controller.js
CHANGED
package/core/lib/extend.js
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
import express from "express";
|
2
|
+
export default (app)=>{
|
3
3
|
app.plus = {
|
4
4
|
setStatic:function ({prefix,dir,maxAge}) {
|
5
5
|
app.use(prefix, express.static(dir, { maxAge: maxAge || 0 }));
|
6
6
|
}
|
7
7
|
}
|
8
|
-
}
|
8
|
+
}
|
9
|
+
|
10
|
+
|
package/core/lib/index.js
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
import express from "express";
|
2
|
+
import cookieParser from "cookie-parser";
|
3
|
+
import favicon from "serve-favicon";
|
4
|
+
|
5
|
+
import morgan from "morgan";
|
6
|
+
import path from "path";
|
7
|
+
import view from "./view.js";
|
8
|
+
export default async function (app, config) {
|
9
|
+
const { logger, APP_PATH, cookieKey, statics, JSON_LIMIT, appName, version } =
|
9
10
|
config;
|
10
11
|
|
11
12
|
app.use(morgan(logger.level));
|
@@ -14,8 +15,8 @@ module.exports = async function (app, config) {
|
|
14
15
|
app.use(express.json({ limit: JSON_LIMIT }));
|
15
16
|
app.use(express.urlencoded({ extended: false }));
|
16
17
|
view(app, config);
|
17
|
-
if (
|
18
|
-
|
18
|
+
if (statics.length > 0) {
|
19
|
+
statics.forEach((item) => {
|
19
20
|
const { prefix, dir, maxAge } = item;
|
20
21
|
app.use(prefix, express.static(dir, { maxAge: maxAge || 0 }));
|
21
22
|
});
|
package/core/lib/service.js
CHANGED
package/core/lib/view.js
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
import path from "path";
|
2
|
+
import dayjs from 'dayjs';
|
3
|
+
import { createRequire } from 'module';
|
4
|
+
|
5
|
+
const require = createRequire(import.meta.url);
|
4
6
|
|
7
|
+
const template = require("art-template");
|
5
8
|
// 注册 dateFormat 函数
|
6
9
|
template.defaults.imports.dateFormat = function (date, format) {
|
7
10
|
if (!date) {
|
@@ -20,7 +23,7 @@ template.defaults.imports.dateFormat = function (date, format) {
|
|
20
23
|
return date.format(format);
|
21
24
|
};
|
22
25
|
|
23
|
-
|
26
|
+
export default (app, config) => {
|
24
27
|
const { APP_PATH, views, env } = config;
|
25
28
|
//合并插件中的view
|
26
29
|
const all = [...views, 'app/modules/web/view'];
|
package/index.js
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
import express from "express";
|
2
|
+
import path from "path";
|
3
|
+
import fs from "fs";
|
4
|
+
import cors from "cors";
|
5
|
+
import { pathToFileURL } from 'url'; // 新增顶部导入
|
6
|
+
import config from "./core/config.js";
|
7
|
+
import {bindClass,createKnex,loadWebToEnd} from "./core/helper.js";
|
8
|
+
|
9
|
+
import Controller from "./core/lib/controller.js";
|
10
|
+
|
11
|
+
import Service from "./core/lib/service.js";
|
12
|
+
import cache from './core/lib/cache.js';
|
13
|
+
import core from "./core/lib/index.js";
|
14
|
+
import extend from "./core/lib/extend.js";
|
12
15
|
/**
|
13
16
|
* @description 基于express封装的mvc框架,遵循约定优于配置原则
|
14
17
|
*/
|
@@ -21,45 +24,38 @@ class Chan {
|
|
21
24
|
static Controller = Controller;
|
22
25
|
|
23
26
|
constructor() {
|
24
|
-
this.
|
27
|
+
this.app = express();
|
28
|
+
this.router = express.Router();
|
25
29
|
}
|
26
30
|
|
27
|
-
init() {
|
28
|
-
const startTime = performance.now();
|
29
|
-
this.app = express();
|
31
|
+
async init() {
|
30
32
|
extend(this.app);
|
31
|
-
this.
|
32
|
-
this.
|
33
|
-
this.loadExtends();
|
33
|
+
await this.loadConfig();
|
34
|
+
await this.loadExtends();
|
34
35
|
this.loadCore();
|
35
36
|
this.loadKnex();
|
36
37
|
this.loadCors();
|
37
|
-
// 记录结束时间
|
38
|
-
const endTime = performance.now();
|
39
|
-
console.log(`Chanjs init: ${endTime - startTime} ms`);
|
40
38
|
}
|
41
39
|
|
42
40
|
|
43
|
-
|
44
|
-
loadConfig() {
|
41
|
+
async loadConfig() {
|
45
42
|
const configPath = path.join(Chan.config.APP_PATH, "config/index.js");
|
46
43
|
if (fs.existsSync(configPath)) {
|
47
|
-
const
|
48
|
-
|
44
|
+
const configUrl = pathToFileURL(configPath).href; // 新增转换
|
45
|
+
const configModule = await import(configUrl); // 使用 URL 导入
|
46
|
+
Chan.config = { ...Chan.config, ...configModule.default }; // 注意 default
|
49
47
|
}
|
50
48
|
}
|
51
49
|
|
52
|
-
loadExtends() {
|
50
|
+
async loadExtends() {
|
53
51
|
const extendPath = path.join(Chan.config.APP_PATH, "extend");
|
54
52
|
if (fs.existsSync(extendPath)) {
|
55
|
-
|
56
|
-
|
57
|
-
.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
const fileName = file.replace(".js", "");
|
62
|
-
Chan.helper[fileName] = helper;
|
53
|
+
const files = fs.readdirSync(extendPath).filter(file => file.endsWith(".js"));
|
54
|
+
for (const file of files) {
|
55
|
+
const filePath = path.join(extendPath, file);
|
56
|
+
const fileUrl = pathToFileURL(filePath).href; // 转换路径
|
57
|
+
const helperModule = await import(fileUrl); // 使用 URL 导入
|
58
|
+
Chan.helper[file.replace(".js", "")] = helperModule?.default || helperModule; // 注意 default
|
63
59
|
}
|
64
60
|
}
|
65
61
|
}
|
@@ -90,14 +86,10 @@ class Chan {
|
|
90
86
|
cb && cb();
|
91
87
|
}
|
92
88
|
//启动
|
93
|
-
start(cb) {
|
94
|
-
|
95
|
-
this.loadModules();
|
96
|
-
this.
|
97
|
-
this.loadCommonRouter();
|
98
|
-
// 记录结束时间
|
99
|
-
const endTime = performance.now();
|
100
|
-
console.log(`Chanjs load modules: ${endTime - startTime} ms`);
|
89
|
+
async start(cb) {
|
90
|
+
await this.loadPlugins();
|
91
|
+
await this.loadModules();
|
92
|
+
await this.loadCommonRouter();
|
101
93
|
cb && cb();
|
102
94
|
}
|
103
95
|
|
@@ -107,63 +99,69 @@ class Chan {
|
|
107
99
|
}
|
108
100
|
|
109
101
|
// 加载插件
|
110
|
-
loadPlugins() {
|
111
|
-
|
102
|
+
async loadPlugins() {
|
103
|
+
await this.loadModules("plugins");
|
112
104
|
}
|
113
105
|
|
114
106
|
/**
|
115
107
|
* @description 模块加载入口(路由&控制器& 服务)
|
116
108
|
*/
|
117
|
-
loadModules(modules = "modules") {
|
109
|
+
async loadModules(modules = "modules") {
|
118
110
|
const configPath = path.join(Chan.config.APP_PATH, modules);
|
111
|
+
console.log('configPath',configPath);
|
119
112
|
if (fs.existsSync(configPath)) {
|
120
|
-
//模块名称
|
121
113
|
const dirs = loadWebToEnd(Chan.config[modules]);
|
114
|
+
console.log('dirs',dirs);
|
122
115
|
Chan[modules] = {};
|
116
|
+
|
123
117
|
// 先加载所有服务
|
124
|
-
|
118
|
+
for (const item of dirs) {
|
125
119
|
Chan[modules][item] = {
|
126
120
|
service: {},
|
127
121
|
controller: {},
|
128
122
|
};
|
129
|
-
this.loadServices(modules, item);
|
130
|
-
}
|
131
|
-
|
123
|
+
await this.loadServices(modules, item); // 确保每个模块的服务加载完成
|
124
|
+
}
|
125
|
+
|
132
126
|
// 加载控制器和路由
|
133
|
-
|
134
|
-
this.loadModule(modules, item);
|
135
|
-
}
|
127
|
+
for (const item of dirs) {
|
128
|
+
await this.loadModule(modules, item); // 确保每个模块的加载完成
|
129
|
+
}
|
136
130
|
}
|
137
131
|
}
|
132
|
+
|
138
133
|
|
139
134
|
/**
|
140
135
|
* @description 加载模块,包括 controller service router
|
141
136
|
* @param {String} moduleName 模块名称
|
142
137
|
*/
|
143
|
-
loadModule(modules, moduleName) {
|
144
|
-
this.loadControllers(modules, moduleName);
|
145
|
-
this.loadRoutes(modules, moduleName);
|
138
|
+
async loadModule(modules, moduleName) {
|
139
|
+
await this.loadControllers(modules, moduleName); // 确保控制器加载完成
|
140
|
+
await this.loadRoutes(modules, moduleName); // 然后加载路由
|
146
141
|
}
|
147
142
|
|
148
|
-
loadFiles(modules, moduleName, type) {
|
143
|
+
async loadFiles(modules, moduleName, type) {
|
149
144
|
const dir = path.join(Chan.config.APP_PATH, modules, moduleName, type);
|
150
145
|
if (fs.existsSync(dir)) {
|
151
146
|
const files = fs.readdirSync(dir).filter(file => file.endsWith(".js"));
|
152
|
-
|
153
|
-
const
|
147
|
+
for (const file of files) { // 使用 for...of 确保异步操作顺序
|
148
|
+
const filePath = path.join(dir, file);
|
149
|
+
const fileUrl = pathToFileURL(filePath).href;
|
150
|
+
const module = await import(fileUrl);
|
154
151
|
const name = file.replace(".js", "");
|
155
|
-
Chan[modules][moduleName][type][name] = { ...bindClass(module) };
|
156
|
-
}
|
152
|
+
Chan[modules][moduleName][type][name] = { ...bindClass(module.default) };
|
153
|
+
}
|
157
154
|
}
|
158
155
|
}
|
156
|
+
|
159
157
|
|
160
158
|
/**
|
161
159
|
* @description 扫描模块下所有service
|
162
160
|
* @param {*} moduleDir 模块路径
|
163
161
|
* @param {*} moduleName 模块名称
|
164
162
|
*/
|
165
|
-
loadServices(modules, moduleName) {
|
166
|
-
|
163
|
+
async loadServices(modules, moduleName) {
|
164
|
+
await this.loadFiles(modules, moduleName, "service");
|
167
165
|
}
|
168
166
|
|
169
167
|
/**
|
@@ -171,8 +169,8 @@ class Chan {
|
|
171
169
|
* @param {*} moduleDir 模块路径
|
172
170
|
* @param {*} moduleName 模块名称
|
173
171
|
*/
|
174
|
-
loadControllers(modules, moduleName) {
|
175
|
-
this.loadFiles(modules, moduleName, "controller");
|
172
|
+
async loadControllers(modules, moduleName) {
|
173
|
+
await this.loadFiles(modules, moduleName, "controller");
|
176
174
|
}
|
177
175
|
|
178
176
|
/**
|
@@ -180,26 +178,23 @@ class Chan {
|
|
180
178
|
* @param {*} moduleDir 模块路径
|
181
179
|
* @param {*} moduleName 模块名称
|
182
180
|
*/
|
183
|
-
loadRoutes(modules, moduleName) {
|
184
|
-
const routersDir = path.join(
|
185
|
-
Chan.config.APP_PATH,
|
186
|
-
modules,
|
187
|
-
moduleName,
|
188
|
-
"router.js"
|
189
|
-
);
|
181
|
+
async loadRoutes(modules, moduleName) {
|
182
|
+
const routersDir = path.join(Chan.config.APP_PATH, modules, moduleName, "router.js");
|
190
183
|
if (fs.existsSync(routersDir)) {
|
191
|
-
const
|
192
|
-
routes
|
184
|
+
const routeUrl = pathToFileURL(routersDir).href; // 转换路径
|
185
|
+
const routes = await import(routeUrl); // 使用 URL 导入
|
186
|
+
routes.default({ router: this.router, modules: Chan[modules], app: this.app });
|
193
187
|
}
|
194
188
|
}
|
195
189
|
|
196
190
|
//通用路由,加载错误处理和500路由和爬虫处理
|
197
|
-
loadCommonRouter() {
|
191
|
+
async loadCommonRouter() {
|
198
192
|
try {
|
199
193
|
const baseRouterPath = path.join(Chan.config.APP_PATH, "router.js");
|
200
194
|
if (fs.existsSync(baseRouterPath)) {
|
201
|
-
const
|
202
|
-
_router
|
195
|
+
const routerUrl = pathToFileURL(baseRouterPath).href; // 转换路径
|
196
|
+
const _router = await import(routerUrl); // 使用 URL 导入
|
197
|
+
_router.default(this.app, this.router, Chan.config); // 注意 default
|
203
198
|
}
|
204
199
|
} catch (error) {
|
205
200
|
console.log(error);
|
@@ -214,4 +209,4 @@ class Chan {
|
|
214
209
|
}
|
215
210
|
}
|
216
211
|
global.Chan = Chan;
|
217
|
-
|
212
|
+
export default Chan;
|
package/package.json
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
{
|
2
|
+
"type": "module",
|
2
3
|
"name": "chanjs",
|
3
|
-
"version": "1.0
|
4
|
+
"version": "1.1.0",
|
4
5
|
"description": "chanjs基于express 纯js研发的轻量级mvc框架。",
|
5
6
|
"main": "index.js",
|
6
7
|
"module": "index.js",
|
@@ -12,6 +13,7 @@
|
|
12
13
|
"chancms",
|
13
14
|
"nodejs"
|
14
15
|
],
|
16
|
+
"engines": { "node": ">=20.0.0" },
|
15
17
|
"author": "明空",
|
16
18
|
"license": "ISC",
|
17
19
|
"dependencies": {
|