We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ThinkJS 是奇舞团开源的一款 Node.js 框架 借助 Babel 编译, 可以大胆使用 ES6/7 特性开发 Web 项目, 是一款后端 MVC 全功能框架. 使用 async & await 让异步执行以同步的方式来书写, 这个 feel 倍爽... 与其他框架的对比 与 express/koa 对比 express/koa 是 2 个比较简单的框架,框架本身提供的功能比较简单,项目中需要借助大量的第三方插件才能完成项目的开发,所以灵活度比较高 与 sails 对比 sails 也是一个提供整套解决方案的 Node.js 框架,对数据库、REST API、安全方面也很多封装,使用起来比较方便。但 sails 对异步回调的问题还没有优化,还是使用 callback 的方式,给开发带来很大的不便,导致项目中无法较好的使用 ES6/7 特性。
ThinkJS 是奇舞团开源的一款 Node.js 框架
借助 Babel 编译, 可以大胆使用 ES6/7 特性开发 Web 项目, 是一款后端 MVC 全功能框架. 使用 async & await 让异步执行以同步的方式来书写, 这个 feel 倍爽...
async & await
与其他框架的对比
与 express/koa 对比
express/koa 是 2 个比较简单的框架,框架本身提供的功能比较简单,项目中需要借助大量的第三方插件才能完成项目的开发,所以灵活度比较高
与 sails 对比
sails 也是一个提供整套解决方案的 Node.js 框架,对数据库、REST API、安全方面也很多封装,使用起来比较方便。但 sails 对异步回调的问题还没有优化,还是使用 callback 的方式,给开发带来很大的不便,导致项目中无法较好的使用 ES6/7 特性。
如果你还是有点蒙, 那么提下与 ThinkJS 同类型(Node.js web application framework)的框架 Express, Koa, Sails, 你是不是就大概了解 ThinkJS 的作用了呢.
与 Express 和 Koa 相比, ThinkJS 更符合一个全功能的 Web 开发框架, 你可以使用 Express/Koa + xx 插件 + xx 模块 + ... 来达到和 ThinkJS 类似的功能, 但其中充满了诸多选择, 需要灵活搭配才能满足所有的需求, 也就是说由于经验的不足, 保不准你就掉坑里了. 而 ThinkJS 自带了 Web 开发的常用模块, 让你开箱即用, 省力省心.
Express/Koa + xx 插件 + xx 模块 + ...
ThinkJS 与 Sails 相比, 就差不多是同一个重量级别的框架了, 类似 Ruby on Rails.
以提升我们学习使用 TA 的兴趣
支持 ES6/7 特性 可以直接在项目里使用 ES6/7(Generator Function, Class, Async & Await)等特性,借助 Babel 编译,可稳定运行在 Node.js 环境上 支持丰富的数据库 支持 Mysql、SQLite、MongoDB 等常见的数据库,提供了很多简单易用、高度封装的方法,自动防止 SQL 注入 REST API 自动生成 REST API,而无需写任何的代码。也可以根据接口定制,隐藏部分数据和进行权限控制 丰富的 Adapter 快速切换 Cache、Store、Session、Template 等功能,而无需关心具体使用哪种方式 支持 WebSocket 支持 socket.io、SockJS 等常见的 WebSocket 客户端,而服务端代码始终保持一致 命令行调用 支持命令行方式调用 Action,方便执行定时任务 自动更新 开发模式下,文件修改后立即生效,无需重启 Node.js 服务 Hook & Middleware 系统提供了大量的钩子和中间件,可以方便地对请求进行控制和修改, 还有更多插件包含 Middleware 和 Adapter 支持多种项目环境 丰富的路由机制 详细的日志,如:请求日志、错误日志、性能日志 支持国际化和多主题 支持自定义多种错误页面,如:400,404,500,503 单元测试
支持 ES6/7 特性
可以直接在项目里使用 ES6/7(Generator Function, Class, Async & Await)等特性,借助 Babel 编译,可稳定运行在 Node.js 环境上
支持丰富的数据库
支持 Mysql、SQLite、MongoDB 等常见的数据库,提供了很多简单易用、高度封装的方法,自动防止 SQL 注入
REST API
自动生成 REST API,而无需写任何的代码。也可以根据接口定制,隐藏部分数据和进行权限控制
丰富的 Adapter
快速切换 Cache、Store、Session、Template 等功能,而无需关心具体使用哪种方式
支持 WebSocket
支持 socket.io、SockJS 等常见的 WebSocket 客户端,而服务端代码始终保持一致
命令行调用
支持命令行方式调用 Action,方便执行定时任务
自动更新
开发模式下,文件修改后立即生效,无需重启 Node.js 服务
Hook & Middleware
系统提供了大量的钩子和中间件,可以方便地对请求进行控制和修改, 还有更多插件包含 Middleware 和 Adapter
支持多种项目环境
丰富的路由机制
详细的日志,如:请求日志、错误日志、性能日志
支持国际化和多主题
支持自定义多种错误页面,如:400,404,500,503
单元测试
2.2.15 2016.12.01 2.0.0 2015.10.30 1.0.0 2014.09.22
2.2.15
2.0.0
1.0.0
大概了解下使用 ThinkJS 开发一个 Web 项目, TA 能提供什么功能, 能给我们带来什么好处, 是不是提高了我们的工作效率.
安装和创建新项目的细节大家请参考官网创建项目的文档, 我这里只是列下重要的命令和注意事项.
npm install thinkjs@2 -g thinkjs new thinkjs-demo cd thinkjs-demo npm install npm start
注意事项
>=0.12.0
4.2.1
[email protected]
2.2.12
src
app
最后打开浏览器, 访问 http://127.0.0.1:8360/ 即可
http://127.0.0.1:8360/
项目算是跑起来了, 但要真正的使用, 还需理解下 ThinkJS 的项目结构, 看下其中各个目录和文件的作用, 以便知道如何新增或者修改某些功能.
首先打开 src 目录, 看见项目目录是按照模块来划分的, 新创建的项目提供了两个模块
common
home
thinkjs module xxx
controller
config
model
thinkjs model home/user
logic
controller action
另外, view 为视图目录, 放置对应的模版文件, 支持国际化和多主题. www/static 用于放置静态资源文件. www/development.js, www/testing.js, www/production.js 分别为三套项目环境(开发/测试/生产)对应的入口启动文件.
view
www/static
www/development.js
www/testing.js
www/production.js
这些目录大概都搞清楚后, 接下来就是重点内容了: 一个 HTTP 请求过来最终是由哪段代码负责处理的呢?
例如: http://127.0.0.1:8360/test/index.html
http://127.0.0.1:8360/test/index.html
这就是路由的工作了, 当用户访问一个 URL 时, 最终执行哪个模块下哪个控制器的哪个操作, 这是由路由来解析后决定的.
首先路由会将 URL 解析为 pathname 例如: http://127.0.0.1:8360/test/index.html, 将 URL 进行解析(去除 host 信息)得到的 pathname 为 /test/index.html 然后会对 pathname 过滤 因为有时候为了搜索引擎优化或者一些其他的原因, URL 上会多加一些东西. 比如: 当前页面是一个动态页面, 但 URL 最后加了 .html, 这样对搜索引擎更加友好. 但这些在后续的路由解析中是无用的, 需要去除. 默认会去除配置的 pathname 前缀和后缀内容, 以及自动去除左右的 / // src/common/config/config.js pathname_prefix: "", pathname_suffix: ".html"
首先路由会将 URL 解析为 pathname
例如: http://127.0.0.1:8360/test/index.html, 将 URL 进行解析(去除 host 信息)得到的 pathname 为 /test/index.html
/test/index.html
然后会对 pathname 过滤
因为有时候为了搜索引擎优化或者一些其他的原因, URL 上会多加一些东西. 比如: 当前页面是一个动态页面, 但 URL 最后加了 .html, 这样对搜索引擎更加友好. 但这些在后续的路由解析中是无用的, 需要去除.
.html
默认会去除配置的 pathname 前缀和后缀内容, 以及自动去除左右的 /
/
// src/common/config/config.js pathname_prefix: "", pathname_suffix: ".html"
因此经过路由处理后, 会拿到干净的 pathname, 我们就可以根据这个 pathname 来判断执行哪个模块下哪个控制器的哪个操作了.
哪个模块下哪个控制器的哪个操作
例如
http://127.0.0.1:8360/test/index.html URL
/test/index.html 解析
test/index 过滤
test/index
路由识别默认根据 模块/控制器/操作/参数1/参数1值/参数2/参数2值 来识别过滤后的 pathname
模块/控制器/操作/参数1/参数1值/参数2/参数2值
当解析 pathname 没有对应的值时, 便使用对应的默认值
其中模块默认值为 home, controller 默认值为 index, action 默认值为 index, 这些值可以在 src/common/config/config.js 中进行修改 默认模块为 home 模块, 当解析用户的请求找不到模块时会自动对应到 home 下, 可以通过配 default_module 来修改默认模块 关于大小写转化 路由识别后, module、controller 和 action 值都会自动转为小写, 如果 action 值里有 _, 会作一些转化, 如: 假设识别后的 controller 值为 index, action 值为 user_add, 那么对应的 action 方法名为 userAddAction, 但模版名还是 index_user_add.html
其中模块默认值为 home, controller 默认值为 index, action 默认值为 index, 这些值可以在 src/common/config/config.js 中进行修改
index
src/common/config/config.js
默认模块为 home 模块, 当解析用户的请求找不到模块时会自动对应到 home 下, 可以通过配 default_module 来修改默认模块
default_module
关于大小写转化
路由识别后, module、controller 和 action 值都会自动转为小写, 如果 action 值里有 _, 会作一些转化, 如: 假设识别后的 controller 值为 index, action 值为 user_add, 那么对应的 action 方法名为 userAddAction, 但模版名还是 index_user_add.html
_
user_add
userAddAction
index_user_add.html
因此我们得知上面的 URL 会调用 test 模块(module)的 index 控制器(controller)的 index 操作(action)
即: src/test/controller/index.js#indexAction
src/test/controller/index.js#indexAction
默认的视图文件路径为 view/[module]/[controller]_[action].html 即 模块/控制器_操作.html
view/[module]/[controller]_[action].html
模块/控制器_操作.html
因此 display() 时对应的视图为: view/test/index_index.html
display()
view/test/index_index.html
如果项目里并没有这个模块或者这个模块被禁用了, 就会识别为默认模块. 例如: http://127.0.0.1:8360/foo/bar.html, 会识别为 src/home/controller/foo.js#barAction
http://127.0.0.1:8360/foo/bar.html
src/home/controller/foo.js#barAction
另外我们还可以自定义路由
默认的路由虽然看起来清晰明了, 解析起来也很简单, 但看起来不够简洁. 有时候需要更加简洁的路由, 这时候就需要使用自定义路由解析了, 路由配置文件为: src/common/config/route.js 正则路由 规则路由 静态路由 按模块来配置路由, 使用这种方式后, 通用模块里的路由配置不再配置具体的路由规则, 而是配置哪些规则命中到哪个模块, 再在对应模块下配置具体的路由规则
默认的路由虽然看起来清晰明了, 解析起来也很简单, 但看起来不够简洁. 有时候需要更加简洁的路由, 这时候就需要使用自定义路由解析了, 路由配置文件为: src/common/config/route.js
src/common/config/route.js
错误处理 扩展错误类型: 添加完错误后, 需要在对应地方调用显示错误才能让用户看到, 可以通过 think.statusAction 方法实现 return think.statusAction(600, this.http) REST API Controller 可以用很便捷的方式来创建 REST API, 创建后无需额外的代码即可响应 REST API 的处理, 同时也可以通过定制响应额外的需求 thinkjs controller home/ticket --rest 上面的命令表示在 home 模块下创建了一个 ticket 的 Rest Controller,该 Controller 用来处理资源 ticket 的请求, 资源名称和数据表名称是一一对应的. 注意继承的类是: think.controller.rest 多级控制器 对于很复杂的项目, 一层控制器有时候不能满足需求, 这个时候可以创建多级控制器, 如:src/test/controller/group/article.js, 这时解析到的控制器为二级, 具体为 group/article, Logic 和 View 的目录与此相同. 例如: http://127.0.0.1:8360/test/group/article/index.html
错误处理
扩展错误类型: 添加完错误后, 需要在对应地方调用显示错误才能让用户看到, 可以通过 think.statusAction 方法实现 return think.statusAction(600, this.http)
think.statusAction
return think.statusAction(600, this.http)
REST API Controller
可以用很便捷的方式来创建 REST API, 创建后无需额外的代码即可响应 REST API 的处理, 同时也可以通过定制响应额外的需求
thinkjs controller home/ticket --rest
上面的命令表示在 home 模块下创建了一个 ticket 的 Rest Controller,该 Controller 用来处理资源 ticket 的请求, 资源名称和数据表名称是一一对应的. 注意继承的类是: think.controller.rest
ticket
think.controller.rest
多级控制器
对于很复杂的项目, 一层控制器有时候不能满足需求, 这个时候可以创建多级控制器, 如:src/test/controller/group/article.js, 这时解析到的控制器为二级, 具体为 group/article, Logic 和 View 的目录与此相同. 例如: http://127.0.0.1:8360/test/group/article/index.html
src/test/controller/group/article.js
group/article
http://127.0.0.1:8360/test/group/article/index.html
下面是一个完整的 controller 示例, 列举了一般开发中所需要的功能
// src/foo/controller/bar.js // 控制器是一类操作的集合, 用来响应用户同一类的请求 export default class extends think.controller.base { // 前置操作: 在 action 调用之前自动调用 // 推荐放在一个 base controller 类中, 其他 controller 继承 base controller __before() { // 如果想在前置操作里阻止后续 action 代码继续执行 // 可以用 return this.end('__before') 之类的操作提前结束请求 console.log('controller __before'); } // 后置操作: 在 action 调用之后自动调用 __after() { // 如果 action 里阻止了后续的代码继续执行(用了 return), 则后置操作不会调用 console.log('controller __after'); } // 空操作: 当解析后的 URL 对应的控制器存在, 但 action 不存在时调用 // 一般不需要使用 __call() { console.log('controller __call'); return this.end('404'); } // 不指定 action 时默认用 indexAction 来处理这个请求 // http://127.0.0.1:8360/foo/bar/a/%E4%B8%AD%E6%96%87/b/2?c=123 indexAction() { // 获取 URL console.log('url', this.http.method, this.http.host, this.http.url); console.log('module/controller/action', this.http.module + '/' + this.http.controller + '.js#' + this.http.action + 'Action'); // 获取请求参数 console.log('pathparam-a', this.get('a')); console.log('pathparam-b', this.get('b')); console.log('urlparam-c', this.get('c')); console.log('GET param', this.get()); // 当上传文件时, 包含 form 表单中除开 file 类型的其他字段的值 console.log('POST param', this.post()); console.log('param', this.param()); // 上传的文件保存在临时目录(runtime/upload)中, 可以通过 path 属性看到 // 使用时需要将其移动到项目里的目录, 否则请求结束时会被删除 console.log('file', this.file()); // 获取模型数据 // 项目开发中, 经常要操作数据库, 如: 增删改查等操作. // 模型就是为了方便操作数据库进行的封装, 一个模型对应数据库中的一个数据表. // 模型文件不是必须存在, 如果没有自定义方法可以不创建模型文件, 实例化时会取模型基类的实例 let model = this.model('city'); // 操作模型 model.where({name: 'Kabul'}).select().then(function(rs) { console.log('model', model.name, model.schema, rs); }); // 指定 SQL 语句执行查询 this.model().query("SELECT * FROM city WHERE name = '%s'", 'Kabul').then(function(rs) { console.log(rs); }); // 变量赋值和模版渲染 this.assign({ title: '我们一起来学习 ThinkJS', author: 'Sun' }); // 默认模版变量: 框架自动向模版里注册了 http, controller, config // 例如 <%- http.url %> <%- controller.ip() %> <%- config.port %> <%- config.db.type %> return this.display(); // return this.end('随便输出点什么内容'); // 返回 JSON/JSONP // return this.json({a: 1}); // return this.jsonp({a: 1}); // 返回格式化的正常数据, 一般是操作成功后输出 // return this.success({a: 1}); // 返回格式化的异常数据, 一般是操作失败后输出 // return this.fail(1000, 'error...', {e: 1}); // 跳转页面 // return this.redirect('https://thinkjs.org'); } // http://127.0.0.1:8360/foo/bar/baz?callback=abc // http://127.0.0.1:8360/模块/控制器/操作 bazAction() { return this.jsonp({baz: 'hello thinkjs'}); } }
支持的数据类型有: boolean、string、int、float、array、object, 默认为 string. 内置了很多校验类型 扩展校验类型 如果默认支持的校验类型不能满足需求, 可以在 src/common/bootstrap/validate.js 中通过 think.validate 方法对校验类型进行扩展
支持的数据类型有: boolean、string、int、float、array、object, 默认为 string. 内置了很多校验类型
boolean
string
int
float
array
object
扩展校验类型
如果默认支持的校验类型不能满足需求, 可以在 src/common/bootstrap/validate.js 中通过 think.validate 方法对校验类型进行扩展
src/common/bootstrap/validate.js
think.validate
下面是一个完整的 logic 示例, 列举了一般开发中所需要的功能
// src/foo/logic/bar.js // Logic 用于校验类(例如请求类型, 请求参数数据校验)的逻辑处理 // 与控制器里的 action 一一对应 // 系统在调用控制器里的 action 之前会自动调用 Logic 里的 action export default class extends think.logic.base { indexAction() { // 验证请求类型 this.allowMethods = 'get,post'; // 自动校验, 如果有错误则直接输出 JSON 格式的错误信息 // this.rules = {}; let rules = { field1: { required: true, // 要去掉这个属性才能让参数变成不是必要的 int: [10, 20], // 多个参数以数组形式传入 // default: 20, post: true // 指定获取数据的方式 } }; // 验证请求参数 let flag = this.validate(rules); // 验证通过返回 true if(!flag) { return this.fail('validate error', this.errors()); // 在模版中显示错误 // return this.display(); } } }
视图配置可以在 src/common/config/view.js 中修改, 如果想每个模块有独立的视图目录,将配置 root_path 修改为空即可. 那么 http://127.0.0.1:8360/foo/bar.html 会去找 src/foo/view/bar_index.html 修改连接符 默认控制器和操作之间的连接符是 _, 文件名类似为 index_index.html, 如果想将控制器作为一层目录的话, 如: index/index.html, 可以将连接符修改为 file_depr: "/".
视图配置可以在 src/common/config/view.js 中修改, 如果想每个模块有独立的视图目录,将配置 root_path 修改为空即可.
src/common/config/view.js
root_path
那么 http://127.0.0.1:8360/foo/bar.html 会去找 src/foo/view/bar_index.html
src/foo/view/bar_index.html
修改连接符
默认控制器和操作之间的连接符是 _, 文件名类似为 index_index.html, 如果想将控制器作为一层目录的话, 如: index/index.html, 可以将连接符修改为 file_depr: "/".
index_index.html
index/index.html
file_depr: "/"
在 VS Code(v1.7+)下断点调试, 设置调试配置后, 在源码中直接添加断点即可调试
可以在不同的模块和不同的项目环境下使用不同的配置, 且这些配置在服务启动时就已经生效 可以在每个模块下定义不同的配置. 其中 common 模块下定义一些通用的配置, 其他模块下配置会继承 common 下的配置. 如: home 模块下的最终配置是将 common 和 home 模块下配置合并的结果. 支持多种级别的配置文件, 会按如下顺序进行读取: 框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置 默认支持 3 种项目环境, 可以根据不同的环境进行配置, 以满足不同情况下的配置需要. 项目里也可以扩展其他的环境, 当前使用哪种环境可以在 入口文件 中设置, 设置 env 值即可. 不同项目环境差异化配置一般不是很多, 所以放在一个文件中定义. 这时候如果要修改一个独立功能的配置, 就需要将独立功能对应的 key 带上. 如修改数据库配置需要将数据库对应的名称 db 带上. 扩展配置 项目里可以根据需要扩展配置, 扩展配置只需在 src/common/config/ 建立对应的文件即可, 例如: src/common/config/foo.js, 这样就可以通过 think.config('foo') 来获取对应的配置了
可以在不同的模块和不同的项目环境下使用不同的配置, 且这些配置在服务启动时就已经生效
可以在每个模块下定义不同的配置. 其中 common 模块下定义一些通用的配置, 其他模块下配置会继承 common 下的配置. 如: home 模块下的最终配置是将 common 和 home 模块下配置合并的结果.
支持多种级别的配置文件, 会按如下顺序进行读取: 框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置
框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置
默认支持 3 种项目环境, 可以根据不同的环境进行配置, 以满足不同情况下的配置需要. 项目里也可以扩展其他的环境, 当前使用哪种环境可以在 入口文件 中设置, 设置 env 值即可.
入口文件
env
不同项目环境差异化配置一般不是很多, 所以放在一个文件中定义. 这时候如果要修改一个独立功能的配置, 就需要将独立功能对应的 key 带上. 如修改数据库配置需要将数据库对应的名称 db 带上.
key
db
扩展配置
项目里可以根据需要扩展配置, 扩展配置只需在 src/common/config/ 建立对应的文件即可, 例如: src/common/config/foo.js, 这样就可以通过 think.config('foo') 来获取对应的配置了
src/common/config/
src/common/config/foo.js
think.config('foo')
数据库配置和常用的CRUD 操作以及关联模型和查询缓存
文件路径必须小写, 因为有些操作系统对文件路径不区分大小写, 有些又区分大小写, 因此统一必须小写 不要使用 constrcutor 方法, 而是统一使用 init 使用 async/await 通过 Babel 编译来使用 ES6 语法开发
constrcutor
init
async/await
上线前执行 npm run compile 命令,将 src/ 目录编译到 app/ 目录,然后将 app/ 目录下的文件上线 使用 PM2 管理服务 注意 pm2.json 中的 "cwd": "F:/tmp/thinkjs-demo" 路径必须使用 / 来分隔, 否则 PM2 启动会报错: Error: ENOENT: no such file or directory, uv_chdir 使用 nginx 做反向代理 同时最好设置 ThinkJS 禁止端口访问和关闭 ThinkJS 本身的静态资源处理
上线前执行 npm run compile 命令,将 src/ 目录编译到 app/ 目录,然后将 app/ 目录下的文件上线
npm run compile
src/
app/
使用 PM2 管理服务
注意 pm2.json 中的 "cwd": "F:/tmp/thinkjs-demo" 路径必须使用 / 来分隔, 否则 PM2 启动会报错: Error: ENOENT: no such file or directory, uv_chdir
pm2.json
"cwd": "F:/tmp/thinkjs-demo"
Error: ENOENT: no such file or directory, uv_chdir
使用 nginx 做反向代理
同时最好设置 ThinkJS 禁止端口访问和关闭 ThinkJS 本身的静态资源处理
默认使用的 www/development.js 作为启动脚本, 因此你会发现通过 PM2 启动项目后, 修改 src 中的源码自动编译到 app 目录了, 就相对于代码已经重新部署生效了.
PM2
因此当你运行了 pm2 startOrReload pm2.json 后, 想修改为 www/production.js 作为启动脚本, 需要先 pm2 stop pm2.json 再 pm2 delete pm2.json, 再修改 pm2.json 中的 script, 最后 pm2 startOrReload pm2.json 来重新启动, 否则你会发现修改了 script 没有效果, 还是用的以前的那份配置.
pm2 startOrReload pm2.json
pm2 stop pm2.json
pm2 delete pm2.json
script
这样当你再修改 src 中的源码时, 需要手动 npm run compile, 然后还需要 pm2 startOrReload pm2.json 来重新部署.
用来解决一类功能的多种实现, 如: 支持多种数据库,支持多种模版引擎等. 系统默认支持的 Adapter 有: Cache, Session, WebSocket, DB, Template.
Cache
Session
WebSocket
DB
Template
在请求处理中埋很多 hook, 每个 hook 串行执行一系列的 middleware, 最终完成一个请求的逻辑处理 建议使用追加的方式配置 middleware, 系统的 middleware 名称可能在后续的版本中有所修改
在请求处理中埋很多 hook, 每个 hook 串行执行一系列的 middleware, 最终完成一个请求的逻辑处理
建议使用追加的方式配置 middleware, 系统的 middleware 名称可能在后续的版本中有所修改
系统提供了很多常量供项目里使用, 利用这些常量可以方便的访问对应的文件, 还可以通过入口文件和启动文件在项目里定义额外的路径常量
启动文件
如何修改服务监听的端口 默认监听的端口为 8360, 可以通过配置文件 src/common/config/config.js 来修改: port: 1234 并行处理 使用 async/await 来处理异步时, 是串行执行的, 但很多场景下我们需要并行处理, 此时可以结合 Promise.all 来处理 如何在不同的环境下使用不同的配置/如何跨模块调用/如何请求其他接口数据/如何输出图片/修改请求超时时间/如何捕获异常/如何忽略异常/如何开启 cluster/如何让 Action 只允许命令行调用/设置跨域头信息(CORS)/如何让用户登录后才能访问
如何修改服务监听的端口
默认监听的端口为 8360, 可以通过配置文件 src/common/config/config.js 来修改: port: 1234
port: 1234
并行处理
使用 async/await 来处理异步时, 是串行执行的, 但很多场景下我们需要并行处理, 此时可以结合 Promise.all 来处理
Promise.all
如何在不同的环境下使用不同的配置/如何跨模块调用/如何请求其他接口数据/如何输出图片/修改请求超时时间/如何捕获异常/如何忽略异常/如何开启 cluster/如何让 Action 只允许命令行调用/设置跨域头信息(CORS)/如何让用户登录后才能访问
示例/教程
demos for ThinkJS 2
遇到问题善用文档搜索功能
推荐模块
网络请求(superagent) 日志(log4j) 日期处理(moment) 编码转化(iconv-lite) 图像处理(gm) 框架(其他 Web 框架) 调试(node-inspector) 单元测试(mocha) 服务管理(pm2) 邮件(nodemailer) 定时任务(node-crontab)
ThinkJS 这么玩了一圈下来, 我们发现其实对于前端来说, 后端也没有想象中的那么难, 还能将 ES6/7 这样的新技术运用到项目中, 而不像在浏览器上随便用个什么新特性都畏畏缩缩, 担心兼容性问题, 何乐而不为呢?
ES6/7
如果你以前感觉前后端跨界似鸿沟般难以逾越, 现在借助 ThinkJS 这么智能的框架, 前端也可以很块上手做后端的开发, 什么接口, 什么访问数据库都是小 case. 况且基于 Node.js 平台从开发到上线到运维都已经很成熟了, 工具和生态圈都很完善而且很活跃, 大型互联网公司早就用于生产环境了, 这方面没有什么后顾之忧.
前端向后端迈进地主要的难点还是在于模型这一块, 对数据库比较陌生的前端多补补课, 把各种关联模型搞清楚, 不出几日已然就是全栈工程师了.
俗话说万事开头难, 最后我只想告诉大家: Node.js 已经彻底改变了前端, 扩大了前端的圈子, 每一个前端工程师都应该拿起这个有力的武器, 在这个前端最好的时代, 实现自己的理想.
The text was updated successfully, but these errors were encountered:
No branches or pull requests
简单介绍下 ThinkJS 是用来做什么的
如果你还是有点蒙, 那么提下与 ThinkJS 同类型(Node.js web application framework)的框架 Express, Koa, Sails, 你是不是就大概了解 ThinkJS 的作用了呢.
与 Express 和 Koa 相比, ThinkJS 更符合一个全功能的 Web 开发框架, 你可以使用
Express/Koa + xx 插件 + xx 模块 + ...
来达到和 ThinkJS 类似的功能, 但其中充满了诸多选择, 需要灵活搭配才能满足所有的需求, 也就是说由于经验的不足, 保不准你就掉坑里了. 而 ThinkJS 自带了 Web 开发的常用模块, 让你开箱即用, 省力省心.ThinkJS 与 Sails 相比, 就差不多是同一个重量级别的框架了, 类似 Ruby on Rails.
我们列一下 ThinkJS 更多的特性
以提升我们学习使用 TA 的兴趣
看看 ThinkJS 的版本历程
让我们试用一把尝尝鲜
大概了解下使用 ThinkJS 开发一个 Web 项目, TA 能提供什么功能, 能给我们带来什么好处, 是不是提高了我们的工作效率.
安装和创建新项目的细节大家请参考官网创建项目的文档, 我这里只是列下重要的命令和注意事项.
注意事项
>=0.12.0
, 建议将 Node.js 版本升级到4.2.1
或更高版本[email protected]
的版本, 以下实践都是基于2.2.15
的版本2.2.12
版本开始, 创建的项目默认为 ES6 模式src
目录下的文件编译到app
目录下最后打开浏览器, 访问
http://127.0.0.1:8360/
即可深入了解 ThinkJS 的各个功能模块
项目算是跑起来了, 但要真正的使用, 还需理解下 ThinkJS 的项目结构, 看下其中各个目录和文件的作用, 以便知道如何新增或者修改某些功能.
首先打开
src
目录, 看见项目目录是按照模块来划分的, 新创建的项目提供了两个模块common
通用模块, 用来放通用逻辑和配置信息的home
一个业务模块(默认模块), 要添加一个新的模块:thinkjs module xxx
controller
控制器, 一个 URL 对应一个 controller 下的一个 actionconfig
模块下的配置信息model
模型, 数据库相关操作, 创建模型:thinkjs model home/user
logic
逻辑处理, 每个controller action
执行前可以先进行逻辑校验, 可以包含: 参数是否合法、提交的数据是否正常、当前用户是否已经登录、当前用户是否有权限等, 这样可以降低 controller 里的 action 的复杂度. logic 里的 action 和控制器里的 action 一一对应, 系统在调用控制器里的 action 之前会自动调用 logic 里的 action另外,
view
为视图目录, 放置对应的模版文件, 支持国际化和多主题.www/static
用于放置静态资源文件.www/development.js
,www/testing.js
,www/production.js
分别为三套项目环境(开发/测试/生产)对应的入口启动文件.路由
这些目录大概都搞清楚后, 接下来就是重点内容了: 一个 HTTP 请求过来最终是由哪段代码负责处理的呢?
例如:
http://127.0.0.1:8360/test/index.html
这就是路由的工作了, 当用户访问一个 URL 时, 最终执行哪个模块下哪个控制器的哪个操作, 这是由路由来解析后决定的.
因此经过路由处理后, 会拿到干净的 pathname, 我们就可以根据这个 pathname 来判断执行
哪个模块下哪个控制器的哪个操作
了.例如
http://127.0.0.1:8360/test/index.html
URL/test/index.html
解析test/index
过滤路由识别默认根据
模块/控制器/操作/参数1/参数1值/参数2/参数2值
来识别过滤后的 pathname当解析 pathname 没有对应的值时, 便使用对应的默认值
因此我们得知上面的 URL 会调用 test 模块(module)的 index 控制器(controller)的 index 操作(action)
即:
src/test/controller/index.js#indexAction
默认的视图文件路径为
view/[module]/[controller]_[action].html
即模块/控制器_操作.html
因此
display()
时对应的视图为:view/test/index_index.html
如果项目里并没有这个模块或者这个模块被禁用了, 就会识别为默认模块. 例如:
http://127.0.0.1:8360/foo/bar.html
, 会识别为src/home/controller/foo.js#barAction
另外我们还可以自定义路由
控制器
下面是一个完整的 controller 示例, 列举了一般开发中所需要的功能
Logic
下面是一个完整的 logic 示例, 列举了一般开发中所需要的功能
视图
断点调试
配置
模型
代码规范
线上部署
默认使用的
www/development.js
作为启动脚本, 因此你会发现通过PM2
启动项目后, 修改src
中的源码自动编译到app
目录了, 就相对于代码已经重新部署生效了.因此当你运行了
pm2 startOrReload pm2.json
后, 想修改为www/production.js
作为启动脚本, 需要先pm2 stop pm2.json
再pm2 delete pm2.json
, 再修改pm2.json
中的script
, 最后pm2 startOrReload pm2.json
来重新启动, 否则你会发现修改了script
没有效果, 还是用的以前的那份配置.这样当你再修改
src
中的源码时, 需要手动npm run compile
, 然后还需要pm2 startOrReload pm2.json
来重新部署.Adapter
Middleware
路径常量
常见问题
更多资源
示例/教程
demos for ThinkJS 2
遇到问题善用文档搜索功能
推荐模块
总结
ThinkJS 这么玩了一圈下来, 我们发现其实对于前端来说, 后端也没有想象中的那么难, 还能将
ES6/7
这样的新技术运用到项目中, 而不像在浏览器上随便用个什么新特性都畏畏缩缩, 担心兼容性问题, 何乐而不为呢?如果你以前感觉前后端跨界似鸿沟般难以逾越, 现在借助 ThinkJS 这么智能的框架, 前端也可以很块上手做后端的开发, 什么接口, 什么访问数据库都是小 case. 况且基于 Node.js 平台从开发到上线到运维都已经很成熟了, 工具和生态圈都很完善而且很活跃, 大型互联网公司早就用于生产环境了, 这方面没有什么后顾之忧.
前端向后端迈进地主要的难点还是在于模型这一块, 对数据库比较陌生的前端多补补课, 把各种关联模型搞清楚, 不出几日已然就是全栈工程师了.
俗话说万事开头难, 最后我只想告诉大家: Node.js 已经彻底改变了前端, 扩大了前端的圈子, 每一个前端工程师都应该拿起这个有力的武器, 在这个前端最好的时代, 实现自己的理想.
The text was updated successfully, but these errors were encountered: