您的位置:首页 > Web前端 > Node.js

Node.js 国产 MVC 框架 ThinkJS 开发 入门

2017-07-14 00:00 1041 查看


ThinkJS (官网 https://thinkjs.org) 是一款非常优秀的 Node.js 国产 MVC 开发框架,下面摘自官网的介绍:

ThinkJS 是一款使用 ES6/7 特性全新开发的 Node.js MVC 框架,使用 ES7 中 async/await,或者 ES6 中的 */yield 特性彻底解决了 Node.js 中异步嵌套的问题。同时吸收了国内外众多框架的设计理念和思想,让开发 Node.js 项目更加简单、高效。

使用 ES6/7 特性来开发项目可以大大提高开发效率,是趋势所在。并且新版的 Node.js 对 ES6 特性也有了较好的支持,即使有些特性还没有支持,也可以借助 Babel 编译来支持。

目前 ThinkJS 版本发布到了 v2.2.19 (更新日志),并且 v3.0beta 版本已经进入公测阶段。

本系列教程以 v2.x 版本为例进行介绍,教程以实际操作为主,ThinkJS 的安装详见官网文档说明。

原创:荆秀网 网页即时推送 https://xxuyou.com | 转载请注明出处
链接:https://blog.xxuyou.com/nodejs-thinkjs-study-start/

官网提供了创建一个空项目,以及空项目的代码结构介绍,这里不再赘述。以下是一些官网没有提到的小技巧,先做个了解~

新项目

为了确保用户错误操作导致现有文件被覆盖,
thinkjs new
命令仅适用于文件夹不存在的,或者空文件夹。否则会收到类似如下的错误提示:

path `/data/www/demo` is already a thinkjs project.

实现这一特性其实是依赖一个项目根目录下的隐藏文件
.thinkjsrc
,使用
ls -a
可以查看隐藏文件,打开这个文件可以看到如下内容:

{
"createAt": "2017-02-12 19:08:38",
"mode": "module",
"es": true
}

按模块分解

创建项目之后,基本的代码框架已经建立起来了(详见 https://thinkjs.org/zh-cn/doc/2.2/app_structure.html),其中默认的
home
common
肯定是无法满足要求的。我们需要给自己的项目建立起相关的层次结构。

以下是几个较为典型的项目模块结构参考。

简单网站

例如官方网站、博客、社区等,这类系统结构较为简单,通常一个前端一个后端管理即可满足要求。

模块结构如下:

src/
src/common/  # 通用模块,放置主配置参数、boostrap adapter middleware service 等相关组件
src/home/  # 前端默认模块
src/backend/  # 后端管理模块
src/util/  # 系统工具类

电商平台

电商平台系统主要考虑到入驻的商户、注册的客户、管理人员、运营人员等使用人群,还需要考虑到较大的功能模块切分(如果足够大到类似京东、天猫那种体量的系统,则需要进行数据、功能、服务、位置等角度的分割)。

模块结构如下:

src/
src/common/
src/home/
src/sso/  # 单点登录、令牌管理等
src/rest/  # 针对Wap、App等多客户端的 rest api
src/goods/  # 商品管理及服务
src/storage/  # 库存管理及服务
src/cart/  # 购物车
src/order/  # 订单
src/delivery/  # 快递
src/pay/  # 在线支付、空中支付
src/member/  #
src/coupon/  # 电子券
src/promotion/  # 促销
src/points/  # 积分
src/merchant/  # 入驻商户
src/shop/  # 商户门店
src/finance/  # 财务核算及款项清算
src/stat/
src/log/
src/monitor/
src/util/
src/task/
src/message/  # 消息队列

即时消息平台

实时推送平台不仅仅要处理 WebSocket 连接和消息囤积发送,还要处理多用户购买相应服务套餐、统计连接数、统计下行流量、进行连接鉴权等,Firebase野狗荆秀即时推送 等都是这类的服务商。

模块结构如下:

src/
src/common/
src/home/
src/rest/
src/storage/
src/websocket/  # ws 或者 wss 服务
src/webhook/  # 钩子服务
src/middleware/  # 搭载中间件运行
src/pay/
src/member/
src/stat/
src/log/
src/monitor/
src/util/
src/message/  # 消息队列

代驾、租车运营平台

代驾、租车、共享单车等平台需要解决的是资源(客户、车、目的地)定位、路线计算、实时定点跟踪、GPS围栏监测等技术问题,然后才是商务行为的电子化处理。

模块结构如下:

src/
src/common/
src/home/
src/rest/
src/map/  # 地图资源、路线计算、电子围栏运算
src/storage/
src/websocket/  # 实时消息传递
src/pay/
src/member/
src/driver/
src/assets/  # 资源费效评估
src/stat/
src/log/
src/math/  # 计算服务
src/monitor/
src/util/

在线教育、直播平台

在线教育或直播平台通常具备实时音视频上传、转码、存储、广播等硬性要求,因此系统除了管理相关课件、学生、教师、选课等,还要负责处理相关媒体文件。

模块结构如下:

src/
src/common/
src/home/
src/rest/
src/sso/  # 单点登录、令牌管理等
src/media/  # 课件、音视频等媒体文件
src/bulk/  # 流媒体
src/process/  # 编解码处理
src/storage/
src/live/  # 直播
src/pay/
src/student/
src/teacher/
src/schedule/
src/stat/
src/log/
src/monitor/
src/util/
src/task/
src/message/  # 消息队列

注:以上结构为示例,并不具备通用性,研发时应当需要根据实际情况进行设计或调整。

项目模式

项目模式其实官网有介绍,但是太过简略,基本上是一笔带过。看看如下两种创建 thinkjs 项目的方式:

# 用 mode 参数创建一个简单结构项目
thinkjs new thinkjs_normal --mode=normal

# 无 mode 参数创建一个较为复杂结构的项目
thinkjs new thinkjs_module

两者创建的项目结构区别其实很简单:

normal mode 的结构直接把
config
controller
logic
model
提到
src
下面,因此适用于一个简单的网站系统。

module mode 则建立了基本的
home
common
两个应用模块,显然是为了较为复杂、多人协作的中大型项目进行的逻辑分割。

thinkjs_normal 项目结构

thinkjs_normal/package.json
thinkjs_normal/.babelrc
thinkjs_normal/.thinkjsrc
thinkjs_normal/nginx.conf
thinkjs_normal/pm2.json
thinkjs_normal/.gitignore
thinkjs_normal/README.md
thinkjs_normal/www
thinkjs_normal/www/development.js
thinkjs_normal/www/production.js
thinkjs_normal/www/testing.js
thinkjs_normal/www/README.md
thinkjs_normal/www/static
thinkjs_normal/www/static/js
thinkjs_normal/www/static/css
thinkjs_normal/www/static/img
thinkjs_normal/src
thinkjs_normal/src/bootstrap
thinkjs_normal/src/bootstrap/middleware.js
thinkjs_normal/src/bootstrap/global.js
thinkjs_normal/src/config
thinkjs_normal/src/config/config.js
thinkjs_normal/src/config/view.js
thinkjs_normal/src/config/db.js
thinkjs_normal/src/config/hook.js
thinkjs_normal/src/config/session.js
thinkjs_normal/src/config/error.js
thinkjs_normal/src/config/env
thinkjs_normal/src/config/env/development.js
thinkjs_normal/src/config/env/testing.js
thinkjs_normal/src/config/env/production.js
thinkjs_normal/src/config/locale
thinkjs_normal/src/config/locale/en.js
thinkjs_normal/src/controller
thinkjs_normal/src/controller/error.js
thinkjs_normal/view
thinkjs_normal/view/error_400.html
thinkjs_normal/view/error_403.html
thinkjs_normal/view/error_404.html
thinkjs_normal/view/error_500.html
thinkjs_normal/view/error_503.html
thinkjs_normal/src/controller/base.js
thinkjs_normal/src/controller/index.js
thinkjs_normal/src/logic
thinkjs_normal/src/logic/index.js
thinkjs_normal/src/model
thinkjs_normal/src/model/index.js
thinkjs_normal/view/index_index.html

thinkjs_module 项目结构

thinkjs_module/package.json
thinkjs_module/.babelrc
thinkjs_module/.thinkjsrc
thinkjs_module/nginx.conf
thinkjs_module/pm2.json
thinkjs_module/.gitignore
thinkjs_module/README.md
thinkjs_module/www
thinkjs_module/www/development.js
thinkjs_module/www/production.js
thinkjs_module/www/testing.js
thinkjs_module/www/README.md
thinkjs_module/www/static
thinkjs_module/www/static/js
thinkjs_module/www/static/css
thinkjs_module/www/static/img
thinkjs_module/src
thinkjs_module/src/common/bootstrap
thinkjs_module/src/common/bootstrap/middleware.js
thinkjs_module/src/common/bootstrap/global.js
thinkjs_module/src/common/config
thinkjs_module/src/common/config/config.js
thinkjs_module/src/common/config/view.js
thinkjs_module/src/common/config/db.js
thinkjs_module/src/common/config/hook.js
thinkjs_module/src/common/config/session.js
thinkjs_module/src/common/config/error.js
thinkjs_module/src/common/config/env
thinkjs_module/src/common/config/env/development.js
thinkjs_module/src/common/config/env/testing.js
thinkjs_module/src/common/config/env/production.js
thinkjs_module/src/common/config/locale
thinkjs_module/src/common/config/locale/en.js
thinkjs_module/src/common/controller
thinkjs_module/src/common/controller/error.js
thinkjs_module/view/common
thinkjs_module/view/common/error_400.html
thinkjs_module/view/common/error_403.html
thinkjs_module/view/common/error_404.html
thinkjs_module/view/common/error_500.html
thinkjs_module/view/common/error_503.html
thinkjs_module/src/home/config
thinkjs_module/src/home/config/config.js
thinkjs_module/src/home/controller
thinkjs_module/src/home/controller/base.js
thinkjs_module/src/home/controller/index.js
thinkjs_module/src/home/logic
thinkjs_module/src/home/logic/index.js
thinkjs_module/src/home/model
thinkjs_module/src/home/model/index.js
thinkjs_module/view/home
thinkjs_module/view/home/index_index.html

配置参数

官网是这么描述配置文件加载顺序的:

框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置


先问个问题:这五个配置都指的是哪里呢?

前两个可以忽略掉,那是 thinkjs 框架自身的配置设置,通常里面不会有我们项目会用到的配置参数。

第三个和第四个则是在不同的项目创建模式下的默认 config 配置文件夹,位置在:

# normal mode
thinkjs_normal/src/config/*
# module mode
thinkjs_module/src/common/config/*

最后一个是指的在 module mode 下的项目,每个 module 自己的 config,位置在:

thinkjs_module/src/home/config/*

明白了多个地方多个配置文件的玩法之后,你可以创建多个 module,并给每个 module 配置自身独特的配置参数。

需要注意的是:thinkjs 加载配置文件是有顺序的![b]回到本节一开始提到的加载顺序,你应当明白:多个配置文件最终会在 thinkjs 运行时被全部加载,并合并在一起[/b](注意加粗文字)。

所以当存在多个配置文件时,需要注意配置参数的 key(即属性名)尽量不要重复,因为按照加载顺序,后加载的 key 的值会覆盖先加载的 key 的值,导致出现不希望的结果。

举例来说,有两个配置文件
src/common/config/assets.js
src/home/config/assets.js
,其中内容是:

// src/common/config/assets.js
export default {
"site_title": "my site"
};

// src/home/config/assets.js
export default {
"site_title": "my test"
};

// src/home/controller/index.js
let assets = this.config('assets');
let siteTitle = assets['site_title'];
console.log('siteTitle is: ', siteTitle); // my test

注:当然也有办法获取到 "my site" 这个值,后面的教程会提到方法。

公共方法

thinkjs 提供了一个
src/common/bootstrap/global.js
文件来放置全局变量/函数。

// 可以直接在 global.js 中增加自己定义的函数
global.formatDate = obj => {
//...
}

如果你的自定义函数很多,想分门别类的组织,也可以在
src/common/bootstrap/
文件夹下新增文件来定义函数。当项目启动时,该目录下的文件会自动加载,无需手动 require。

src/common/bootstrap/global_datetime.js
src/common/bootstrap/global_math.js
src/common/bootstrap/global_string.js

注:thinkjs v3.x 可能会取消
bootstrap
,想要升级的朋友们注意了。 ThinkJS v3.x 设计图

Babel 编译时删除注释

开发时的工作代码都在
src
下面,运行时才会编译到
app
下面成为运行脚本(经过 Babel 编译),如果不想自己写的各种注释也出现在
app
下面的代码中,可以修改项目目录下的一个隐藏文件
.babelrc
增加相应
comments
参数。

增加该参数后编译速度会比较慢,因为需要处理的代码内容多了~

{
"presets": [
["es2015", {"loose": true}],
"stage-1"
],
"plugins": ["transform-runtime"],
"sourceMaps": true,
"comments": false  # <-- 就是这个参数
}

注:给喜欢在生产服务器就地编译的筒子们。

完善 package.json 字段

package 打包描述文件虽然会被 thinkjs 自动生成,不过如果能够手工维护这个文件,添加必要的属性,会让我们的项目工程更加规范、有序。

参考一下 thinkjs v2.x 源码的 package.json 文件:

{
"name": "thinkjs",
"description": "ThinkJS - Use full ES6/7 features to develop web applications, Support TypeScript",
"version": "2.2.18",
"author": {
"name": "welefen",
"email": "welefen@gmail.com"
},
"scripts": {
"test": "npm run eslint && npm run test-cov",
"test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -t 50000 --recursive  -R spec test/",
"compile": "babel src/ --out-dir lib/",
"watch-compile": "npm run compile -- --watch",
"watch": "npm run watch-compile",
"prepublish": "npm run compile",
"eslint": "eslint src/"
},
"bin": {
"thinkjs": "./bin/index.js"
},
"contributors": [
{
"name": "welefen",
"email": "welefen@gmail.com"
},
{
"name": "im-kulikov",
"email": "im@kulikov.im"
},
{
"name": "maxzhang",
"email": "zhangdaiping@gmail.com"
},
{
"name": "akira-cn",
"email": "akira.cn@gmail.com"
},
{
"name": "qgy18",
"email": "quguangyu@gmail.com"
}
],
"main": "lib/index.js",
"dependencies": {
"ejs": "2.4.1",
"multiparty": "4.1.2",
"mime": "1.3.4",
"mysql": "2.11.1",
"thinkit": "4.10.0",
"babel-runtime": "6.6.1",
"bluebird": "3.3.5",
"co": "4.6.0",
"colors": "1.1.2",
"validator": "4.2.0",
"commander": "2.9.0"
},
"devDependencies": {
"mocha": "1.20.1",
"muk": "0.3.1",
"istanbul": "0.4.0",
"babel-cli": "^6.18.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-1": "^6.16.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-core": "^6.20.0",
"babel-eslint": "^6.0.4",
"eslint": "2.8.0",
"typescript": "^2.1.6",
"source-map": "0.5.3"
},
"keywords": [
"thinkjs",
"framework",
"web",
"rest",
"restful",
"router",
"api",
"es6",
"es7",
"async",
"await",
"yield",
"websocket",
"generator-function",
"typescript"
],
"repository": {
"type": "git",
"url": "https://github.com/thinkjs/thinkjs"
},
"engines": {
"node": ">=0.12.0"
},
"license": "MIT",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/thinkjs/thinkjs/issues"
}
}

修改 pm2 日志位置

pm2 (官网 http://pm2.keymetrics.io)是一个优秀的 Node.js 进程管理器。

它的强大之处在于不仅可以作为 Node.js 项目的守护进程,还具备可配置化启动、分布式支持、内存监控、热重载(优雅重载)、支持数据统计、运行日志记录、实时运行监控、API 和脚本支持等强大的特性。(更多的特性,另文描述~)

thinkjs 推荐使用 pm2 来管理项目运行,并自动生成了 pm2 的配置文件
pm2.json


默认生成的 pm2 配置文件不含日志记录部分,如果不单独配置,pm2 的日志将会保存在安装目录中,查找起来很不方便(当然你可以使用
pm2 logs [id|name]
来直接查看某个进程的日志,不过有些时候还是需要直接查看日志文件的)。

我的做法是:在项目目录下建立
logs
文件夹,用来放置 pm2 以及其他(诸如 log4js 等等)日志,打开
pm2.json
,给
apps[0]
增加如下几行配置参数:

{
"apps": [{
"error_file"      : "/data/www/thinkjs_module/logs/pm2-err.log",
"out_file"        : "/data/www/thinkjs_module/logs/pm2-out.log",
"log_date_format" : "YYYY-MM-DD HH:mm:ss Z",
"merge_logs"      : false
}]
}


error_file pm2 捕捉到的致命错误记录在这里

out_file pm2 接收到的 console 输出记录在这里

log_date_format 日期和时间格式

merge_logs 是否给日志文件增加进程id的后缀

注:更详细的参数配置,可前往 pm2 官网查阅。

done~

下一篇:Node.js 国产 MVC 框架 ThinkJS 开发 config 篇

原创:荆秀网 网页即时推送 https://xxuyou.com | 转载请注明出处
链接:https://blog.xxuyou.com/nodejs-thinkjs-study-start/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Node.js thinkjs Koa es7