chanjs 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # <center>Chan.js mvc框架</center>
2
+
3
+ Chan.js 基于express 纯js研发的轻量级mvc框架。基于函数式编程思想,性能优越,代码清晰,流程易读,可持续维护高。
4
+
5
+ ## 特性
6
+
7
+ - 基于express
8
+ - 支持es6语法
9
+ - 模块化
10
+ - 支持多模块路由
11
+ - 支持多模块视图
12
+ - 支持多模块控制器
13
+ - 支持多模块服务
14
+ - 插件化
15
+ - 轻量级(核心代码300行内)
16
+ - 长期维护
17
+
18
+ ## 规范 遵循约定优于配置
19
+
20
+ ```code
21
+ |- app
22
+ |- config 配置
23
+ |- module 模块1
24
+ |- module1 模块1
25
+ |- controller 控制器
26
+ |- service 服务模型
27
+ |- view 视图模板
28
+ |- router.js 路由
29
+ |- module2 模块2
30
+ |- controller 控制器
31
+ |- service 服务模型
32
+ |- view 视图模板
33
+ |- router.js路由
34
+ |- extend 扩展
35
+ |- middleware 中间件
36
+ |- plugin 插件
37
+ |- public 静态文件
38
+ |- index.js
39
+ ```
40
+
41
+ ### 初始化流程
42
+
43
+ - 初始化
44
+ - 加载配置
45
+ - 加载模块
46
+ - 加载service
47
+ - 加载controller
48
+ - 加载router
49
+ - 加载extend
50
+ - 加载plugin
51
+ - beforeStart() 挂在从数据库获取的配置合并到配置文件中
52
+ - run() 启动服务
53
+
54
+ ### 官网
55
+
56
+ 网址:https://www.chancms.top
57
+
58
+ ### 运行
59
+
60
+ ```javascript
61
+ const Chan = require('chanjs');
62
+ const app = new Chan();
63
+ app.run();
64
+ ```
@@ -0,0 +1,64 @@
1
+ const path = require("path");
2
+
3
+ const config = {};
4
+ config.version = "v2.0.5";
5
+ config.appName = "禅悦cms";
6
+ config.port = '81';
7
+ config.versionTime = "2023-12-08";
8
+ config.author = "明空";
9
+
10
+ config.appRoot = path.join(__dirname, "../");
11
+
12
+
13
+ // cookie sign key
14
+ config.keys = "chanyue-cms_202301032044";
15
+
16
+ config.token = {
17
+ KEY: "chanyue-cms", // JSON WEB TOKEN KEY
18
+ TIME: "1d", // 失效时间 10
19
+ };
20
+
21
+ config.secret = {
22
+ key: "chanyue-cms", // md5 加盐
23
+ };
24
+
25
+ // 关闭csrf
26
+ config.security = {
27
+ csrf: {
28
+ enable: false,
29
+ },
30
+ };
31
+
32
+ // 配置上传
33
+ config.multipart = {
34
+ fileSize: "50mb",
35
+ mode: "stream",
36
+ whitelist: [
37
+ ".jpg",
38
+ ".jpeg",
39
+ ".png",
40
+ ".gif",
41
+ ".zip",
42
+ ".gz",
43
+ ".tgz",
44
+ ".gzip",
45
+ ".mp3",
46
+ ".mp4",
47
+ ".avi",
48
+ ],
49
+ fileExtensions: [".pdf", ".txt"], // 扩展几种上传的文件格式
50
+ };
51
+
52
+ // 模板配置
53
+ config.static = {
54
+ prefix: "/public/",
55
+ dynamic: true, // 如果当前访问的静态资源没有缓存,则缓存静态文件,和`preload`配合使用;
56
+ dir: ["app/public"],
57
+ maxAge: 0, // in prod env, 0 in other envs
58
+ buffer: false, // in prod env, false in other envs
59
+ preload: false,
60
+ };
61
+
62
+ config.views = [path.join(config.appRoot, `plugin/open/view`)];
63
+
64
+ module.exports = config;
@@ -0,0 +1,12 @@
1
+ const config = {
2
+ mysql:{
3
+ host: 'localhost',
4
+ user: 'root',
5
+ password: '123456',
6
+ port: 3306,
7
+ database: ''
8
+ }
9
+ }
10
+
11
+
12
+ module.exports = config;
@@ -0,0 +1,12 @@
1
+ const config = {
2
+ mysql:{
3
+ host: 'localhost',
4
+ user: 'root',
5
+ password: '123456',
6
+ port: 3306,
7
+ database: ''
8
+ }
9
+ }
10
+
11
+
12
+ module.exports = config;
@@ -0,0 +1,9 @@
1
+ const dev = require('./config.dev')
2
+ const prd = require('./config.prd')
3
+ const base = require('./config.base')
4
+ const config = {
5
+ 'dev':dev,
6
+ 'prd':prd
7
+ }
8
+ const env = process.env.NODE_ENV || 'dev'
9
+ module.exports = Object.assign({}, base, config[env]) // 合并配置
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ log: (str) => {
3
+ console.log(str);
4
+ },
5
+ };
@@ -0,0 +1,39 @@
1
+ const Tea = require("../../../../core/chan");
2
+ const { service } = Tea.modules.api;
3
+
4
+ /**
5
+ *
6
+ * @param {*} req
7
+ * @param {*} res
8
+ * @param {*} next
9
+ */
10
+ function index(req, res, next) {
11
+ try {
12
+ let data = service.home.index();
13
+ res.send(data);
14
+ } catch (error) {
15
+ console.log(error);
16
+ next(error);
17
+ }
18
+ }
19
+
20
+
21
+ /**
22
+ *
23
+ * @param {*} req
24
+ * @param {*} res
25
+ * @param {*} next
26
+ */
27
+ function list(req, res, next) {
28
+ try {
29
+ let data = service.home.list();
30
+ res.send(data);
31
+ } catch (error) {
32
+ console.log(error);
33
+ next(error);
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ index,list
39
+ };
@@ -0,0 +1,8 @@
1
+ module.exports = (app) => {
2
+ const {
3
+ router,
4
+ controller,
5
+ } = app;
6
+ router.get("/", controller.home.index);
7
+ router.get("/list", controller.home.list);
8
+ };
@@ -0,0 +1,15 @@
1
+ const Tea = require('../../../../core/chan');
2
+
3
+
4
+ function index() {
5
+ return 'Hello Teajs';
6
+ }
7
+
8
+ function list(){
9
+ return 'Teajs List';
10
+ }
11
+
12
+ module.exports = {
13
+ index,
14
+ list
15
+ }
package/core/chan.js ADDED
@@ -0,0 +1,250 @@
1
+ const express = require("express");
2
+ const config = require("./lib/config/config.js");
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+ const core = require("chanjs/lib/core.js");
6
+
7
+ /**
8
+ * @description 基于express封装的mvc框架,遵循约定优于配置原则
9
+ */
10
+ class Chan {
11
+ constructor(options={}) {
12
+ //配置
13
+ Chan.config = Object.assign(config, options);
14
+
15
+ //模块
16
+ Chan.modules ={};
17
+ //工具
18
+ Chan.helper ={};
19
+ //应用实例
20
+ this.app = express();
21
+ this.app.config = Chan.config;
22
+ this.router = express.Router();
23
+ //加载配置
24
+ this.loadConfig();
25
+ //加载扩展
26
+ this.loadExtends();
27
+ //加载核心(日志、favicon 图标、cookie、json、url、模板引擎、静态资源)
28
+ this.loadCore();
29
+ //加载实例化数据库
30
+ this.loadKnex();
31
+ //生命周期钩子:开始启动
32
+ this.beforeStart();
33
+ //加载模块
34
+ this.loadModules();
35
+ //生命周期:初始化完成
36
+ this.start()
37
+ }
38
+
39
+ // 加载配置
40
+ loadConfig() {
41
+ const configPath = path.join(config.APP_PATH, "config/index.js");
42
+ if (fs.existsSync(configPath)) {
43
+ const config = require(configPath);
44
+ console.log('111----',Chan.config)
45
+ Chan.config = Object.assign(Chan.config, config);
46
+ console.log('222----',Chan.config)
47
+ }
48
+
49
+
50
+ }
51
+
52
+ // 加载扩展
53
+ loadExtends() {
54
+ const extendPath = path.join(config.APP_PATH, "extend");
55
+ if (fs.existsSync(extendPath)) {
56
+ let controllers = fs
57
+ .readdirSync(extendPath)
58
+ .filter((file) => file.endsWith(".js"));
59
+ for (let i = 0, file; i < controllers.length; i++) {
60
+ file = controllers[i];
61
+ const helper = require(path.join(extendPath, file));
62
+
63
+ const fileName = file.replace(".js", "");
64
+ Chan.helper[fileName] = helper;
65
+ }
66
+ }
67
+
68
+ }
69
+
70
+ //数据库操作
71
+ loadKnex(){
72
+ // 连接数据库
73
+ const {host,port,user,password,database,client,charset} = Chan.config.database;
74
+ const knex = require("knex")({
75
+ client: "mysql2",
76
+ connection: {
77
+ host,
78
+ port,
79
+ user,
80
+ password,
81
+ database,
82
+ charset,
83
+ },
84
+ debug: config.debug, //指明是否开启debug模式,默认为true表示开启
85
+ pool: {
86
+ //指明数据库连接池的大小,默认为{min: 2, max: 10}
87
+ min: 0,
88
+ max: 2,
89
+ },
90
+ log: {
91
+ warn(message) {
92
+ console.error("[knex warn]", message);
93
+ },
94
+ error(message) {
95
+ console.error("[knex error]", message);
96
+ },
97
+ },
98
+ });
99
+ Chan.knex = knex;
100
+ }
101
+
102
+
103
+ //开始启动
104
+ beforeStart(cb) {
105
+ // 初始化一些配置
106
+ cb && cb();
107
+ }
108
+
109
+ //启动
110
+ start(cb){
111
+ // 初始化一些配置
112
+ cb && cb();
113
+ }
114
+
115
+ // 加载插件
116
+ loadPlugins() {
117
+ const configPath = path.join(config.APP_PATH, "plugin");
118
+ if (fs.existsSync(configPath)) {
119
+ const dirs = fs
120
+ .readdirSync(configPath, { withFileTypes: true })
121
+ .filter((dirent) => dirent.isDirectory())
122
+ .map((dirent) => dirent.name);
123
+ this.plugins = dirs;
124
+ } else {
125
+ this.plugins = [];
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @description app核心模块:日志、favicon 图标、cookie、json、url、模板引擎、静态资源
131
+ */
132
+ loadCore(){
133
+ core(this.app);
134
+ }
135
+
136
+ /**
137
+ * @description 模块加载入口(路由&控制器& 服务)
138
+ */
139
+ loadModules() {
140
+ const configPath = path.join(config.APP_PATH, "modules");
141
+ if (fs.existsSync(configPath)) {
142
+ const dirs = fs
143
+ .readdirSync(configPath, { withFileTypes: true })
144
+ .filter((dirent) => dirent.isDirectory())
145
+ .map((dirent) => dirent.name);
146
+
147
+ this.modulesDir = dirs;
148
+ for(let i=0,item;i<dirs.length;i++){
149
+ item = dirs[i];
150
+ Chan.modules[item] = {
151
+ controller: {},
152
+ service: {},
153
+ };
154
+ this.loadModule(item);
155
+ }
156
+
157
+ //通用路由,加载错误处理和500路由和爬虫处理
158
+ const baseRouterPath = path.join(config.APP_PATH, "router.js");
159
+ if (fs.existsSync(baseRouterPath)) {
160
+ const _router = require(baseRouterPath);
161
+ _router(this.app, this.router);
162
+ }
163
+ //执行路由
164
+ // this.app.use(this.router);
165
+ }
166
+ }
167
+
168
+
169
+ /**
170
+ * @description 加载模块,包括 controller service router
171
+ * @param {String} moduleName 模块名称
172
+ */
173
+ loadModule(moduleName) {
174
+ const moduleDir = path.join(config.APP_PATH, "modules", moduleName);
175
+ this.loadServices(moduleDir,moduleName);
176
+ this.loadControllers(moduleDir,moduleName);
177
+ this.loadRoutes(moduleDir,moduleName);
178
+ }
179
+
180
+
181
+ /**
182
+ * @description 扫描模块下所有service
183
+ * @param {*} moduleDir 模块路径
184
+ * @param {*} moduleName 模块名称
185
+ */
186
+ loadServices(moduleDir,moduleName) {
187
+ const servicesDir = path.join(moduleDir, "service");
188
+ if (fs.existsSync(servicesDir)) {
189
+ let services = fs
190
+ .readdirSync(servicesDir)
191
+ .filter((file) => file.endsWith(".js"));
192
+ for (let i = 0, file; i < services.length; i++) {
193
+ file= services[i]
194
+ const Service = require(path.join(servicesDir, file));
195
+ const serviceName = file.replace(".js", "");
196
+ Chan.modules[moduleName].service[serviceName] = {};
197
+ Chan.modules[moduleName].service[serviceName] = Service;
198
+ }
199
+ }
200
+ }
201
+
202
+
203
+ /**
204
+ * @description 扫描模块下所有controller
205
+ * @param {*} moduleDir 模块路径
206
+ * @param {*} moduleName 模块名称
207
+ */
208
+ loadControllers(moduleDir,moduleName) {
209
+ const controllersDir = path.join(moduleDir, "controller");
210
+ if (fs.existsSync(controllersDir)) {
211
+ let controllers = fs
212
+ .readdirSync(controllersDir)
213
+ .filter((file) => file.endsWith(".js"));
214
+ for (let i = 0, file; i < controllers.length; i++) {
215
+ file= controllers[i]
216
+ const controller = require(path.join(controllersDir, file));
217
+ const controllerName = file.replace(".js", "");
218
+ Chan.modules[moduleName].controller[controllerName] = {};
219
+ Chan.modules[moduleName].controller[controllerName] = controller;
220
+ }
221
+ }
222
+ }
223
+
224
+ /**
225
+ * @description 扫描模块下所有router.js
226
+ * @param {*} moduleDir 模块路径
227
+ * @param {*} moduleName 模块名称
228
+ */
229
+ loadRoutes(moduleDir,moduleName) {
230
+ const routersDir = path.join(moduleDir, "router.js");
231
+ if (fs.existsSync(routersDir)) {
232
+ const routes = require(routersDir);
233
+ routes({router:this.router,modules:Chan.modules,app:this.app});
234
+ }
235
+ }
236
+
237
+
238
+
239
+ loadPlusins() {
240
+ // 加载插件
241
+ }
242
+
243
+ run(port) {
244
+ this.app.listen(port, () => {
245
+ console.log(`Server is running on port ${port}`);
246
+ });
247
+ }
248
+ }
249
+
250
+ module.exports = Chan;
@@ -0,0 +1,35 @@
1
+ const express = require("express");
2
+ const cookieParser = require("cookie-parser");
3
+ const favicon = require("serve-favicon");
4
+ const morgan = require("morgan");
5
+ const path = require("path");
6
+
7
+ const view = require("./middleware/view.js");
8
+ module.exports = async function (app) {
9
+
10
+ const { logger,APP_PATH, cookieKey, maxAge } = app.config;
11
+ //日志
12
+ app.use(morgan(logger.level));
13
+
14
+ // favicon 图标
15
+ app.use(favicon(path.join(APP_PATH, "public/favicon.ico")));
16
+
17
+ //cookie
18
+ app.use(cookieParser(cookieKey));
19
+
20
+ //解析接口 json & url
21
+ app.use(express.json());
22
+ app.use(express.urlencoded({ extended: false }));
23
+
24
+ //配置模板引擎
25
+ view(app);
26
+
27
+ //使用静态资源 ,
28
+ app.use(
29
+ "/public",
30
+ express.static(path.join(APP_PATH, "public"), {
31
+ maxAge:maxAge,
32
+ })
33
+ );
34
+
35
+ };
@@ -0,0 +1,37 @@
1
+ const path = require('path');
2
+
3
+ /**
4
+ * @description 根目录
5
+ */
6
+ const ROOT_PATH = process.cwd();
7
+
8
+ /**
9
+ * @description 程序目录
10
+ */
11
+ const APP_PATH = path.join(ROOT_PATH, 'app');
12
+
13
+ let config = {
14
+ logger : {
15
+ level: 'dev',
16
+ },
17
+ env:'dev',
18
+ template:'default',
19
+ cookieKey:'chanjs-2024-02-02-10:49',
20
+ maxAge:'1d',
21
+ views:[], //模板路径
22
+ database:{
23
+ client: "mysql2",
24
+ host: "localhost",
25
+ port: "3306",
26
+ user: "root",
27
+ password: "123456",
28
+ database: "chanyue",
29
+ charset: "utf8mb4",
30
+ }
31
+ }
32
+
33
+ module.exports = {
34
+ ROOT_PATH,
35
+ APP_PATH,
36
+ ...config
37
+ }
@@ -0,0 +1,35 @@
1
+ const express = require("express");
2
+ const cookieParser = require("cookie-parser");
3
+ const favicon = require("serve-favicon");
4
+ const morgan = require("morgan");
5
+ const path = require("path");
6
+
7
+ const view = require("chanjs/lib/middleware/view.js");
8
+ module.exports = async function (app) {
9
+
10
+ const { logger,APP_PATH, cookieKey, maxAge } = app.config;
11
+ //日志
12
+ app.use(morgan(logger.level));
13
+
14
+ // favicon 图标
15
+ app.use(favicon(path.join(APP_PATH, "public/favicon.ico")));
16
+
17
+ //cookie
18
+ app.use(cookieParser(cookieKey));
19
+
20
+ //解析接口 json & url
21
+ app.use(express.json());
22
+ app.use(express.urlencoded({ extended: false }));
23
+
24
+ //配置模板引擎
25
+ view(app);
26
+
27
+ //使用静态资源 ,
28
+ app.use(
29
+ "/public",
30
+ express.static(path.join(APP_PATH, "public"), {
31
+ maxAge:maxAge,
32
+ })
33
+ );
34
+
35
+ };
@@ -0,0 +1,31 @@
1
+ const path = require("path");
2
+ const dealRouter = (app,router) => {
3
+
4
+ const {config:{template='default',APP_PATH}} = app;
5
+ //机器人抓取
6
+ router.get("/robots.txt", function (req, res, next) {
7
+ res.type('text/plain');
8
+ res.sendFile(path.join(APP_PATH, "/public/robots.txt"));
9
+ });
10
+
11
+ //404处理
12
+ router.use((req, res, next) => {
13
+ let ip = req.headers["x-forwarded-for"] || req.ip;
14
+ console.log("404-->", `${req.method}-${decodeURI(req.url)}-${ip}`);
15
+ res.render(`${template}/404.html`);
16
+ });
17
+
18
+ //处理错误
19
+ router.use((err, req, res) => {
20
+ console.error("500-->", req.method, req.url, err);
21
+ let data = { url: req.url, method: req.method, error: err.message };
22
+ if (req.is("html") || req.is("html") == null) {
23
+ res.render(`${template}/500.html`, { data });
24
+ } else {
25
+ res.json({ code: 500, data, msg: data.error });
26
+ }
27
+ });
28
+
29
+ };
30
+
31
+ module.exports = dealRouter;
@@ -0,0 +1,18 @@
1
+ const path = require("path");
2
+ module.exports = (app) => {
3
+ const
4
+ { APP_PATH, views,env } = app.config;
5
+ //默认home view
6
+ const home = path.join(APP_PATH, `modules/home/view`);
7
+ //合并插件中的view
8
+ const all = [...views, home];
9
+
10
+ app.set("view options", {
11
+ debug: env != "prd",
12
+ cache: env == "prd",
13
+ minimize: true,
14
+ });
15
+ app.set("view engine", "html");
16
+ app.set("views", all);
17
+ app.engine(".html", require("express-art-template"));
18
+ };
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "chanjs",
3
+ "version": "0.0.1",
4
+ "description": "Chan.js 基于express 纯js研发的轻量级mvc框架。基于函数式编程思想,性能优越,代码清晰,流程易读,可持续维护高。",
5
+ "main": "chan.js",
6
+ "directories": {
7
+ "lib": "lib"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "author": "明空",
13
+ "license": "ISC"
14
+ }
package/index.js ADDED
@@ -0,0 +1,9 @@
1
+ const Chan = require('./core/chan');//本地开发调试
2
+ // const Chan = require('chanjs'); 正式开发换成npm包
3
+
4
+ const app = new Chan();
5
+ app.beforeStart(()=>{
6
+ // 启动服务前的操作
7
+ console.log('可以操作数据库,加载配置');
8
+ })
9
+ app.run(8000);
package/package.json CHANGED
@@ -1,14 +1,29 @@
1
1
  {
2
2
  "name": "chanjs",
3
- "version": "0.0.1",
4
- "description": "Chan.js 基于express 纯js研发的轻量级mvc框架。基于函数式编程思想,性能优越,代码清晰,流程易读,可持续维护高。",
5
- "main": "chan.js",
6
- "directories": {
7
- "lib": "lib"
8
- },
3
+ "version": "1.0.0",
4
+ "description": "\"chanjs\"",
5
+ "main": "core/chan.js",
9
6
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "dev": "nodemon app.js",
8
+ "clear": "node timer.js",
9
+ "prd": "pm2 start pm2.json"
10
+ },
11
+ "keywords": [
12
+ "\"mvc\""
13
+ ],
14
+ "author": "\"明空\"",
15
+ "license": "ISC",
16
+ "dependencies": {
17
+ "art-template": "^4.13.2",
18
+ "body-parser": "^1.20.2",
19
+ "cookie-parser": "^1.4.6",
20
+ "express": "^4.18.2",
21
+ "express-art-template": "^1.0.1",
22
+ "knex": "^3.0.1",
23
+ "morgan": "^1.10.0",
24
+ "mysql2": "^3.6.2"
11
25
  },
12
- "author": "明空",
13
- "license": "ISC"
14
- }
26
+ "devDependencies": {
27
+ "nodemon": "^3.0.1"
28
+ }
29
+ }
package/chan.js DELETED
@@ -1,162 +0,0 @@
1
- const express = require("express");
2
- const config = require("./lib/config/config.js");
3
- const path = require("path");
4
- const fs = require("fs");
5
-
6
- /**
7
- * @description chanjs
8
- */
9
- class Chan {
10
- constructor(options={}) {
11
-
12
- //加载全局对象
13
- this.config = Object.assign(config, options);
14
- //配置
15
- Chan.config = this.config;
16
- //模块
17
- Chan.modules = this.modules = {};
18
- //帮助文档
19
- Chan.helper = this.helper = {};
20
-
21
- this.app = express();
22
- this.router = express.Router();
23
-
24
- this.loadConfig();
25
- this.beforeStart();
26
- this.init();
27
- }
28
-
29
- // 加载配置
30
- loadConfig() {
31
- const configPath = path.join(config.APP_PATH, "config/index.js");
32
- if (fs.existsSync(configPath)) {
33
- const config = require(configPath);
34
- Object.assign(this.config, config);
35
- }
36
-
37
- console.log("config——>配置文件加载完成");
38
- }
39
-
40
- //启动加载
41
- beforeStart(cb) {
42
- // 初始化一些配置
43
- console.log("beforeStart--->初始化一些配置");
44
- cb && cb();
45
- }
46
-
47
- init() {
48
- this.loadModules();
49
- this.loadExtends();
50
- this.loadPlusins();
51
-
52
- }
53
-
54
- loadModules() {
55
- const configPath = path.join(config.APP_PATH, "module");
56
- if (fs.existsSync(configPath)) {
57
- const dirs = fs
58
- .readdirSync(configPath, { withFileTypes: true })
59
- .filter((dirent) => dirent.isDirectory())
60
- .map((dirent) => dirent.name)
61
- .forEach((item, index) => {
62
- this.modules[item] = {
63
- controller: {},
64
- service: {},
65
- };
66
- this.loadModule(item);
67
- });
68
- //执行路由
69
- this.app.use(this.router);
70
- }
71
- }
72
-
73
- // 加载插件
74
- loadPlugins() {
75
- const configPath = path.join(config.APP_PATH, "plugin");
76
- if (fs.existsSync(configPath)) {
77
- const dirs = fs
78
- .readdirSync(configPath, { withFileTypes: true })
79
- .filter((dirent) => dirent.isDirectory())
80
- .map((dirent) => dirent.name);
81
- this.plugins = dirs;
82
- } else {
83
- this.plugins = [];
84
- }
85
- }
86
-
87
- loadModule(moduleName) {
88
- const moduleDir = path.join(config.APP_PATH, "module", moduleName);
89
- this.loadServices(moduleDir,moduleName);
90
- this.loadControllers(moduleDir,moduleName);
91
- this.loadRoutes(moduleDir,moduleName);
92
- }
93
-
94
- // 加载服务
95
- loadServices(moduleDir,moduleName) {
96
- const servicesDir = path.join(moduleDir, "service");
97
- if (fs.existsSync(servicesDir)) {
98
- let services = fs
99
- .readdirSync(servicesDir)
100
- .filter((file) => file.endsWith(".js"));
101
- for (let i = 0, file = services[i]; i < services.length; i++) {
102
- const Service = require(path.join(servicesDir, file));
103
- const serviceName = file.replace(".js", "");
104
- this.modules[moduleName].service[serviceName] = {};
105
- this.modules[moduleName].service[serviceName] = Service;
106
- }
107
- }
108
- }
109
-
110
- // 加载控制器
111
- loadControllers(moduleDir,moduleName) {
112
- const controllersDir = path.join(moduleDir, "controller");
113
- if (fs.existsSync(controllersDir)) {
114
- let controllers = fs
115
- .readdirSync(controllersDir)
116
- .filter((file) => file.endsWith(".js"));
117
- for (let i = 0, file = controllers[i]; i < controllers.length; i++) {
118
- const controller = require(path.join(controllersDir, file));
119
- const controllerName = file.replace(".js", "");
120
- this.modules[moduleName].controller[controllerName] = {};
121
- this.modules[moduleName].controller[controllerName] = controller;
122
- }
123
- }
124
- }
125
-
126
- // 加载路由
127
- loadRoutes(moduleDir,moduleName) {
128
- const routersDir = path.join(moduleDir, "router.js");
129
- if (fs.existsSync(routersDir)) {
130
- const routes = require(routersDir);
131
- routes({router:this.router,controller:this.modules[moduleName].controller});
132
- }
133
- }
134
-
135
- // 加载扩展
136
- loadExtends() {
137
- const extendPath = path.join(config.APP_PATH, "extend");
138
- if (fs.existsSync(extendPath)) {
139
- let controllers = fs
140
- .readdirSync(extendPath)
141
- .filter((file) => file.endsWith(".js"));
142
- for (let i = 0, file = controllers[i]; i < controllers.length; i++) {
143
- const helper = require(path.join(extendPath, file));
144
- const fileName = file.replace(".js", "");
145
- this.helper[fileName] = helper;
146
- }
147
- }
148
- }
149
-
150
- loadPlusins() {
151
- // 加载插件
152
- }
153
-
154
- run(port) {
155
- this.app.listen(port, () => {
156
- console.log(`Server is running on port ${port}`);
157
- });
158
- }
159
- }
160
-
161
-
162
- module.exports = Chan;
package/lib/base.js DELETED
@@ -1,8 +0,0 @@
1
- class Base{
2
- constructor(config){
3
- this.config = config;
4
- }
5
- log(...args){
6
- console.log(...args);
7
- }
8
- }
@@ -1,18 +0,0 @@
1
- const path = require('path');
2
-
3
- /**
4
- * @description 根目录
5
- */
6
- const ROOT_PATH = process.cwd();
7
-
8
- /**
9
- * @description 程序目录
10
- */
11
- const APP_PATH = path.join(ROOT_PATH, 'app');
12
-
13
- module.exports = {
14
- ROOT_PATH,
15
- APP_PATH,
16
- }
17
-
18
-
File without changes
File without changes
File without changes
File without changes
File without changes