精华 sails vs meteor之sails篇
发布于 9 年前 作者 i5ting 10870 次浏览 最后一次编辑是 8 年前 来自 分享

看一下sails的特性

安装

npm install -g sails

很简单就可以安装了。

看一下它的帮助

 sails --help

  Usage: sails [command]

  Commands:

    version               
    lift [options]        
    new [options] [path_to_new_app]
    generate              
    console               
    consle                
    consloe               
    c                     
    www                   
    debug                 
    configure             
    help                  
    *                     

  Options:

    -h, --help     output usage information
    -v, --version  output the version number
    --silent       
    --verbose      
    --silly  

这是它的cli的全部功能

  • new 是根据模板创建项目
  • generate 是教授叫生成
  • lift 是启动服务器

了解这3个基本上就可以了。

如果你想进一步了解,可以继续看help

 sails lift --help

  Usage: lift [options]

  Options:

    -h, --help     output usage information
    --prod         
    --port [port]  

创建一个项目看看

sails new helloworld
cd helloworld 
sails lift

我们需要看一下它的目录结构

➜  helloworld  tree -L 2    
.
├── Gruntfile.js
├── README.md
├── api
│   ├── controllers
│   ├── models
│   ├── policies
│   ├── responses
│   └── services
├── app.js
├── assets
│   ├── favicon.ico
│   ├── images
│   ├── js
│   ├── robots.txt
│   ├── styles
│   └── templates
├── config
│   ├── blueprints.js
│   ├── bootstrap.js
│   ├── connections.js
│   ├── cors.js
│   ├── csrf.js
│   ├── env
│   ├── globals.js
│   ├── http.js
│   ├── i18n.js
│   ├── local.js
│   ├── locales
│   ├── log.js
│   ├── models.js
│   ├── policies.js
│   ├── routes.js
│   ├── session.js
│   ├── sockets.js
│   └── views.js
├── node_modules
│   ├── ejs -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/ejs
│   ├── grunt -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt
│   ├── grunt-contrib-clean -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-clean
│   ├── grunt-contrib-coffee -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-coffee
│   ├── grunt-contrib-concat -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-concat
│   ├── grunt-contrib-copy -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-copy
│   ├── grunt-contrib-cssmin -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-cssmin
│   ├── grunt-contrib-jst -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-jst
│   ├── grunt-contrib-less -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-less
│   ├── grunt-contrib-uglify -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-uglify
│   ├── grunt-contrib-watch -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-contrib-watch
│   ├── grunt-sails-linker -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-sails-linker
│   ├── grunt-sync -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/grunt-sync
│   ├── include-all -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/include-all
│   ├── rc -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/rc
│   ├── sails -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails
│   └── sails-disk -> /Users/sang/.nvm/v0.10.38/lib/node_modules/sails/node_modules/sails-disk
├── package.json
├── tasks
│   ├── README.md
│   ├── config
│   ├── pipeline.js
│   └── register
└── views
    ├── 403.ejs
    ├── 404.ejs
    ├── 500.ejs
    ├── homepage.ejs
    └── layout.ejs

36 directories, 29 files

目录说明

app.js是入口,和express类似,但你看不到任何express的影子,它把东西都抽象到module里了,一般人看起来是有点难于理解的。

自己的代码要写在api目录里

├── api
│   ├── controllers
│   ├── models
│   ├── policies
│   ├── responses
│   └── services

而rails是在app目录里。sails放到api里,可能是现在写api比较多,2点好处

  • 前后端分离
  • 为移动端提供api

这命名也是比较好理解的

  • controllers和models是mvc里的m和c
  • services 一般是多model相关的业务操作,它只在controller里调用
  • responses比较有意思,它实际上是给res服务器响应对象增加方法,比如定义个aaa方法,你就可以res.aaa()了,对于扩展res是有好处的,算一个小亮点
  • policies 是权限控制部分,说白了也还是中间件,config.policies.js里声明权限,相信会玩死很多人,简单的acl还不如自己写

至此,核心的特性已经从目录看的差不多了。

node_modules

一般项目里做模块依赖,很烦。

rails里的bundle install也很烦。。。

但是sails利用软连接,把依赖的模块放到自己的npm安装目录,然后创建软连接,这样就可以在sails new之后,里面启动服务器,无需安装任何模块,这一点还是值得借鉴的

views

目录和express一样,它的默认模板引擎是ejs

/**
 * View Engine Configuration
 * (sails.config.views)
 *
 * Server-sent views are a classic and effective way to get your app up
 * and running. Views are normally served from controllers.  Below, you can
 * configure your templating language/framework of choice and configure
 * Sails' layout support.
 *
 * For more information on views and layouts, check out:
 * http://sailsjs.org/#!/documentation/concepts/Views
 */

module.exports.views = {
  engine: 'ejs',
  layout: 'layout',
  partials: false
};

