本文主要和大家分享前端框架ThinkJS框架詳解,Thinkjs 是一個快速、簡單的基於MVC和物件導向的輕量級Node.js開發框架,遵循MIT協定發布。秉持簡潔易用的設計原則,在維持出色的效能和至簡的程式碼同時,專注於開發體驗和易用性,為WEB應用開發提供強而有力的支援。
Thinkjs裡面很多特性來自ThinkPHP,同時根據Node.js的特點,使用了Promise, WebSocket等特性,讓程式碼更簡潔、優雅。最大的特色是對目前比較潮的語法特性支援的特別好,例如es6、es7、typescript等,有了這些,對aysnc/await等特性支持,讓程式碼更加fashion。
安裝命令列工具:
$ npm install -g thinkjs
然後使用thinkjs new demo建立一個新專案。為了確保使用者錯誤操作導致現有檔案被覆蓋,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}
使用指令後,系統就開始建置專案了:
$ thinkjs new demo create : demo create : demo/package.json create : demo/.babelrc create : demo/.thinkjsrc create : demo/nginx.conf create : demo/pm2.json create : demo/.gitignore create : demo/README.md create : demo/www create : demo/www/development.js create : demo/www/production.js create : demo/www/testing.js create : demo/www/README.md create : demo/www/static create : demo/www/static/js create : demo/www/static/css create : demo/www/static/img create : demo/src create : demo/src/common/bootstrap create : demo/src/common/bootstrap/middleware.js create : demo/src/common/bootstrap/global.js create : demo/src/common/config create : demo/src/common/config/config.js create : demo/src/common/config/view.js create : demo/src/common/config/db.js create : demo/src/common/config/hook.js create : demo/src/common/config/session.js create : demo/src/common/config/error.js create : demo/src/common/config/env create : demo/src/common/config/env/development.js create : demo/src/common/config/env/testing.js create : demo/src/common/config/env/production.js create : demo/src/common/config/locale create : demo/src/common/config/locale/en.js create : demo/src/common/controller create : demo/src/common/controller/error.js create : demo/view/common create : demo/view/common/error_400.html create : demo/view/common/error_403.html create : demo/view/common/error_404.html create : demo/view/common/error_500.html create : demo/view/common/error_503.html create : demo/src/home/config create : demo/src/home/config/config.js create : demo/src/home/controller create : demo/src/home/controller/base.js create : demo/src/home/controller/index.js create : demo/src/home/logic create : demo/src/home/logic/index.js create : demo/src/home/model create : demo/src/home/model/index.js create : demo/view/home create : demo/view/home/index_index.html enter path: $ cd demo install dependencies: $ npm install run the app: $ npm start
要注意的是,新建專案的時候需要好多babel,所以專案的建置會比較慢,依賴的套件主要有:
"dependencies": { "thinkjs": "2.2.x", "babel-runtime": "6.x.x", "source-map-support": "0.4.0" },
.├── README.md ├── app │ ├── common │ │ ├── bootstrap │ │ ├── config │ │ └── controller │ └── home │ ├── config │ ├── controller │ ├── logic │ └── model ├── nginx.conf ├── package.json ├── pm2.json ├── src │ ├── common │ │ ├── bootstrap │ │ ├── config │ │ └── controller │ └── home │ ├── config │ ├── controller │ ├── logic │ └── model ├── tree.txt ├── view │ ├── common │ │ ├── error_400.html │ │ ├── error_403.html │ │ ├── error_404.html │ │ ├── error_500.html │ │ └── error_503.html │ └── home │ └── index_index.html └── www ├── README.md ├── development.js ├── production.js ├── static │ ├── css │ ├── img │ └── js └── testing.js388 directories, 1381 files
1)啟動指令
npm start
那使用start後系統做了什麼呢?
"scripts": { "start": "node www/development.js", "compile": "babel src/ --out-dir app/", "watch-compile": "node -e \"console.log('<npm run watch-compile> no longer need, use <npm start> command direct.');console.log();\"", "watch": "npm run watch-compile" },
即使用Node執行www/development.js,這是env環境處理,thinkjs採用了3中env,比較常見的有:
development 開發模式
production 線上模式
testing 測試模式
thinkjs是把www當成node項目目錄,而www下的static才是靜態資源檔案目錄。 www/development.js目錄如下:
var instance = new thinkjs({ APP_PATH: rootPath + path.sep + 'app', RUNTIME_PATH: rootPath + path.sep + 'runtime', ROOT_PATH: rootPath, RESOURCE_PATH: __dirname, env: 'development'});
當然,可以使用「tree src -L 3」 指令來檢視專案的目錄:
$ tree src -L 3 src ├── common │ ├── bootstrap │ │ ├── global.js │ │ └── middleware.js │ ├── config │ │ ├── config.js │ │ ├── db.js │ │ ├── env │ │ ├── error.js │ │ ├── hook.js │ │ ├── locale │ │ ├── session.js │ │ └── view.js │ └── controller │ └── error.js ├── home │ ├── config │ │ └── config.js │ ├── controller │ │ ├── base.js │ │ └── index.js │ ├── logic │ │ └── index.js │ └── model │ └── index.js16 directories, 19 files
常見模組設定(後文會具體涉及) :
$ thinkjs module topic(能创建不能删除,略遗憾) create : src/topic/config create : src/topic/config/config.js create : src/topic/controller create : src/topic/controller/base.js create : src/topic/controller/index.js create : src/topic/logic create : src/topic/logic/index.js create : src/topic/model create : src/topic/model/index.js exist : /Users/sang/workspace/github/nodewebframework/demo/view/topic/index_index.html
此時目錄結構如下:
src ├── common ├── home └── topic
3)業務模組目錄
├── home │ ├── config │ │ └── config.js │ ├── controller │ │ ├── base.js │ │ └── index.js │ ├── logic │ │ └── index.js │ └── model │ └── index.js
4)路由與view識別 路由識別,預設根據 模組/控制器/操作/參數1/參數1值/參數2/參數2值 其實就是一個約定。
例如/解析為:
預設模組是home
控制是index
#操作是indexAction
那如果再來一個呢?
'use strict';import Base from './base.js';export default class extends Base { /** * index action * @return {Promise} [] */ indexAction(){ //auto render template file index_index.html return this.display(); } myAction(){ //auto render template file index_index.html return this.display(); }}
增加myAction,報錯[Error] Error: can't find template file /Users/sang/workspace/github/nodewebframework/demo/view/home/index_my.html
#將view /home/index_index.html複製為view/home/index_my.html。原理是my要對應index_my.html模組。即index是controller,而my是action。
理解了這個,你會覺得index_index這樣的命名也不是很怪異了。剩下的就是view編寫之類的,此處就不在熬述。
前面提到了,開發階段採用babel寫的,所以效率不會很高。
$ autocannon -c 100 -d 5 -p 10 localhost:8360Running 5s test @ http://localhost:8360100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 108.9 201.32 866 Req/Sec 891.8 148.37 1000 Bytes/Sec 417.79 kB 50.76 kB 458.75 kB 4k requests in 5s, 2.09 MB read
點慘,對吧?但這就是開發模式啊,我們一定要拿線上的production模式來測試。
$ npm run compile $ node www/production.js $ autocannon -c 100 -d 5 -p 10 localhost:8360Running 5s test @ http://localhost:8360100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 61.76 124.71 763 Req/Sec 1567.2 734.94 1993 Bytes/Sec 679.12 kB 242.25 kB 884.74 kB 8k requests in 5s, 3.4 MB read $ autocannon -c 100 -d 5 -p 10 localhost:8360Running 5s test @ http://localhost:8360100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 54.65 105.47 707 Req/Sec 1813.4 368.21 1999 Bytes/Sec 807.73 kB 156.09 kB 917.5 kB 9k requests in 5s, 4.09 MB read $ autocannon -c 100 -d 5 -p 10 localhost:8360Running 5s test @ http://localhost:8360100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 54.14 89.81 465 Req/Sec 1816.4 319.14 2000 Bytes/Sec 914.23 kB 145.96 kB 1.05 MB 9k requests in 5s, 4.55 MB read
下面以同樣的功能express + ejs模板的方式。
$ autocannon -c 100 -d 5 -p 10 localhost:3000Running 5s test @ http://localhost:3000100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 53.85 177.72 1309 Req/Sec 1728 385.85 2075 Bytes/Sec 702.87 kB 159.56 kB 851.97 kB 9k requests in 5s, 3.53 MB read $ autocannon -c 100 -d 5 -p 10 localhost:3000Running 5s test @ http://localhost:3000100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 46.06 141.52 739 Req/Sec 2061.2 320.53 2275 Bytes/Sec 842.14 kB 134.95 kB 950.27 kB 10k requests in 5s, 4.2 MB read $ autocannon -c 100 -d 5 -p 10 localhost:3000Running 5s test @ http://localhost:3000100 connections with 10 pipelining factor Stat Avg Stdev Max Latency (ms) 45.97 139.58 620 Req/Sec 2059.4 122.93 2167 Bytes/Sec 829.03 kB 52.43 kB 884.74 kB 10k requests in 5s, 4.2 MB read
建立專案之後,基本的程式碼框架已經建立起來了,其中預設的 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 連接和訊息囤積發送,還要處理多用戶購買相應服務套餐、統計連接數、統計下行流量、進行連接鑑權等。通常包含的模組如下:
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/ # 消息队列
線上教育或直播平台通常具備即時音視訊上傳、轉碼、儲存、廣播等硬性要求,因此系統除了管理相關課件、學生、教師、選課等,也要負責處理相關媒體文件。
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/ # 消息队列
官網是這麼描述設定檔載入順序的:框架預設的設定-> 專案模式下框架設定-> 專案公共設定->專案模式下的公共配置-> 模組下的配置。
第三个和第四个则是在不同的项目创建模式下的默认 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 加载配置文件是有顺序的!!!多个配置文件最终会在 thinkjs 运行时被全部加载,并合并在一起。所以当存在多个配置文件时,需要注意配置参数的 key(即属性名)尽量不要重复,因为按照加载顺序,后加载的 key 的值会覆盖先加载的 key 的值,导致出现不希望的结果。
举例来说,有两个配置文件 src/common/config/assets.js 和 src/home/config/assets.js,
// src/common/config/assets.jsexport default { "site_title": "my site"};// src/home/config/assets.jsexport default { "site_title": "my test"};// src/home/controller/index.jslet assets = this.config('assets');let siteTitle = assets['site_title'];console.log('siteTitle is: ', siteTitle); // my test
开发时的工作代码都在 src 下面,运行时才会编译到 app 下面成为运行脚本(经过 Babel 编译),如果不想自己写的各种注释也出现在 app 下面的代码中,可以修改项目目录下的一个隐藏文件 .babelrc 增加相应 comments 参数。
{ "presets": [ ["es2015", {"loose": true}], "stage-1" ], "plugins": ["transform-runtime"], "sourceMaps": true, "comments": false # <-- 就是这个参数}
目前,thinkJs支持两种控制器:普通的控制器和多级控制器。 支持__before和__after这样的回调钩子,对于app和controller控制来说是非常实用的。使用co来实现也是可圈可点,此处如果使用koa可以更加优雅。例如:
class PathController extends BaseController { constructor(app, ctx, next) { super(app, ctx, next) this.path = '/c' // this.global_filter.push('custom_filter') this.post_filter = [this.log] } before() { } log(ctx, next) { ctx.someText = 'some' // console.log('before') return next().then(function(){ // console.log('after') }) } post(req, res) { console.log(this.ctx.someText) var a = this.reqbody.a return res.body = this.ctx.someText } after() { }}
pm2 (官网 http://pm2.keymetrics.io)是一个优秀的 Node.js 进程管理器。thinkjs 推荐使用 pm2 来管理项目运行,并自动生成了 pm2 的配置文件 pm2.json 。
它的强大之处在于不仅可以作为 Node.js 项目的守护进程,还具备可配置化启动、分布式支持、内存监控、热重载(优雅重载)、支持数据统计、运行日志记录、实时运行监控、API 和脚本支持等强大的特性。
默认生成的 pm2 配置文件不含日志记录部分,如果不单独配置,pm2 的日志将会保存在安装目录中,查找起来很不方便。普遍的做法是:在项目目录下建立 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的后缀
主要优势:
完全自己实现,对已有框架很少借鉴
内置各种adapter,db,中间件,hook,插件,非常丰富,all in one 比组装更适合新手
遵循mvc和coc
使用最潮的es6/es7/ts特性,对aysnc函数,exports等都非常好的支持
支持i18n等实用功能
内置pm2和nginx集成,部署方便
有自己的脚手架,稍弱
性能不错,虽然比express稍弱,但功能强大许多
测试丰富,代码质量有保障
文档健全,是经过设计的,支持多语言
背后有75团和李成银支持,最近一周内有更新,代码提交2600+,35人贡献,整体来说算健康
以上是前端框架ThinkJS框架詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!