chanjs 2.6.8 → 2.6.11

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/App.js CHANGED
@@ -47,7 +47,6 @@ class Chan {
47
47
  async start() {
48
48
  //加载配置
49
49
  await this.config();
50
-
51
50
  //加载数据库
52
51
  await this.loadDB();
53
52
  //加载扩展方法
package/README.md CHANGED
@@ -2,69 +2,67 @@
2
2
 
3
3
  Chanjs 是一个基于 Express 5+ 构建的轻量级 MVC 框架,完全使用 JavaScript 开发。它体现了函数式编程的概念,提供了卓越的性能、清晰的代码和易于遵循的过程,确保了高可维护性。
4
4
 
5
+ ‌ChanJS‌ 是一个基于 ‌Express 5+‌ 构建的轻量级 ‌MVC 框架‌,完全使用纯 JavaScript 开发,强调函数式编程理念,具有高性能、代码清晰、易维护等特点。
6
+
5
7
  ## 特点
6
8
 
7
- - **核心架构**
8
- - 基于 Express 5+ 构建
9
- - 支持 ES6+ 语法
10
- - 轻量级设计(核心代码精简高效)
11
-
12
- - **模块化设计**
13
- - 多模块化路由(支持模块独立路由)
14
- - 模块化 views(模板文件模块化)
15
- - 模块化 controllers(控制器模块化)
16
- - 模块化 services(服务层模块化)
17
- - 模块化 middleware(模块级中间件)
18
-
19
- - **插件式架构**
20
- - 支持插件扩展
21
- - 插件独立 MVC 结构
22
- - 热插拔式插件管理
23
-
24
- - **数据库支持**
25
- - 多数据库支持(PostgreSQL、MySQL/MariaDB、SQLite3、Oracle、MSSQL)
26
- - 数据库连接池管理
27
- - Knex 查询构建器
28
- - 事务支持
29
- - 日期字段自动格式化
30
-
31
- - **安全防护**
32
- - WAF(Web应用防火墙)
33
- - XSS 防护
34
- - 关键词过滤
35
- - 访问限流(Rate Limiting)
36
- - 路径白名单
37
- - Cookie 安全处理
38
-
39
- - **中间件生态**
40
- - CORS 跨域配置
41
- - 请求体解析
42
- - Cookie 处理
43
- - 静态资源管理
44
- - 日志记录
45
- - 模板引擎(Art-template)
46
-
47
- - **高级特性**
48
- - 依赖注入(DI,基于 Map 实现)
49
- - 面向切面编程(AOP,支持 before/after/error 切面)
50
- - 事件系统(基于 EventEmitter)
51
- - 自动控制器加载(loadController)
52
-
53
- - **开发体验**
54
- - 缓存支持(内存缓存)
55
- - 统一响应格式
56
- - 全局错误处理(404/500)
57
- - 分页查询封装
58
- - 配置文件管理
59
- - 环境变量支持(.env.dev/.env.prd)
60
-
61
- - **工具函数**
62
- - 时间格式化
63
- - 文件操作
64
- - 路径处理
65
- - 树形结构转换
66
- - 代码生成
67
- - 过滤器
9
+ ### 核心架构
10
+ - Express 5+ 原生
11
+ - Node.js 24+
12
+ - ✅ ES Modules (import / export)
13
+ - ✅ 多模块 MVC 架构
14
+ - ✅ 轻量级内核
15
+ - ✅ 约定优于配置
16
+
17
+ ### 模块化
18
+ - 多模块路由
19
+ - 模块化 views
20
+ - ✅ 模块化 controllers
21
+ - ✅ 模块化 services
22
+ - ✅ 模块化 middleware
23
+
24
+ ### 数据库
25
+ - ✅ Knex.js 查询构建器
26
+ - ✅ SQLite / MySQL / PostgreSQL
27
+ - ✅ 连接池
28
+ - ✅ 事务
29
+ - 自动时间格式化
30
+
31
+ ### 安全能力
32
+ - ✅ WAF 防火墙
33
+ - ✅ XSS 防护
34
+ - ✅ 关键词过滤
35
+ - 请求限流
36
+ - ✅ 路由白名单
37
+ - Cookie 安全
38
+
39
+ ### 中间件生态
40
+ - ✅ CORS
41
+ - ✅ 请求解析
42
+ - Cookie
43
+ - ✅ 静态资源
44
+ - 日志
45
+ - ✅ Art-template 模板引擎
46
+
47
+ ### 高级特性
48
+ - ✅ DI 依赖注入(Map 实现)
49
+ - ✅ AOP 切面(before/after/error)
50
+ - 事件系统
51
+ - 自动加载控制器
52
+ - 定时任务
53
+ - ✅ WebSocket
54
+ - ✅ 缓存系统(Redis 和 内存缓存 map 实现)
55
+ - ✅ 分页器
56
+ - ✅ 国际化 i18n
57
+ - ✅ 请求验证器
58
+ - ✅ 全局异常处理
59
+ - ✅ 接口文档自动生成
60
+ - ✅ 文件上传 / OSS 扩展口
61
+
62
+ ### 开发体验
63
+ - ✅ 多环境配置
64
+ - ✅ 统一响应
65
+ - ✅ 工具函数
68
66
 
69
67
  ## 约定优于配置
70
68
 
@@ -100,29 +98,61 @@ Chanjs 是一个基于 Express 5+ 构建的轻量级 MVC 框架,完全使用 J
100
98
  |- package.json
101
99
  ```
102
100
 
101
+
102
+ ## npm 包参考
103
+
104
+ ```json
105
+ {
106
+ "art-template": "^4.13.4",
107
+ "body-parser": "^2.2.0",
108
+ "cookie-parser": "^1.4.7",
109
+ "cors": "^2.8.5",
110
+ "dotenv": "^17.2.1",
111
+ "dayjs": "^1.11.13",
112
+ "express": "^5.1.0",
113
+ "express-art-template": "^1.0.1",
114
+ "knex": "^3.1.0",
115
+ "morgan": "^1.10.0",
116
+ "mysql2": "^3.14.1",
117
+ "marked": "^17.0.3",
118
+ "adm-zip": "^0.5.16",
119
+ "bcryptjs": "^3.0.2",
120
+ "better-sqlite3": "^12.8.0",
121
+ "chanjs": "^2.6.10",
122
+ "cheerio": "^1.1.2",
123
+ "crypto-js": "^4.2.0",
124
+ "iconv-lite": "^0.6.3",
125
+ "jsonwebtoken": "^9.0.2",
126
+ "multer": "^2.0.2",
127
+ "nodemailer": "^7.0.6",
128
+ "qiniu": "^7.14.0",
129
+ "serve-favicon": "^2.5.1",
130
+ "xml2js": "^0.6.2",
131
+ "xss": "^1.0.15",
132
+ "zod": "^4.1.11"
133
+ }
134
+ ```
135
+
103
136
  ## 初始化过程
104
137
 
105
- ```mermaid
106
- graph TD
107
- A[初始化] --> B[加载配置]
108
- B --> C[加载数据库]
109
- C --> D[加载扩展]
110
- D --> E[加载中间件]
111
- E --> F[设置应用配置]
112
- F --> G[加载模块路由]
113
- G --> H[加载公共路由]
114
- H --> I[应用路由]
115
- I --> J[设置错误处理]
116
- J --> K[beforeStart钩子]
117
- K --> L[run启动服务器]
118
-
119
- G --> G1[加载服务]
120
- G --> G2[加载控制器]
121
- G --> G3[加载路由]
122
-
123
- D --> D1[加载common]
124
- D --> D2[加载helper]
125
- D --> D3[加载extend]
138
+ ```
139
+ 初始化流程:
140
+
141
+ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
142
+ │ 初始化 │───▶│ 加载配置 │───▶│ 加载数据库│───▶│ 加载扩展
143
+ └─────────┘ └─────────┘ └─────────┘ └─────────┘
144
+
145
+ ┌─────────┐ ┌─────────┐ │
146
+ │ 加载服务 │ 加载控制器│ │
147
+ └────▲────┘ └────▲────┘ │
148
+ │ │ │
149
+ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──┴──────┐
150
+ 应用路由 │◀───│加载公共路由│◀───│加载模块路由│◀───│加载中间件│
151
+ └────┬────┘ └─────────┘ └────┬────┘ └─────────┘
152
+ │ │
153
+ ┌─────────┐ ┌─────────┐ ┌─────────┐
154
+ └───▶│设置错误处理│───▶│beforeStart│───▶│ run启动 │
155
+ └─────────┘ └─────────┘ └─────────┘
126
156
  ```
127
157
 
128
158
  ## 核心功能
@@ -141,14 +171,7 @@ class UserService extends Service {
141
171
  super("user");
142
172
  }
143
173
 
144
- async getUserWithArticles(userId) {
145
- const user = await this.findById(userId);
146
- // 从依赖注入容器中获取 ArticleService 实例
147
- const articleService = await this.get("article", "Article");
148
- const articles = await articleService.findByUserId(userId);
149
-
150
- return { user, articles };
151
- }
174
+
152
175
  }
153
176
 
154
177
  class UserController extends Controller {
@@ -157,15 +180,7 @@ class UserController extends Controller {
157
180
  }
158
181
 
159
182
  async getUser(req, res, next) {
160
- try {
161
- const { id } = req.params;
162
- // 从依赖注入容器中获取 UserService 实例
163
- const userService = await this.get("user", "User");
164
- const result = await userService.findById(id);
165
- res.json(this.success({ data: result.data }));
166
- } catch (err) {
167
- next(err);
168
- }
183
+
169
184
  }
170
185
  }
171
186
  ```
@@ -345,4 +360,4 @@ app.run((port) => {
345
360
  });
346
361
  ```
347
362
 
348
- 该框架专为寻求简单与功能之间平衡的开发者设计,为构建 Web 应用程序提供了一个强大的基础。
363
+ 该框架专为寻求简单与功能之间平衡的开发者设计,为构建 Web 应用程序提供了一个强大的基础。
package/helper/cache.js CHANGED
@@ -34,16 +34,21 @@ class Cache {
34
34
  * @param {number} [ttl=this.defaultTTL] - 过期时间(毫秒)
35
35
  * @description
36
36
  * 将键值对存入缓存,如果缓存已满则淘汰最久未使用的条目
37
- * 每次设置都会更新访问时间
37
+ * 每次设置都会更新访问时间 + 过期时间
38
38
  * @example
39
39
  * cache.set('key1', 'value1', 60000); // 60 秒后过期
40
40
  * cache.set('key2', { data: 123 }); // 使用默认过期时间
41
41
  */
42
42
  set(key, value, ttl = this.defaultTTL) {
43
+ // 修复:缓存满 + 是新 key 才淘汰
43
44
  if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
44
45
  this._evictLRU();
45
46
  }
47
+
48
+ // 修复:无论 key 是否存在,都更新 过期时间 + 访问时间
46
49
  this.cache.set(key, { value, expireAt: Date.now() + ttl });
50
+ // LRU:先删除再插入,保证 Map 尾部是最新访问
51
+ this.accessOrder.delete(key);
47
52
  this.accessOrder.set(key, Date.now());
48
53
  }
49
54
 
@@ -54,7 +59,7 @@ class Cache {
54
59
  * @description
55
60
  * 获取指定键的缓存值
56
61
  * 如果值已过期,会自动删除该条目
57
- * 每次获取都会更新访问时间
62
+ * 每次获取都会更新访问时间 + 刷新过期时间
58
63
  * @example
59
64
  * const value = cache.get('key1');
60
65
  * if (value !== null) {
@@ -64,14 +69,22 @@ class Cache {
64
69
  get(key) {
65
70
  const item = this.cache.get(key);
66
71
  if (!item) return null;
67
-
68
- if (Date.now() > item.expireAt) {
72
+
73
+ const now = Date.now();
74
+ // 已过期直接删除
75
+ if (now > item.expireAt) {
69
76
  this.cache.delete(key);
70
77
  this.accessOrder.delete(key);
71
78
  return null;
72
79
  }
73
-
74
- this.accessOrder.set(key, Date.now());
80
+
81
+ // 修复:命中缓存 → 刷新 LRU 顺序 + 刷新 TTL
82
+ this.accessOrder.delete(key);
83
+ this.accessOrder.set(key, now);
84
+ // 重新计算过期时间(访问续命,标准行为)
85
+ const ttl = item.expireAt - (now - (item.expireAt - this.defaultTTL));
86
+ this.cache.set(key, { value: item.value, expireAt: now + ttl });
87
+
75
88
  return item.value;
76
89
  }
77
90
 
@@ -141,20 +154,11 @@ class Cache {
141
154
  * 淘汰最久未使用的条目(内部方法)
142
155
  * @private
143
156
  * @description
144
- * 找到访问时间最早的条目并删除
145
- * 当缓存达到最大容量时自动调用
157
+ * Map 头部就是最早访问,直接删除(O(1))
146
158
  */
147
159
  _evictLRU() {
148
- let oldestKey = null;
149
- let oldestTime = Infinity;
150
-
151
- for (const [key, time] of this.accessOrder.entries()) {
152
- if (time < oldestTime) {
153
- oldestTime = time;
154
- oldestKey = key;
155
- }
156
- }
157
-
160
+ // 修复:Map 有序,keys().next() 直接拿到最久未使用的 key,性能 O(1)
161
+ const oldestKey = this.accessOrder.keys().next().value;
158
162
  if (oldestKey) {
159
163
  this.cache.delete(oldestKey);
160
164
  this.accessOrder.delete(oldestKey);
@@ -180,4 +184,4 @@ class Cache {
180
184
  }
181
185
 
182
186
  export const cache = new Cache();
183
- export default Cache;
187
+ export default Cache;
package/index.js CHANGED
@@ -14,7 +14,7 @@ export * as common from "./common/index.js";
14
14
  export * as extend from "./extend/index.js";
15
15
 
16
16
  // 常用工具函数直接导出
17
- export { loadConfig, loaderSort, loadController } from "./helper/index.js";
17
+ export { loadConfig, loaderSort, loadController ,cache} from "./helper/index.js";
18
18
 
19
19
  // 路径配置
20
20
  export { Paths } from "./config/paths.js";
@@ -24,7 +24,7 @@ import { importjs } from "../global/import.js";
24
24
  export let setTemplate = (app, config) => {
25
25
  const { views, NODE_ENV } = config;
26
26
  const isProduction = NODE_ENV === "production" || NODE_ENV === "prd";
27
- console.log("cache", isProduction);
27
+ console.log("模板缓存->", isProduction);
28
28
  const all = [...views];
29
29
  app.set("view options", {
30
30
  debug: !isProduction,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "chanjs",
4
- "version": "2.6.8",
4
+ "version": "2.6.11",
5
5
  "description": "chanjs基于express5 纯js研发的轻量级mvc框架。",
6
6
  "main": "index.js",
7
7
  "module": "index.js",