各取所需吧,爱用啥用啥,比如又要掀起一场口水打仗了。。。。

assets

asset pipeline其实最早也是rails里的概念,可以将JS和CSS合并和压缩

打开package.json

"grunt": "0.4.2",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-coffee": "~0.10.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-cssmin": "~0.9.0",
"grunt-contrib-jst": "~0.6.0",
"grunt-contrib-less": "0.11.1",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-sails-linker": "~0.9.5",
"grunt-sync": "~0.0.4",

从这里基本可以看出它的功能

  • js支持coffeescript
  • css支持less
  • 常用grunt操作,clean是清理,concat是合并,copy是复制,cssmin是压缩css,uglify是压缩js,watch是检测文件变动,sync应该是类似livereload之类的模块

后来发现它的文档里也有

Here are a few things that the default Grunt configuration in Sails does to help you out:

  • Automatic LESS compilation
  • Automatic JST compilation
  • Automatic Coffeescript compilation
  • Optional automatic asset injection, minification, and concatenation
  • Creation of a web ready public directory
  • File watching and syncing
  • Optimization of assets in production

多了一个jst编译,是grunt-contrib-jst做的事儿,其他大致一样

默认它是没有grunt-cli模块的,需要自己安装

npm install -g grunt-cli

然后执行grunt命令

➜  helloworld  grunt       
Running "clean:dev" (clean) task
Cleaning .tmp/public...OK

Running "jst:dev" (jst) task
>> Destination not written because compiled files were empty.

Running "less:dev" (less) task
File .tmp/public/styles/importer.css created: 0 B → 619 B

Running "copy:dev" (copy) task
Copied 3 files

Running "coffee:dev" (coffee) task

Running "sails-linker:devJs" (sails-linker) task
padding length 4
File "views/layout.ejs" updated.

Running "sails-linker:devStyles" (sails-linker) task
padding length 4
File "views/layout.ejs" updated.

Running "sails-linker:devTpl" (sails-linker) task
padding length 4
File "views/layout.ejs" updated.

Running "sails-linker:devJsJade" (sails-linker) task

Running "sails-linker:devStylesJade" (sails-linker) task

Running "sails-linker:devTplJade" (sails-linker) task

Running "watch" task
Waiting...

这里就是grunt的tasks了,没有啥可说的,我不是很喜欢grunt,我更喜欢gulp,sails默认是grunt,但文档里有有gulp版本的,可以去试试

另外要说明的是上线的时候,静态资源处理

  • 要么cdn
  • 要么nginx反向代理

这东西的价值就非常好了。

config

太多了,蛋疼。。。。

console

sails console

是通过命令行来处理数据的,一般简单测试会用

测试模型以及orm方法还是很爽的

来个例子玩玩吧

生成controller玩玩

sails generate controller comment create destroy tag like

生成的代码

/**
 * CommentController
 *
 * @description :: Server-side logic for managing comments
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {



  /**
   * `CommentController.create()`
   */
  create: function (req, res) {
    return res.json({
      todo: 'create() is not implemented yet!'
    });
  },


  /**
   * `CommentController.destroy()`
   */
  destroy: function (req, res) {
    return res.json({
      todo: 'destroy() is not implemented yet!'
    });
  },


  /**
   * `CommentController.tag()`
   */
  tag: function (req, res) {
    return res.json({
      todo: 'tag() is not implemented yet!'
    });
  },


  /**
   * `CommentController.like()`
   */
  like: function (req, res) {
    return res.json({
      todo: 'like() is not implemented yet!'
    });
  }
};

这种意义不是很大。。。

生成模型

sails generate model user name:string email:string password:string

基于Waterline的,除了可以适配多个db外,没看出啥特别的,写法一点也不好

如果直接生成api呢

➜  helloworld  sails generate api sssd sdf jklsdf werjk jlksd sd 
info: Created a new api!

擦,生成SssdController,每一个属性生成一个方法

Sssd model里只有属性对。。。。哭了

另外把路由配置在config.routes.js里,声明式做法也蛮蛋疼的,太麻烦了。。。。

另外说基于blueprints的restful api,恕我愚钝,没太看明白

难道

 sails generate api dentist

所有的代码都隐掉,你无法做任何修改么?

orm

  • 强大的关联
  • console 调试

如果一个orm,在js的语法下,兼容Any database,你说能不恶心么?把nosql和rdbms搞到一起,Waterline也是醉了。。。

他们还自己吹牛

  • activerecord
  • hibernate

类的。。。

凑合用吧

总结

sails能做到这样已经很不错了,有很多点都是和rails概念类似,也很用心

但出于js语法以及各种db等,还是有很多难受的地方

项目选型思考

  • 如果有熟悉rails思想的人可以考虑用
  • 如果有大牛可以用
  • 如果是新手或者无人解决框架问题,还是老老实实的express吧

全文完

欢迎关注我的公众号【node全栈】

node全栈.png

28 回复

sails 很不错啊~

@i5ting 这几点捣鼓sails 框架,发现还是很多蛋疼不灵活的地方,决定不用了,自己基于express搭一套简单的mvc框架。

因为后台项目中需要orbc 权限管理,用sailsjs 的话 有一个sails-permissions, 但是这个项目还不完善。自己集成node_acl到sailsjs里面又各种 不便,所以决定不用了~~~~(>_<)~~~~

@jerrywu55 分享一下 rbac

我之前也研究了一段时间这个框架,sailsjs应该是node.js的web server库里面包含最完整解决方案的一个框架。 基于blueprints的restful api 是sailsjs的一个最大特点,其实就是默认下,create的api里面,自动生成rest的crud的router,并且不需要写一句代码,酒会自动操作data(当然自己要写一些权限相关的policy),并且也支持rest的多表关联的数据,比如:post /model/:id/associationModel 假如body的id已存在,就保存关系,如果不存在,则创建associationModel数据后,再保存关系,这些都是现成的,不需要自己实现。

@hcnode 多表关联是亮点

但是自动生成rest的crud的router,并且不需要写一句代码是有问题的,我不能一点也不该代码的,隐藏的东西(黑魔法)会让人很郁闷,新人更郁闷

@jerrywu55 我觉得还是挺灵活的,这个框架的机制尽量将所有功能都以config、或者hook等各种插件方式提供给开发者,权限管理就用它的polices方式就够用了,它的polices配置可以是多种形式配置,你想灵活一点,就用配置成一个controller的方法,运行时判断

@hcnode 恩,是的

我说的是,它一行代码不写就可以生成restful api(是在它的库里实现的),我如果想改里面的代码怎么办?

@i5ting 嗯,我说的是默认情况下,你可以有很多方式修改的,比如新建controller对应的方法,就会覆盖它的默认方法,或者在model的before、after注入事件中加入自己代码(比如注册用户时修改password属性对密码加密),或者也可以写自己的hook插件,覆盖它的router

@hcnode 哦,秒懂~~,哈哈,覆盖还是比较麻烦的,O(∩_∩)O谢谢

@i5ting 不客气哈,因为它的文档写的很好,我看得很舒服,所以我之前基本把它的文档看了一遍,然后自己试做了一个小应用。 另外我还写了一个叫deep-blueprint的hook,因为他的blueprint最多只能生成两层model的router,我改了一下,可以生成多级的router,比如:/users/:userid/projects/:projectid/todos/:todoid/comments/:commentid,并提供crud操作,并自动对层级关系验证。

为什么还能看到grunt,说好的gulp呢?

我不想用他的ORM 怎么破?

@hades 不想用就干脆用express或koa,sails 、django这类框架的重要价值(也是束缚)就是在他们的ORM上

@SoaringTiger 不喜欢他的ORM,自己弄express这类东西,又要作好多事。

Salils还算挺整体的

@hades thinkjs,值得你拥有

挺喜欢Sails,可能是过去有Rails背景吧。但是现在用了Mongoose,和Sails的ORM不兼容,所以一直也没用。Express挺好,多用一个框架,多很多学习和维护成本。

@hcnode post /model/:id/associationModel这种传参数是怎么搞的?

@shinygang 我写个简单的列子吧,创建sails app,然后按照这里上面的例子创建这两个api

sails new apptest
cd apptest
sails generate api user
sails generate api pet

分别修改/api/models/User.js 和/api/models/Pet.js替换成上面官方文档的的代码,然后执行

sails lift

1.创建一个pet: 屏幕快照 2015-07-06 下午4.10.17.png

2.创建一个user: 屏幕快照 2015-07-06 下午4.11.20.png

3.post /user/2创建的user返回的id/pets,参数id为1创建pet的id 屏幕快照 2015-07-06 下午4.12.12.png

4.或者你可以创建一个全新的pet 屏幕快照 2015-07-06 下午4.14.12.png

以上结果返回,会自动populate所有association的field,也就是会自动查询关联的表,并在结果里面返回。 sails的populate很方便,不需要自己查询关联表,并且支持传入关键字、分页的方式查询关联表。

@hcnode 谢谢指导,懂了,话说你这http请求工具可以分享下

@hcnode 老兄,再请教一下: test.png 我想添加一个已经存在的photo到product上,这样操作怎么不行?数据库我用的mongo

@shinygang 我试过mongo可以,无论参数是id还是_id都可以

屏幕快照 2015-07-06 下午10.09.44.png

@hcnode 能把deep-blueprint分享出来学习学习不?

@cnwang sails-hook-deepblueprints 花了两天时间重新整理一下,并写了一个sample

用前想想怎么解决并发问题,没有提供数据锁,transaction也难用的一逼, lock数据也没有方法提供,感觉sails的model如果换成sequelize用起来也许会好很多

回到顶部