EmberJS 从恨到爱——如何使用 Ember 开发应用程序

nightire for 上海巧议网络科技有限公司 · 2016年10月27日 · 最后由 afly 回复于 2016年12月06日 · 17829 次阅读
本帖已被管理员设置为精华贴

前言

前方预警:这将是一篇长文,我尽可能把主题区分开并做到良好的排版,因此你可以根据标题来检索你感兴趣的部分。

不过在我展开之前,先得丢几句不是那么“干”的货。从恨到爱,这个标题源自于一位同行的文章,在这篇文章里 Ember 只是一个引子,但却因为作者对于 Ember 的态度所发生的转变而使得他怀疑自己“讨厌 React”的态度可能也是错的。

我自己对 Ember 的态度倒没有这位老兄这样的极端化,至少我没有恨过它。对于技术性的东西,如果让你产生了恨意,那多半是因为自己太蠢:要么掌握不了它的用法,要么没搞清楚它真正的用武之地。可是人非圣贤,主观的好恶是免不了的,如果因为工作环境的需要你不得不使用一些你不喜欢的工具,那么你要么从容应对化腐朽为神奇,要么另谋高就,寻找更加适合自己的团队。恨,是解决不了问题的,它只会污染你和你身边同事的情绪;而作为工程师,我们是天生擅长解决问题的那一群人,何去何从就要问问自己的内心了。

本文最大的受益群体应该是那些对 Ember 无感甚至有些讨厌 Ember 的人,并且你们因为工作或事其他什么原因不得不用这个框架(这么一说,真没多少人吧……),既不算喜欢又不能逃避,这的确挺煎熬的。那么我希望能够通过分享我们团队使用 Ember 的一些经验让你们对 Ember 的了解能更加完整一些深入一些,如果能让你们获得一些“啊哈”的瞬间那就更棒了,我相信用不了太久你们就能从恨它到爱上它,或者从路人转粉,我的一点心愿吧。

现在(2016 年末)的 Ember 足够成熟到值得推荐吗?

我认为是的。

当然也有业界专家们也这么看:

ember-mature-enough

上图截取自 2016 年 11 月发布的 ThoughtWorks 技术雷达白皮书,详情可见:https://www.thoughtworks.com/radar,有中文版的。

可以看出,在新的或是有持续进展的框架中,ThoughtWorks 对 Ember 成熟度的认同是最高的,和 React + Redux 同属一个级别——值得注意的是,React 算不上真正意义上的框架,即使搭配了 Redux 要达到 Ember 的完整度也还要花很多功夫的。

Angular 哪儿去了?v1 已经不再推荐了,v2 由于比较新,目前也很难下一个结论。我不否认 v2 有着一些很吸引人的特点,不过这不是什么“独占”的技术,需要的话我在 Ember 当中也可以容易的添加上它们。更重要的是非技术层面的观感,下面是一段引文:

You were part of the team at Angular, and you talk about “irreconcilable differences” between yourself and the team, could you talk a bit about that?

We disagreed on various technical choices which I felt wouldn’t be tenable in the real world, wouldn’t be flexible enough. But coming back to the business side of things, what I began to see when I worked there was that the entire development process was completely disconnected from the community. There was a lot of speak that went out that was “Thank you, we love our community…” and that was genuine, they really do, but when they went back to build version 2, there were no use cases or case studies coming from anyone, not even from inside Google. There were groups inside of Google using things that they could have done an official case study with, and that didn’t happen there and it didn’t happen publicly.

If you do a bit of research you’ll find that Angular is actually a subteam inside of something called GreenTea which is an internal app (specifically Google’s Adwords CRM). Really, that is the driver for Angular, and if Angular does anything at all, it’s going to be this one app. Because of how they’re set up there, Angular isn’t really this independent Google product that exists to do what people think it does. It does some of those things, but that whole business side is missing. It really exists because it’s funded internally by this other thing that has it’s own agenda.

-- Rob Eisenberg

捉虫:现在 Ruby China 的 markdown 无法正确处理引言的分段了

Rob Eisenberg 是 Aurelia 框架的作者(Aurelia 也在上图中有),同时也是 Ember 社区的活跃份子之一,最近 Ember Engines 的新功能就是他主写的。之前他曾经受邀加入了 Angular 2 开发组,主要负责新的路由系统,但后来他主动离开了。上面的引言来自于一次访谈,大概讲述了离开的原因。在这里我也无意展开去说什么道理,只是我觉得有些事情还是值得去了解一下的,所谓“兼听则明”吧,反正我一直对 Angular 的社区无感,个人意见。

这些事情对于一些人来说可能也无足轻重,但至少说明了部分业内人士对于 Ember 的评价是相当不错的,所以我认为它足够成熟,也足够让我向别人推荐。当然我们总是需要考虑实际的业务场景的,因此接着我就来说说:

什么情况下你不需要 Ember

咱一上来先说 Ember 不适用的地方,这样可以节省一些读者的时间。如果你觉得你现在做的事情和下面的描述比较接近的话,Ember 大概是无法给你带来什么特别的好处的。但如果你已经是一个经验丰富的 Ember 工程师,那么你也应该知道即使在这些场合之下 Ember 依然可以发挥它的优势,善于利用的话也可以改变一些典型的思路并获得出其不意的效果——这全看你对你做的事情的理解,不必强求。

而在你心里没什么谱的时候,下面这些情况是你可以不需要 Ember 的。

内容展示为主的网站

这个分类涵盖的范围极广,小到只有几个页面的官方网站,大到一个 CMS(比如现在遍地都是的网络小说网站)都算是以内容呈现和展示为主的网站。在过去十到二十年的时间里,互联网的主体内容就是这些,我们在日常获取绝大部份信息的渠道也正是这些。哪怕是今天,基于 Web 的应用程序这个概念炒得火热的 2016 年,我想至少八成以上的开发者做的事情也离不开这个范畴。这一类型的网站存在的时间足够长,大家对它的研究和探索也足够深入和广阔,因此能够把它做好的技术也是足够成熟和稳定的,用不用得着 Ember 真的是见仁见智的事情。在我看来,多数情况下不需要用到 Ember 也绰绰有余。有鉴于此,Ember 的用户基数很小在我看来一点儿也不奇怪。

但是近年来,Angular/React/Vue 等前端框架或工具的崛起吸引了很多开发者的目光,所以大家也都纷纷试水开始使用它们来开发这一类型的网站。在这个过程当中,那些基础好、善于钻研、并且对 web 的理解比较到位的人并不会觉得有什么不便,并且还能够从中发掘出这些新兴工具的闪光点,让它们能够为自己的日常开发起到更多的助益;反之也会有另外一部分人会觉得非常不适应,一面增加了自己学习的负担,一面却体会不到新工具带来的好处(注:这是客观存在的现象,而不是说一定要分出个高下来,各位看官请自行体会),于是会放弃它们回归到自己的舒适区域,这在我看来也是很正常的事情。

所以,你觉得新的工具在眼下帮不了你什么,那就不用它便是了,没必要产生一些额外的情绪,也没必要反感和排斥那些乐于探索新世界的人。想想前言里那位同行老司机吧,说不定有一天你也会产生同样的感受。另外,就算是停留在那些稳定舒适的技术区里,你就一定以为自己已经掌握的足够出色了吗?即使是那些今天看起来不那么 fancy 的工具和技术,它们所代表的基础技术素养也是极为重要的。我这里有几个例子,留着后面铺开了讲,下面再说说第二种:

互动式炫酷 UI 为主的网站

还有一些个网站本质上也属于内容呈现类的,但却不局限于传统的文本、图片等媒介,而是大量采用动画、音视频、绚丽的色彩、大胆的布局、前卫的交互技术,甚至包括 3D 特效等技术。这类网站可以看作是第一类的升级加强版,会给用户带来美妙到震撼的感官享受。擅长做这类网站的前端工程师也是值得敬佩的,因为他们往往也要花费大量的时间在学习和钻研前沿技术上面,并且他们还要擅长设计,从传统的平面设计一直跨越到 Web 设计,同时也要包括各种形式的媒介展示技术。他们或许并不擅长那些知名的应用程序框架,或许也很少制作大型应用程序的经验,但是他们所擅长的东西也足以让偏工程化为主的开发者们羡慕不已了。

开发这样的网站不用 Ember 也是很正常的,因为这类网站的技术聚焦点不在于应用程序架构,而是更具体一些的技术,这个涉及的层面就很广阔了,比如说最近两年如火如荼的 HTML5 之中就有很多相关的技术点和 API 是为这类开发而生的。在过去很长一段时间里,这类网站主要被 Flash 的开发者们所垄断,后来鬼知道 Flash 都经历了些什么,反正这帮人基本上都转战 Web 了。可能像 Ember 这样的应用程序框架对他们而言是陌生的,或者是不对路数的,而没有 Ember 的话也不会让它们觉得缺少了些什么。

在我看来,Ember 的组件化技术其实也是可以派的上用场的,不过仅仅考虑视图这一块的话,用 jQuery 操作 DOM 已经足够优秀,喜欢组件化的话也可以选择 React 之类的工具,所以 Ember 在这里就无关紧要的很了。

信息管理为主的(后台)网站/应用

这个类型其实算是一个临界点,拿 Ember 来说用或者不用当然也都可以,但个人认为用它带来的好处会更大一些。信息管理类的网站相比于内容展示类的网站最大的不同点在于:

  1. 业务模型相对复杂一些。比如说一个小说网站,从前台的角度看没多少业务实体参与其中的,掰着指头数不会超过 10 个,一般 5 个左右就足够用了。但切换到后台这个数量级至少得 x2(其实 CMS 也在此例,只不过前面我们是单说它的前台罢了),再多一些也很寻常。
  2. 要处理的用户交互更多。在前台用户主要就是看,收藏评论这一类的交互已经算是复杂的了;切到后台之后,用户虽然少了,但交互的频次和复杂度却直线上升,特别是各种批量操作、搜索/过滤/排序、数据呈现、角色/权限控制。所说这些东西最终也都必然会体现在 DOM 操作上,但很大一部分工作则是隐藏在视图之下的。
  3. 数据交互也变得复杂了。这件事情要分两头说,有一种情况是整个网站无论前后台都是服务端渲染 + 静态化输出的,用的自然也就是大家耳熟能详的那些,这种情况下前端工具往往扮演的是“助攻者”的角色,很多动态化的数据更新其实还是后端做的,前端只能负责到渲染之后的用户交互上,也就是说其实大量的业务逻辑都是后端先做好了,只把结果丢给视图然后才有前端介入,那么此时 Ember 也会缺少自己的用武之地,倒是 jQuery/React/Vue 等等比较合适。 另外一种情况就是后端很轻,只有基本的数据模型/校验再加上 API 输出,而把更多的业务逻辑交给前端来完成,那么这时候 Ember 就能发挥自己的特长了。更具体的事情我后面再谈,这里只是一个概述。

有很多现成的例子,比如博客引擎 Ghost 的后台,论坛 Discourse 全站,Linkedin 的管理后台和移动应用,Yahoo 内部使用的一些管理后台等等都是采用了 Ember 作为开发框架。在国内多数此类的应用都是基于 Angular 开发的,鉴于本人拥有长达四年的 Angular 开发经验,类似的企业级管理后台也做过几个,我可以负责任的说综合评比 Ember 绝对比 Angular 好用,至于 Angular 2 我不熟,暂时也没有要研究它的打算,就不予置评了。

不过这里我们说的是可以不用 Ember 啊是不是?没错,因为这类网站大家也都是做的快要吐了的,不用 Ember 也没什么,只不过从这里开始使用 Ember 会带来更好的体验罢了——代价也有,比如说你得先学,而且在这类场景下想用的足够爽,你要学的还不能只是皮毛,否则发挥不出原有的十分之一也只会让你觉得束手束脚。


以上差不多涵盖了绝大部分基于 Web 的应用场景了。我说你可以不用,但我并没有说你不能用,也没有说用了不好,比较准确的意思应该是你不用影响不大,其他的技术手段足够应对,并且 Ember 或其他框架也不是万能的,某些角度的考量下它(们)也有自己的劣势。所以在这些场景下,Ember 可以不是第一选择。接下来我从自己的角度来说说什么时候 Ember 会是我的第一选择。

框架的意义

jQuery 的问题不是 jQuery 的问题,而是观念和使用者的问题

我们经常可以看到很多人在争论一个问题:jQuery 还是 xx 框架?而这种争论的源起大概应该是多数的现代前端框架都不推荐使用 jQuery 了,或者换个说法,它们都认为可以不需要使用 jQuery 了,并且在绝大多数情况下效果只会更好。

这样的意见倾向当然会引起争议,但人们在争论的时候却显然忽略了一个本质的问题:说可以不用 jQuery 的并不是框架,而是数据驱动这种新的思路,而数据驱动这种思路不是孤立存在的,它需要有相对完整的架构链路来保障数据的通路——也就是说,当你用数据驱动的思路去开发应用程序的时候,DOM 仅仅是一整个链条中的一个部分,甚至都不是重心。jQuery 不是不能在数据驱动的思路中发挥作用,但只靠 jQuery 是肯定不够的。当你做的应用在应对数据处理时的规模不太大或者不复杂,又或者数据相关的业务逻辑都是服务端帮你完成的时候,你对此的感觉是非常微弱的。那么这些情况我都已经在前文中列举过,所以你觉得 jQuery 够了不需要框架那也是十分正常的事情。

然而这些并不代表框架没有什么用处,或者框架在排斥 jQuery,我个人是很难理解为什么会有这样的想法,当我看到这些观点的时候我的感觉主要是两个原因:

  1. 他们的确不怎么需要使用框架(就目前的需求来看),使用 jQuery 就足够了
  2. 他们曾经学过/用过某种框架,但并没有学会或者没有领会到框架的实际意义

另外一方面也有一些人觉得框架可以在任何场景下代替 jQuery 为代表的传统开发技术栈——注意,我又一次强调了可以这两个字——不能说这是错的,因为的确可行,但也不代表就是正确的、明智的选择。这种说法的确会引起一些意见上的冲突,不过可以不等于应该,阅读这些观点的时候我们应该有自己的判断能力。

如果遇到下列的场景,我也会毫不犹豫的使用 jQuery:

  1. 后端 MVC 的架构,有完整的 View 层,不需要过度考虑前端组件化——当然,这个 View 层也得足够好用,像传统的 JSP 人工拼模版的方式,那我宁可在 jQuery 的基础上引入一个模板引擎 + 模块管理器,比如说 Handlebars + require.js。在这种场景下,后端框架可以提供给我足够的视图逻辑操作,比如说 Rails,我没必要硬塞一个前端框架进去。 不过对于我个人来说,我可能会倾向于逐渐改变这种架构,让后端去掉 View 层转变成纯粹的 API 服务,那么届时前端将会重构,框架就很有可能再次被引入了。至于为什么会有这种倾向,我放在后面单独说。
  2. 制作一些单页面或少量页面即可满足需求的微型站点

所以如果你问我 jQuery 有什么问题,我会说它没有什么问题,真正的问题在于我们每一个人身处的业务环境不同,技术栈环境不同等等,很多时候是环境在约束你的技术栈选择,再接下来才是个人的倾向。你可以设想一下,接下来如果你只有 API 可用且不给你后端 View 层,在目前的应用发展趋势下你若是还能坚持 jQuery 去搞定一切的话,那你也算得上一条汉子了。

那么有人就要问了:凭什么不给我后端 View 层?这么多年我都用得好好的呀!

你需要一个 API

你可以把前端能写的东西都混合在 MVC 的 View 层,这个时候 jQuery 似乎就足以应付了。

如果现在要你做另一个应用呢?需要不同的 UI,但是数据和 Model 都是同一份。OK,可以设置新的路由,然后派发给新的控制器 + 视图来做,控制器或视图的重复可以抽取出来。

如果现在要你做一个混合移动客户端呢?OK,我们可以判断 UserAgent 为移动端编写新的 View(且不论判断 UserAgent 是否准确,这里只是举例)

如果现在要你做一个原生移动客户端呢?呃……写 API 吧

如果你的应用程序的数据可以应用在更广泛的场合(而不仅仅是桌面浏览器里),那么为它编写一个 API(无论是内部使用的还是公共使用的)是迟早的事情。面对不断扩张的客户端需求,与其绞尽脑汁去修修补补现有的框架,还不如未雨绸缪的建立起 API 服务。

如果你的应用程序才刚刚开始,你甚至都会考虑后端只提供 API,而不再使用臃肿的 MVC 架构——这也是一种趋势,在很多新兴的互联网公司、团队、项目中都有着广泛的实践。

如果你现在所处的开发环境就是如此,那么有什么理由不去试试前端的框架呢?让我来描述一下最理性的思路:

  1. 前后分离是必要前提条件,因为现在你没有后端视图层了。前后分离不是要逼迫你去分开,而是因为后端不再负责任何客户端的视图渲染了,于是分开就成了必然的选择。同时,前后分离并不等于 SPA,你依然可以开发各个页面独立的应用程序。再有,SPA 并不代表不支持 SEO 和首次加载慢,绝大多数的 SPA 框架都有服务端渲染技术的基础,这个我在后面单独会讲。
  2. API 会给予客户端比较完整且合理的数据映射(数据库 => API),客户端需要有数据层来进行对接。绝大多数的框架都有适合自己的数据层来提供完整的解决方案。jQuery 只有底层的 Ajax 请求接口,数据怎么进来,怎么 mapping,怎么改变,怎么传递,怎么响应变化,怎么做有效性验证,怎么收集(用于提交)等等都需要你自己来设计。当你搞出一个相对通用且好用的方案来,你也就等于实现了一个其他框架里的等价机制,所以何去何从心里就会有个数了吧?
  3. 如上所述,今后你很有可能做多个客户端(哪怕都是在一个平台上),所以通用逻辑或者 UI 组件如何抽取并且共享使用也是需要考虑的点。在这个方面,不同框架的表现各有不同,而你自己做也会面临同样的问题。

即使你现在所处的开发环境还不是这样的,提供 API 这件事情从长远来看也是必要的。目前你可以依赖后端的 View,可要是遇到了我上面提到的一些场景,使用某种前端框架也是必要的了。

刚巧前两天有一位国外同行写了一篇文章,文章的内容在这里不重要,重要的是里面几张图画的很好,我就借花献佛一下:

back-to-2008

now-in-2006

the-divide

图的意思我就不浪费篇幅了,相信各位都能看明白。知乎上有人做了中文翻译,顺带分享一下地址:https://zhuanlan.zhihu.com/p/23412169

(本章待续……)

静态资源管理

静态资源的管理其实是每一个前端工程师的必修课,尽管这件事情和 UI 的关系没有那么紧密,但是只有前端工程师才对如何管理和使用静态资源最有发言权(当然到了存储和伺服的环节就会偏向服务端了),这也是为什么自打 node.js 诞生以来,成堆的任务运行器和模块打包/构建机制疯狂滋生的主观原因——我们需要优秀的管理工具。

当下最火的当属 webpack 派系了,不过由于 Ember CLI 诞生的较早并没有使用 webpack,而是借助了相对冷门的 broccoli 作为基础工具体系,然后在其基础上打造了专职服务于 Ember 体系的构建工具。也正是由于这个原因,大多数工程师对 Ember CLI 都不够熟悉,我在日常的交流中对此感触很深,因此我想单独撰写一章总结一下我所知道的一切。

关于 Bower

Bower 很烦人,一个需要修正的历史。实际上目前 Ember CLI 对 bower 的依赖只有两个了:emberember-cli-shims。前者已经重新发布到了 npm,目前正在集成测试中,预计下一个版本的 Ember CLI 就可以正式移除该依赖;而后者呢则可能会直接去除,新的 module resolution 方案将不再需要这些 shims。

但是在很长一段时间之内 Ember CLI 还是会保留对 Bower 的支持,因为已有的项目可能会用 Bower 安装一些其他的依赖。在我的开发经验当中,几乎所有的依赖都可以找到对应的 npm modules 来取代 bower components,唯一的例外是 device.js——一个很小巧但是对移动端开发非常有用的库——不知道作者搞什么,npm modules 上发布的版本从来不更新,逼得人用 Bower。

如果你需要用 Bower 安装模块,以下是正确的步骤:

我用 APP_NAME指代当前项目,MODULE_NAME 指代目标模块,EDITOR 指代使用编辑器编辑文件,FILE_PATH 指代目标文件路径。另外如无特别说明,当前目录一概假定为项目的根路径。不再赘述。

$ bower install MODULE_NAME --save
$ EDITOR ember-cli-build.js
// before `return app.toTree()
app.import('./bower_component/MODULE_NAME/FILE_PATH'[, options])

options 是一组可配置的参数,它的诸多用法可参照 Ember CLI 文档的 Managing Dependencies 一节。其中要重点说一下 options.prepend: true,这个参数可以让被 import 进来的依赖文件追加到 vendor.{js,css} 的前面,这在很多时候都是必要的。比方说你要使用 normalize.css,它就应该追加到 vendor.css 的最前面才能发挥应有的作用。如果有多个文件都要 options.prepend: true,那你就要小心安排 import 它们的次序了。

按需加载?

一般来说,一个 Ember App 只需要最终构建两个样式文件和两个脚本文件:APP_NAME.{js,css}vendor.{js,css},这些文件默认都已经引入在 app/index.html 文件中了。然而很多人都喜欢按照一定的规则把样式/脚本拆分成多个子文件,然后希冀于“按需加载”并以此来获得预想中的“快速加载”体验,其实对于 SPA 应用来说这么做反而是得不偿失,理由有三:

  1. 分成多个文件(但不按需加载,而是一次性加载全部)是有道理的,特别是在 HTTP/2 普及之后——目前只是实际尚未成熟,届时 Ember CLI 会做出改变来迎合新技术带来的好处;
  2. 分成多个文件,借由路由驱动加上 document.write “秘法”实现伪按需加载是没有道理的,且不说 document.write 已经被打上了 bad practise 的标签(现代浏览器会警告你),就是每次路由跳转都要等待零零碎碎的请求和加载就会影响用户的体验,你可能不得不定制 loading state 来粉饰背后的“龌龊”,而且也使得离线应用特性变得名不符实;
  3. SPA 讲究的就是一次加载完毕,此后都是平滑/立刻响应,也就是说除了首次加载之外,之后的体验应该像桌面应用那样流畅(异步请求 + 局部状态更新是另外一个层面的问题,后面再说),而不是磕磕绊绊的。真正的按需加载不是这么玩的,如果确有其使用场景,你应该试试新的 Ember Engines(可以试试 LinkedIn 的移动端,感受一下无缝流畅的按需加载,这就是 Ember Engines 做到的效果)。

说到 Ember Engines,由于我还没机会去在正式产品中应用它,所以我估计这次是没法介绍太多了。明年 EmberConf 将会是 Ember Engines 和 Ember FastBoot 正式登场的时候,我希望届时再开专坑来填。

因此我个人的建议是不要刻意去搞什么按需加载,为了按需加载你可能要在 UI 和体验上做很多妥协来弥补不成熟技术的缺陷,注意:不是所有的应用程序都需要追求极速的页面加载的,这种追求通常对于内容型网站会比较有意义,因此它们多采用服务端渲染,而工具/服务型应用的加载等待只要不是太过分,用户是完全可以接受的。与其绕很多弯路,不如去追求更好的用户体验和引导,比如说我们可以学习一下 Slack 是怎么处理用户等待加载的。

另外在现阶段,我们也可以在工程方面多注重一下控制依赖的体积,尽量避免盲目的使用大堆的第三方模块。说到体积,我估计多数人都认为 Ember 在物理体积上很庞大吧?给大家看两张截图对比:

ember-production-build

webpack-production-build

上图是一个新建 Ember 项目的构建结果,下图是我自己的 Univera 脚手架(基于 webpack 的 React+Redux+SSR)的构建结果,单从数字比较 Ember 多了 1/3,但需要说明的是:

  • Univera 里写了一个简单的 demo,不多,业务代码撑死一百来行几乎可以忽略不计;而 Ember 因为许多 convensions over configurations,实际写业务代码时能省略的东西也不少,综合比较:平手。
  • 图中这俩架构,Univera 多了 HMR(模块热替换)和 SSR(服务端渲染)以及按需加载(不是静态资源,而是模块)的支持,总的代码量会有一些但也不是大头;上面这三个特性在干净的 Ember 架构中是没有的,加上 Ember Engines 和 Ember FastBoot 会再大一些些,但是 Ember 有更多东西是 Univera 里没有的,综合比较:平手
  • Ember 架构里有个“癞皮狗”依赖暂时去不掉——我说的是 jQuery,其实它有时候也是很有用的;而在 Univera 里由于是我自主搭建的,压根儿就没有考虑过 jQuery 的存在,这货的体积占了 1/6 左右(使用代码行数粗略估算),所以单考虑构建后体积 Ember 吃了个亏,综合比较:Univera 胜之“不武”
  • 最重要的!Ember 是社区维护,开箱即用,持续更新,不断优化;Univera 能负责的人只有我一个,而我也是站在一堆靠谱或者不靠谱的开源软件的身上,搭建 Univera 的过程……鬼知道我都经历了些什么,而那些依赖的后续可靠性……鬼知道它们都在经历着什么,所以技术风险和稳定性保障方面,诸位自己掂量着办,综合比较:Ember 完胜

问题是:为什么 Ember 会这么大呢?原因是 Ember 提供了非常非常多的“宝石”,看看它的 API 文档就知道了,即使你使用 Ember 框架好几年,你依然会觉得很多东西都没有学会怎么去用;但是另外一个角度来看,有很多潜在的问题也因为 Ember 而解决在无形之中。举个例子,如果你要在 IE 9 使用 Function.prototype.bind 你必须要自己添加 es5-shims,而 Ember 内置了增强版的 Ember.run.bind 等等。

不过也有很多时候我们并不需要默认提供给我们这么多东西,也许我们更希望能够自己挑选需要的部分,这是一种非常合理的诉求,只是因为从前“模块化”这件事情是 JavaScript 的痛,Ember CLI 开发的时候也没有 webpack 这样的模块处理机制,所以一直没能成为现实。

Ember 社区当然不会视而不见,最新的一个 RFC 已经将此事提上了日程(实际上已经开始做了),Ember 框架将被会以独立模块的方式用 npm 提供,于是用户可以选择用什么或者不用什么,这将从根本上解决体积相对较大的问题。有兴趣的不妨读读这个 RFC,特别是末尾的附录——你可以看到体积的对比之下,Univera 缺少了太多太多东西。

我还是一样的观点:体积不是最重要的,毕竟我是冲着媲美桌面应用的 SPA 去的,缩减体积并不是最重要的优化因素,而我已经做过大多数人都没有做过的尝试,我深知这里面水的深浅。这个问题在不远的将来将不会再是问题,就此搁笔,何去何从且悉听尊便。

(本章待续……)

Static assets management (npm / bower / x-processors / others)

Plus output multiple files

Environment management

Module resolution and shims (how it helps for future, e.g. tree-shaking)

Prototype extensions and why add-ons disable it by default

When (not) to use arrow function in CP and why should always use CP for property declarations

CPs are lazy evaluated

Understanding data binding (When 1-way / 2-way bindings are useful)

The art of components organization

Try best to not to embed children components deeply in parent component

What is ember-runloop and why it is so important?

extend means put into prototype which might fool you on testing

SEO 怎么处理的?像 Discourse 再写一套模板吗?

#1 楼 @cxh116 过去很多用于 SEO 友好的方式都像打补丁一样是一种 compromising,事实上,SEO 不是对任何类型的网站/应用都那么重要的。比方说我们做应用程序的也都会有一些内容页面,官网/帮助/教程/范例等等,这些东西可以不需要用 Ember 做,或者说不需要做成 SPA,也就不存在 SEO 友好的问题。而应用程序本身就算 SEO 友好也无法提供 SEO 所渴望的那种信息。另外,搜索引擎也在不断进化,它们也不再像从前那样“挑食”,你可以提供给爬虫信息的方式越来越多,不见得非得靠内容静态化。比如说提供足够丰富和准确的 meta 标签也是一种方式(在 head 标签内)。

对于 SPA 来说,真正能做到“无伤 SEO”的可能只有 SSR(服务端渲染)了吧,我在之前讲过 React 的 SSR,但那些都是自己折腾出来的,没有所谓官方的整合支持(官方只提供一些工具函数)。Ember 则有提供 ember-fastboot,这是官方团队提供的集成方案,目前还在测试阶段不过已经能用了。我会放在正文里单独介绍一下的。

偶尔关注一下 Ember,感觉很多 2.0 时宣布的东西现在都还在实验阶段,engine, routable component, fastboot 都是如此。现在这些东西稳定性如何?

#3 楼 @darkbaby123 engine 和 fastboot 都挺稳定的,Linkedin 已经在内部大范围的使用了 engine,用户也能从他们的 mobile app 上体验到(尽管用户并不知道 engine 是个啥),fastboot 要解决的问题其实是应用程序的开发者如何区分那些不可在 node 下运行或者只能部分支持的代码(源自于 DOM 的缺失),这需要大量的 sample 来逐步总结经验。有很多的 addon 已经开始做这个方面的迁移了,我自己做过一些常规的事情都没什么问题。不过做过 SSR 的我深深知道,痛点往往出现在那些不怎么常规的地方,这也正常,毕竟 SPA 的 SSR 不管在哪里都是很前卫的事情。

routable component 因为 2.9 的 glimmer 2 跳票了,所以目前未知,可用的样子我曾经给你看过,只是具体时间不清楚,我估计至少 EmberConf 2017 会给一个交代,明年春天。

比如我想做一个在线的 office,有文档编辑,表格,ppt(ppt 有编辑器,类似 slides.com),就好像 cform.io 的编辑器,这些都需要大量操作 dom,这种情况下,使用 ember(或者 vuejs reactjs)等合适吗?

#5 楼 @stephen 这很难说,得分析的再具体一些(各种功能点)。坦率地说做这样一个东西没有几个靠谱的前端工程师是不行的,并且即便如此也还是需要依赖一些第三方的东西,视开发人员的技术实力和资源限制而定。那些现代的框架 可以 少用甚至不用 DOM,但并不是不让用。什么时候应该用那是需要自己来判断的。比方说我们的应用里也有大量的图表,做这个东西 d3 就是专业的,而 d3 也是以操作 DOM 为主的,这种时候 ember 或者其他框架并不会阻碍你什么,也不会提高操作 DOM 的难度。反而是如果你熟悉这些框架的话,它们还会在很多细节上帮到你,比如说丰富的生命周期,有用的助手函数/类等等。

如果一定要判断合不合适,还需要更具体的细节,比如规模,比如数据的规格和支持等等。我在正文里会描述一些适用和不适用的场合,具体的你到时也可以参考一下。

@nightire 因为像 vuejs(个人用得比较多),都是宣传以数据驱动,尽量减少对 dom 的操作。而对编辑器来说,个人理解,反而是对 dom 操作更多于以数据驱动。

想了解 Ember 比较 Redux + React 的优势。

@stephen 数据驱动,首先数据要“流动起来”,否则怎么驱动呢?你的应用场景可能数据流动的因素不是特别大,大部分时候数据都是“静止”的,主要工作都集中在响应用户“编辑”也就是操作 DOM 上,所以自然你会觉得数据驱动不合适。但是用某种框架也不总代表就为了数据驱动,这只是一种建议罢了,用框架也可能是为了别的好处,没必要因为一个点觉得不合适就全盘否定,技术选型还是要全面考量的。

另外数据驱动其实可以代表两个层面的意思,一个是高层面的驱动框架各个部分衔接起来,还有一个则是更具体的层面,比如说一个组件内部用状态变更来重绘视图——可能把这个叫做状态驱动更合适吧。

假设做一个富文本编辑器,状态的变更无非就是由用户的动作带来的,如果能把每一种用户可能的动作都映射为某种状态,那就很容易让视图响应用户交互而重绘,接着就是绑定各种事件到各种元素上来接收用户动作 -> 追加业务逻辑 -> 改变状态。

问题是,我的组件要怎么分割?理论上我可以用一个组件搞定整个编辑器,但由于所有的状态映射都被封装在一个组件里,那么:

  1. 这代码是否好维护,好抽象(重用)?或许我可以利用框架提供的机制来进行部分的解耦,比如 Ember 有 Service(不太清楚 vue 2 有没有,但普通的 POJO 也是可以的)
  2. 是不是任何状态的变更都需要视图重绘?
  3. 各种交互有没有可能分类?让它们共同使用一个组件?(比如说编辑器的各种按钮)

类似的事情即使我不用框架了,改用传统的方式写也一定会做等价的思考,无非就是里面部分东西的叫法不一样了,分离解耦的边界决定条件可能也会不一样了,但终究会视其复杂性对整个应用程序做一个合理的组织——这一点不管用不用框架都是应该的,而框架本身的意义也在于此,即应用某一种哲学来帮助你更好的组织和管理你的应用程序。

你不妨自己列一个表,不用 vue,以及用了 vue 之后会对你写这么一个应用产生哪些影响?自己评估一下权重打打分,结果不难得出。

@chareice 好的,我会讲的,刚好我对这二者都比较熟。

ember 是不是更适合写交互比较复杂的'web app'而不是已展示内容为主的'web page'?

请问有没有 ember 的入门材料推荐?看了些官网 tutorial 里的内容,以及后面讲的类和实例的那一章节,感觉有点晕。。

#11 楼 @lwd369 没错,的确是这样。

感觉对 Rails 程序员来说,还是 Ember 看着更亲切

#10 楼 @nightire 能讲一下 ember2 对于 angular2 的优势吗

@ch3rub1m 对 ng2 不熟,不好对比。仅从个人角度来看,ng2 除了 Rx 和 TS 的部分以外,剩下的对我没有什么吸引力。而这两者虽然不是 ember 内置的,但也可以很方便的通过 addon 得到支持,所以没有感觉到任何 ember2 的劣势。

#15 楼 @nightire 我初学前端(原本做后端),现在在搞 Angular 2,选的 Dart。选 Dart 的原因是,新、小项目(个人的 side project),一来没有性能担忧,二来无需考虑兼容。选 Angular 而没选 Ember 的原因是,WebStorm 有默认 Angular 2 模板……

不过不论如何,还是期待你的 Ember 感悟!

我也想知道 Ember vs Redux + React。

@nightire 有中间表的多对多关联一般是怎么处理的?

#16 楼 @franklinyu WebStorm 有一个 ember 的 plugin,可以方便的调用 ember cli 的命令,至于模板,WebStorm 是可以自定义的呀。

#18 楼 @williamherry 中间表映射为 Model 就可以了,两边 hasMany 或者 belongsTo。你要知道 Ember Data 不是映射数据库的 ORM,它是映射 API 的,如果 API 已经可以处理中间关系查询,那就直接 Model 映射 API Endpoint 就行了,是否用中间表这件事情对于前端来说是透明的。

#17 楼 @jimmy0017 其实不存在 vs,因为一个是 FP 一个是 OO,并没有绝对的高下之分。

nightire 关闭了讨论。 11月08日 08:29
nightire 重新开启了讨论。 11月08日 08:29

终于更新了!

@nightire 你这篇每个章节都可以扩展成一篇文章了

👍 EmberJS、React 和 Angular 的官方文档和初级 Tut 我都看过,打算择善而从:Angular 是最先让我吐的——我真受不了那种对 HTML 的扩展方式,抱歉,对那些 Angular 的爱好者,我实在受不了那个;React 初步看起来没啥大问题,不过真正的问题可能是:如果不用它的扩展语法、只用 JS 的话,代码写起来会比较啰嗦——换句话说,React 不鼓励用户直接使用 JS,至少从我角度看是这样——这个问题是个大问题:我既不喜欢一个框架把 HTML 扩充成一个种新的 XXML,也不喜欢用它发明一种新的编语言。在我看来,一个好的框架必须坚持 HTML 和 JS 的基本语法不动摇,任何试图强迫或者诱导用户使用一种新的编程语言进行开发的前端框架都是极端危险的。这样就剩下 EmberJS 了,不过 EmberJS 本身确实是优秀的,并不是因为我排除了它的两个对手才发掘了它。Discourse 就是一个例子——在很多方面,Discourse 都可以看作是 Rails 的旗舰应用,它有很多优秀的地方值得学习,每次看它的代码我都有新发现——也可能是我的 Rails 水准太 low 吧😄 不过我做 Ruby Web 开发 5 年多、总共开发经验 12+ 年,直觉还行。

  1. 楼主说的大部分我都同意。这种重量级前端框架的使用场景只有一个,就是恨不得用一个网页实现一个软件的功能的 saas 应用。除此之外我觉得没其他的应用场景。一个应该用 jQuery 处理的页面,无论变得多复杂,jquery 都能胜任的。
  2. 该不该用 ember, react 这类前端框架的,考量维度不是交互,而是状态:页面的状态复杂到一定程度,导致你需要费劲的维护这个状态。这时前端 runtime 里面其实有两层:数据/状态,和表现/DOM。前端的表现层只是对状态的展示,后端则退化成一个暴露 DB 数据的 API,前端数据层变成最厚的一层。
  3. 在这种状态下,页面的状态和 DOM 的同步是非常头痛的事。react + redux 的优雅之处在于 visual dom 和 unidirectional data flow 这些概念控制复杂度。不知道在这个问题上,emberjs 如何比 react + redux 做得更好?

@academus "React 不鼓励用户直接使用 JS",这句话不知从何说起,JSX 其实只是一个语法糖罢了,都不算是一个完备的 ?xml。如果可能的话,React 巴不得所有人都直接使用函数而不是 JSX,但毕竟要照顾很多人的底子和情绪,再说文档结构复杂的时候,嵌套的函数调用写起来并不舒服,所以最简单的方式就是不要把 JSX 当成 HTML 的替代品。如果学过简单的模版引擎实现原理,那么就当 React 的 JSX 是直接 compile(template) 里面的部分(其实就是),而 template 才是之前的 HTML 或其他模版语法。

因此 React 也并没有发明新的语言,它只是把过去模版编译的中间过程直接暴露出来了而已,并没有那么极端。也就是说 render 函数既是模版的解释和编译,也是渲染调用。我们可以说它解耦的层次太高不够清晰,但发明新语言的确是假说。

#25 楼 @darkbaby123 老实说我更了几个章节之后就觉得我有必要换成 gitbook……

#27 楼 @u1440247613

  1. 笼统归纳的场景只有一个,但这个场景可做的领域实在太多了,而且事实上这个场景在逐渐占据着主流,可以看看国外内容型朝应用型过渡的趋势就知道了。另外 sass 是一种提供服务的形式,但其实应用本身可以不局限于以 sass 的方式提供。比如说我们的巧思吧,主服务是 sass,但也可以变成内部/私人服务部署,可以打包成桌面/移动应用,甚至可以离线使用(虽然还没实现……顺带一提,传统的服务端渲染做离线是很麻烦的哦)。

  2. 考量维度的事情,交互只是一个因素,状态的事情我后面还会单独讲。事实上这两者并不矛盾,因为交互复杂必然对应着状态复杂,无非就是使用不同的工具对于状态的抽象描述不同罢了。细分的话,状态还可以分成 UI 状态和数据状态,因此我先说 UI 的部分,也就是强调交互复杂性的原因。事实上,很多人都把交互理解为用户可以操作的部分,然而并不是单纯这样。交互是双向的,除了用户主动操作的部分,应用程序的反馈也是其中的重要组成部分——这我就不细说了,有机会我可以单独谈谈设计与交互方面的话题。另外,用 jQuery 去修改 DOM 不就是把状态强行映射为动作么,只不过在 jQuery 程序员的认知里,很多状态都是“隐性”的,只存在于他们的瞬态思维里。如你所说:可以用 jQuery 编写的网页,用 jQuery 也会做得很好。但是一次性做得好并不代表其扩展性也好,复用性也好,可维护性也好。我后面有计划写我用 Ember + d3 实现 100% 可定制性交互图表,实际上现在就有一个可以交互的 demo:http://ember-d3.surge.sh/sandbox ,技术上讲,d3 和 jQuery 在操作 DOM 的层面上是非常相似的,然而我几乎没用它操作 DOM,而只是利用其丰富的函数来做数据结构和比例变换计算,Ember 来负责数据与视图的绑定和一些必要的 DOM 操作(比如支持 SVG 响应式)。我绝对可以想像得到如果没有 Ember(或其他等价功能的框架)而单纯用 d3 或 jQuery 的话,这种东西写起来或是维护起来该有多复杂。而现在的代码呢?由于是商业作品,开源估计是够呛(未来也许会开源部分定制化的 Ember Addon),不过可以先看看还在整理中的 API doc(上面的域名后面改 docs),看完之后你不妨告诉我,这样的局部应用(还不牵扯到数据层状态维护,单纯是 UI),以后还会不断增加几十甚至上百的定制项与图表类型,你是愿意用 jQuery 还是基于状态管理的框架呢?所以说了,能写得好不代表没有更好的,选择总是要跟着需求走的。

  3. Virtual DOM 这个事情没有那么“神话”,如今的主流框架其实都是 VD 化的,Ember 早在前年换成 Glimmer 引擎的时候就已经是 VD 了,事实上单说 VD 方面的发展,React 都已经落后于很多竞争对手了,React 自己现在都在重写渲染和 diffing 的核心算法。单比较极端的渲染性能(比如说大量的——千以上级别的——组件重绘),Ember 在 Glimmer 一代的时候就已经打平 React 了,而马上 Glimmer 二代又要更新了,今年三月的 EmberConf 就已经放出了渲染性能的对比 demo,React 已经不是对手了。你可以去找油管上的 talk,里面还有 demo 的链接。

顺带一提,Ember 可以做到核心渲染层不断替换升级,模版层也不断替换升级,但模板语法和组件 API 始终不变,对开发者来说这种性能提升的代价(我指的是代码的编写和维护代价)几乎为零。所以说到“优雅”——这方面是一个神话。

而说到 unidirectional data flow,这就更是一个“神话”了。首先,这不是 React 独创的技术(实际上也是一种思维,而不是特定的技术),不过 React 的确是把它正规化、明确化、标准化的领头人。然而 React 做出了强制单向绑定的决策——在大部分情况下都是可以的——则有点矫枉过正的意思。事实上双向数据流在 UI 编程的领域是很有用也很重要的模式,真正有问题的是不加节制的滥用双向数据绑定,这种风气是 Angular 1 带动起来的,我不知道 React 做出这个决策是不是有和 Angular 唱对台戏的意思,但我可以负责任的说:丢弃双向绑定是一种很傻的行为。而实际上 React 没多久就妥协了,只不过把双向绑定的机制搞成了 mixin,默认还是不给你。

后面我会用一些例子来详细阐述这一点。问题在于很多开发者并不能够理解使用它们的时机和它们各自的 pros & cons,所以不管是 Angular 还是 React,他们的做法至少可以让最早一批实践者在理解这件事情时的心智模型变得简单一些。随着人们的认知不断的深化,我们现在可以看到大把大把的教程文章来介绍在各种默认双绑的框架里实现单绑,或者在各种默认单绑的框架里实现双绑,等等。

Ember 呢?Ember 一开始的时候 CP(计算属性)就是存在单绑模式的(ReadOnly),但那时候没多少人理解这东西的意义。后来等到 React 火起来之后,所有的数据绑定都是可以在三种方式中切换的:默认双绑、单绑(readonly helper,相当于后来 ng 里的 ::,以及 React 的默认绑定)、解绑(unbound helper,等于数据拷贝)。我在 Ember 群里发过一个讲解数据绑定关系的视频在线 Demo,这件事情我光在 Ruby China 就已经讲过许多次,其他网站的科普文章更是不计其数,我也不知道为什么到今天还是有很多人认为这是 React Exclusive 的概念,大概 React 社区对这个概念的“洗脑”实在是太成功了吧——一个技术型营销的优秀案例。

总而言之,如果你想,你现在就可以在 Ember 中完全践行 unidirectional data flow,丝毫不带缩水的。并且顺应潮流的趋势,Glimmer 2 引擎面世的时候,所有组件的数据绑定将会是默认单绑,可选双绑(mut helper)——这就和 React 组件是一样的了——并且 Glimmer 2 的 diffing 的最小单位是每一个 getter(比如组件模板里的一个 {{}}),相比之下 React 的最小单位是一个 render 函数,我还不确定新的算法是否会改进这一点,但 Glimmer 2 已经做到了,按照 Vue 的文档描述也应该是这样的,但是 diffing 只是影响渲染性能的一个因素,请不要以点带面。

除此之外,如果你还想要 single data source,那么 ember-data 本来就是这样的(但不是函数式 reducer + 不可变数据结构,而是 纯正的 OO 式),而且 ember-data 和 ember 的整合是非常自然流畅的,你可以使用 container 的模式(data link 在最顶层单向往内层传递,action 向上),也可以仿照 flux,哪里需要往哪里 link,在这个方面有很多细节在 ember 里都是天然支持或者默认优化的,比如说路由的 model hook 天然支持异步(根据 promise 状态决定渲染树的走向)等等。而 Redux(或其他 data store)和 React 的整合需要人工调整的地方就琐碎的多了——这种事情对于架构师来讲自然都是份内之事,可问题是目前有多少靠谱的前端架构师呢?Ember 和 Ember Data 可是开箱即用的,你完全不需要事先理解它们是怎么协同工作的才能开始写具体业务。

再往远了说一步,你以为 Ember 就不能用 Redux?Redux 可不是 React 的禁娈,Ember 也是可以用 Redux 的,甚至 Mobx!(Mobx 本身还没有人做 addon 整合,但是 Rx 的套路明白了,实现 Mobx 方式的 state management 也并不困难,且不说 reactivex 是已经可以直接整合在 Ember 里的了)。这些还只是冰山一角了,UI 编程的各种思想和模式在 Ember 社区里都有广泛的采纳和实践。Stream?Concurrency?(ServiceWorker)Partial App?(Engine)SSR?(FastBoot),所有这些都只需要一句 ember instal xxx 就可以立即体验——当然,你要想玩转它们肯定还是要深入学习一下的,它们本身都是比较新鲜的概念,Ember 社区也只能说是身先士卒帮你踩坑罢了。

所有的这些不是为了替 Ember 吹牛皮,而是想说明一点,Ember 的好不是在于它立了什么 Flag,或是洗了什么脑,而是它的社区文化是以开放包容的心态广纳四方菁华,并尽可能的消化它改良它,最终为我所用,所以我们从来不喜欢说如何比 xxx 更好,因为我们不喜欢把自己摆在任何一个 xxx 的对立面。我们更喜欢说:xxx 哪里做得比较好,好在哪里,和我们的契合点在哪里,是否可以学习采纳,是否可以有更好的方式来实现这个需求。

去看看 Ember RFCs 吧,这才是一个技术社区该有的样子。

@u1440247613 刚好这两天有一篇文章挺火的,这是另外一个角度来阐述了选择 Ember 而不是 React 的原因(此前一直用 React 两年半),可以作为第三方参考:https://blog.instant2fa.com/choosing-ember-over-react-in-2016-41a2e7fd341#.x6jcrj8es

特别是里面提到的“选择疲劳症”,由于我个人之前从头开始搭建和维护了一个 React 的全功能框架 Univera,对此的体会简直可以说是刻骨铭心。我对 Ember 的诸多不满意之处是促使我深钻 React 的初始原因,可是等到钻完之后我的感想却变成了:我再也不想维护下去了。

#31 楼 @nightire

我对 Ember 的诸多不满意之处是促使我深钻 React 的初始原因

可以说说当初你对 Ember.js 有哪些不满意的地方吗?我觉得我现在也到这一阶段了,对 Ember.js 很熟稔,但真有点审美疲劳,有学习 Vue.js 的打算,或许对比之下能重新发现 Ember 的强大。

#32 楼 @ugoa @nightire 同问。我最先接触的是 Ember,然后是 Angular 和 React,比较之下反而发现了后两者的不少闪光点,至少对 Angular 变得不讨厌了。

我当时最不喜欢 Ember 的一点就是,作为一个高度集成的全栈框架,重要的 key feature 都要等官方的解决方案,因为这涉及到框架集成方方面面的事情。这导致 Ember 的解决方案要么就很稳定全面,要么就太 naive(注意这不代表完全不能用)。React 这种微框架的思路因为本身做的事情就非常少,也变相地刺激了社区的繁荣,鼓励第三方开发者做自己的解决方案。虽然会导致众多良莠不齐的方案,但每个领域内有口碑的也就那么几个,所以也不太会有“选择困难”的问题。至于开发者得自己写点胶水代码整合的问题,我觉得跟自己从头开发插件相比,代价还是小很多的。

@nightire Ember 也有很好的地方,我个人最喜欢的是几乎无缝的升级体验,和 computed property 带来的数据驱动的思路,这两点都很重要,但也非常容易被忽略。

@darkbaby123 我就说一件事情,redux 自己不管异步的,OK,这可以理解。我在做 Univera 考察 middleware 的时候,候选对象多少个?13 个!这还不包括后居而上的 redux-saga,并且你也知道现在的势头又变成了 mobx 大有取而代之的意思。

其实平均每一个 project 代码量也不过就是百行左右,我当时真的是全部看了一遍,外加所有的 active issues。问题是没有一个能 cover 绝大多数常用情景的,要么就是能但是抽象层次很低。一定的 glue code 并不是无法容忍,但是每加入一个碎片就要来点 glue code,加到一定程度之后才发现之前的一些东西要么想得不够周全,要么路子不对,咋整?

最终让我感到厌倦的最主要原因还不在这里,我记得跟你说过,如果只是我一个人玩那变就变吧,反正从头到尾演进的过程都在我脑子里。可问题是我们搭一个架子的目的是要提供给团队来使用的,我记得当时在一个月内光是 router 上面的 breaking changes 就给小伙伴们开过三次会——我真的很讨厌这种无休无止的改来改去。

在一个团队里,能做到随机应变并且还可以始终遵循一些 best practice 的终究是少数,大多数人在遇到 confusion 的时候还是会以寻求帮助为主。框架的一个重要的职责就是给出这样的 guides,它未必是最先进的,未必是最具吸引力的,但它应该是成熟的,经过验证的,足够稳定的。否则有的时候我连 code style 都没法写清楚。我希望我们用到的东西应该是约定一次就足以长久的应用下去,并且可以适应绝大部分场景。那些 edge case 我可以来写一些 layer 来适应它,而这些 layer 也要给予 base api 的稳定和有计划性的演进。

Ember 有 lts,有 half year releasing 的计划,至少我知道即使有什么东西被 deprecated,它也不会在一次 npm install 之后立刻就引爆,我们可以合理的安排时间去修正这些地方,而不是不断的 breaking changes。

我并不认为 React 社区是完全错误的,你提到的那些 shining parts 我也一样关心,即便目前我们已经停用 React 了,我依然对 React 的核心进展天天关注着。但我不再会关注它的那个混乱的无组织的生态圈了,即使 Redux 的作者也是这么觉得,我在 twitter 上看到他在呼吁所有的周边作者们要多一些的全面思考和责任心。

举一个对比的例子,Ember Addon 刚兴起的时候,一瞬间就出现了 3 个 addon 是做 deploy 的,各有各的特色。Ember 社区怎么做的呢?在其中最受欢迎的那个 addon 发了个 issue @ 了其他两位作者,询问是否可以把大家的力量汇集起来共同做好一个 deploy addon?最终的结果是现在大家都知道那个最好的,并且它自己也形成了统一的扩展接口,任何 deploy concerns 都可以作为 plugin 补充于其上,而开发者只需要挑选自己需要的 recipes,然后 ember install 就可以了。这里面也会有 configurations,你可以按照你的实际情况来微调,如果微调不满意你可以开发补充的 plugin 来增强这个过程并且能分享给其他人。

为什么 redux async middleware 不可以这么来做呢?为什么要分裂十几个,各有各的想法和套路呢?难道这么做会阻止你社区繁荣?思想碰撞?I don't think so,在我看来可能唯一的 drawback 就是新的 idea 不会 landing 的那么快,就像 RFC 一样,可是我们的实际工作也不是前沿科学,也不需要追求那么快啊。

@ugoa 这些具体而微的点我在正文里都会有提到,可能我不会开个单篇来批判,因为问题终将都有解决办法,无非就是有些来得慢了些罢了。

#35 楼 @nightire 团队合作方面的问题有道理。关于 async middleware 方面,我觉得更深层的原因是“没人知道怎么样做是最好的” ,在这种思路不同的时候也只能“道不同,不相为谋”了。反正自己做个 package 的开发成本也很低。说到良莠不齐,我感觉可能也跟 npm 生态圈有关,大量良莠不齐的包,很多也只考虑部分的应用场景。使用者挑来挑去,最后往往是看了几份别人的源码后再自己造一个轮子…… 我感觉已经有点习惯了,所以没觉得是多大问题……

#37 楼 @darkbaby123 其实就是一个人和多个人的区别,自己折腾就不太会担心这个。

感觉 routable component 一直不出来,ember 就算不上真正的 2.0 版本。目前在使用 ember 时,controller 和 route 各种重合部分,感觉体验不好,例如说 actions 可以同时放到 route 或 controller 的问题,不能完全去除 controller,因为 queryParams。目前的感觉是在等下去,要没有耐心去期待 routable component 了。

“可是人非圣贤,主观的好恶是免不了的。。。”据小弟粗见,圣贤对好恶是要分得很清楚的,而且坚持自己的观点,并设法解决好恶的事物。比如,喜欢 Ember,就在 Ember 的路上走下去。又比如突然哪一天发现了一个更棒的 Framework,也会考虑在新项目(或功能中)的使用。比如不喜欢汇编语言来开发 APP,就坚定的不用汇编开发 APP。如果必要,还会写博客告诉别人,用 Ruby 可能更好。 那些没有主观好恶的人,其实不是没有主观好恶,而是把主观好恶隐藏起来了。这种人可能就是“乡愿”,就是“道德之贼”。

@gazeldx 我觉得你的理解浅了一层。我说主观的好恶免不了,并不是说没有主观的好恶,而是在评价一项事物的时候能否足够客观。

因为这句话的上下文是说,因为工作场景的需要不得不用自己不喜欢的工具……那么这个时候你评价该不该用这个工具是顺着自己的偏好来呢?还是一概安之若素呢?

人非圣贤孰能无过这个词已经是一个成语了,有很多引申的用法。人们对“过”的评判也是无法统一的,有人认为束缚个体性格是一种过,也有人认为不遵守公共规则是一种过。按你的标准是圣人的,按我的标准就可能不是,按他的标准甚至可能变成了小人。

说这么一句无非就是修饰一下罢了,若有文过饰非之嫌,实在是笔力不足,惭愧了。

我再重新读了一遍那个段落之后算是明白我们的误会在哪里了,你的说法自有你的道理,但用在我这里却是强人所难了,且容我分析:

人非圣贤,孰能无过

套一下模板变成:

人非圣贤,还能没有个人好恶吗?

按你的说法,圣贤是有好恶的,所以这么说不通。那么我是不是也可以说,圣贤是有过的,左传这么写也是说不通的。对吗?

古人眼中的圣贤就是“白莲花”一般,没有过错的吗?肯定不是这样,孔孟老庄在史书当中的记载也不是完美无瑕的,左传中的圣贤指的不是你说的圣贤,而是一种虚指,说的是那传说中的“完美”人物。而我所说的圣贤也是那种仅存于理论中的,分析评价事物百分之百客观不参杂个人好恶的楷模——我们都知道这是不可能的,就和左传中的圣贤一样,古人也明白这个道理。所以这就是一种 conventional 的修辞手法罢了,不必较真。

#39 楼 @jesktop 不是 routable component 出不来,而是 glimmer 引擎最初的设计有错误,但直到和 htmlbars 一起启用之后才被发现,原本这个时候 angle brackets components 已经都做好了(我还曾经写过一篇介绍),下一步就是测试 routable components,却因为这个失误导致了后面的计划最终全部推翻重来。

但是本来也有机会就这么上了的,但这个失误影响的范围其实很广。routable components 只是一个名字,其实它可以是很多种风格,比如说是 container 风格的组件,还是 bridge 风格的组件。那么当时对于 routable components 最终的走向也是意见不一,这也是推迟发布的原因之一。

另外,估计你对版本的理解和我们不太一样(或者说和 semver 不太一样)。不是说有了新特性的更替就是 x.0,重点是有没有 API 层面上的 breaking changes。glimmer 2 替代 glimmer 就是一个非常大的特性更替,但由于新的引擎在设计方面非常小心谨慎,所以最终完全没有 API 的改变(有一些 deprecations),所以 2.8 -> 2.9 的升级对于用户来说就是透明的,而不是非要搞个大新闻上到 3.0 才甘心。

routable components 也是同样的道理,组件那一层面的事情已经尘埃落定了,路由那边则是由于在 glimmer 2 研发期间,一些新的 rfcs 收到了广泛的关注,比如说 virtual dynamic segments 等等,这些东西要不要随着 routable components 上,还是制定计划慢慢上?这些问题都是需要考虑清楚的。

我之前也提到过,Ember 对于一些重大/敏感特性的改动的确给外界一种反应比较慢的印象,这确实是令人不爽的一点。不过在我用 Ember 做过一些大型项目之后我也逐渐能有所理解,因为它完整而庞大所带来的一个副作用就是牵一发而动全身,这势必会造成 breaking changes 无法迅速完成。只能说没有完美的事吧。

其实处理现在 controller 的问题很简单,那就是把目前直接展开在路由对应模版的内容用一个 component 包装起来,且把这个 component 当作是 routable components,只不过涉及到 queryParams 的部分要交给 controller 就可以了。涉及到 route actions 的可以用一下 ember-route-actions 这个 addon,或者自己写一个 patch,很简单的(参考这个 addon)。

这贴怎么没人加精?

lgn21st 将本帖设为了精华贴。 11月21日 22:26

#43 楼 @lgn21st 可能还没更新完😄

从去年开始边学边用 Ember.js 到现在一年多,业余也做一些 Ember 的技术咨询,说说我对这个框架整体的看法吧,先来优点:

  • 开箱即用 这一点是我最直观的感受,不仅可以用,而且超好用,比如无需任何配置直接写 ES6,整个人都好了很多。ember-cli除了在安装和升级项目的时候有点麻烦外,其他时候完全可以媲美 rails 的命令行工具,Ember 这一点启发了很多其他前端框架。

  • 与现有技术融合顺畅 尤其是可以直接大量借鉴现有的丰富的 jQuery 库,不知道可以省掉多少时间,少造多少没有明显收益的轮子。

  • Ember Addon 当然还是有人愿意造轮子,而且还愿意分享出来,一些复杂的场景现在都有了成熟的解决方案,比如ember-simple-auth, ember-cp-validations,etc。以前自己写的一个select2.js的 wrapper 各种别扭各种不兼容,然后我发现了ember-power-select,原生实现,好用到哭。

  • Ember-data 不只是有很多好用的 API,而是用多了之后你会不由自主地围绕 Data 来思考,因为这是 The single source of truth,而且 Ember data 也是一个极好的存储状态的地方,可以省掉不同视图间大量的状态传递和计算。

  • 大量杀手级特性 比如 Computed Property,熟读其 bool, equal, oneway等 APIs 代码优雅指数可获极大加成。再比如 queryParams,对URL即状态这一理念的完美实践,记得这个理念是 Yahuda Katz 在哪个演讲里提出的,个人深以为然。

接下来说说感觉不是那么良好的:

  • 学习曲线 真的不是一般的陡峭,基本上新手安装完,做完 ToDoList 了之后差不多新鲜感就过渡到就迷茫感了,老老实实去啃文档去吧。记得我开始学的时候,除了把最佳入门读物 Rock and roll with Ember.js过了一遍之外,还和一个以色列的哥们做了 5,6 次的远程结对编程,才慢慢地感觉有点头绪,真正写起来有行云流水的感觉就要到好几个月之后了。印象最深的是把后端的 snake_style 转换成 js 通用的 camelCaseStyle 就用了我 3 天,而那个 hook 就隐藏在文档的某个小角落里……

  • 使用场景局限 就是小项目不是不能用,而是用起来显现不出 Ember 的优势,用传统的技术比如 jQuery 也能实现的很好。这一点 @nightire 总结的很好,我就不多赘述,只是比较最近用 Ember 帮客户做了一个简单的 CRUD 的 app,感觉确实有点杀鸡焉用牛刀了。不过如果你的后端是 API-only 的那就另说了,

  • 文档(或者说缺少文档)平胸而论,官方现在的文档质量已经好很多了,但这也是很少甚至是唯一可以依赖的地方,其他方面比如书啊,教程啊要么很少要么就很过时,尤其是 Stackoverflow,上面关于 Ember 的问答大部分都「年代久远」,根本都不能看。 比如一个比较新的Contextual component特性,基本除了 RFC 和 Release Notes, 还没有看到有 blog 提到关于它的最佳实践,除非去扒开源 add-on 的源码。当然 Ember 有自己的 slack group,YouTube 上也有很多演讲,但太过分散而且效率低。所以很多时候想要真正自信地采用某个方案,还是得回去看官方文档,然后自己领悟,只有真正懂了才能形成自己的最佳实践,不然就是给自己或别人挖坑,这也算是某种程度的倒逼吧。

  • 开发进度 这一点 @nightire 也解释了,主要是这个新的 Glimmer 2的开发耽误了许多,社区追求更好的实现当然无可厚非,但客观事实就是 Ember 丧失了迅速发展的机会。想想去年这个时候(2015-11 月),Angular 1 已经日薄西山,2 还在无限 beta,React 的生态比现在还混乱,Vue.js 更是小众中的小众,那时候要做技术选型,作为唯一一个稳定先进的框架,有点常识的人都会认真考虑一下 Ember.js。可现在如果再选,你有不是一个而是四个成熟的选择,Ember 对那些技术决策人的吸引力不得不说小了很多,不是 hard core fan 或前端大拿,选 Ember 还是要很大决心的,这也导致了 Ember.js 至今仍然是不愠不火地发展着。虽然说做 early adopter 的感觉良好,但用的人多其实才是好事,集思广益才能加速促进。想 Redux 玩非主流的 FP,连 OO 都没搞明白的新手还不是趋之若鹜?这一点,Ember 社区真的还是要好好学习一个。

缺点说了这么多,搞得我的口气好像在批评一样,但其实不然,我个人对 Ember 的整体感觉还是瑕不掩瑜,Ember 的理念还是很先进的,掌握 Ember 之后面对其他框架的确有种高屋建瓴的感觉,很多看似新鲜的东西其实深究起来在 Ember 里早就实现了。但具体到个人需求,每个人都不一样,Ember 也不是银弹能照顾到所有,所以个人还是要按需选择。我们的目标是:不追 HYPE!

@ugoa 趋之若鹜又能怎样呢?能因此而证明从此便能健康的发展下去吗?

关于 Redux 造成的问题我在很多回帖里都谈到过,不知道你怎么看,依然认为这些不是问题吗?

即便使用 Redux 的人很多很多,但是真的懂透彻了,能用好的(包括围绕其周边的一系列 middleware 或 packages)却是少之又少——那么这样就可以满足了吗?事实上,你看看现在讲 Redux 的教程,十之有九还是在基础的 reducer 上绕,翻来覆去都是 todo list / counter 这样的例子,有几个正儿八经谈谈真正复杂的场景的?而 Ember Data 这些年来已经发展到常见的场景都有 adapter 并且几乎都有实际运行的真正的项目(因为这些 addon 都是在实际开发中抽象出来的)。就连 Dan Abranov 自己都说了:You Might Not Need Redux

事实上,从 Dan 推出 Redux 以来这么久了,有什么本质上的进步吗?这么久了!趋之若鹜的人们大多还在门口绕圈圈,看看 SF/SO 上关于 Redux 的问题都在问些什么吧,绝大多数人都还搞不明白怎么把一个 store 里的状态渲染到视图里,或者怎样发一个异步的 action

再去 google 一下:github redux async/ajax/promise,看看你能找出多少“解决方案”?一年过去了,分出高下了吗?选出最优了吗?

所以我不禁要问了:这样的繁荣有多少实际价值呢?Dan 因为 Redux 声名远扬,也加入了 React Core Team,So What?Redux 成为 Official Guaranteed 了吗?非但没有如此,又冒出一个 Mobx 来。这样的循环还要搞多少次?

一方面喊 Frontend Fatigue,另一方面什么火就往什么冲,我是真搞不懂这种现象 Ember 社区有什么必要好好学习一下的,我还是喜欢现在的 Ember Community,steady as the beating drum

BTW,上面的话只是借你的话题说说感受,不针对你的评论哈。

#47 楼 @nightire 其实我引用 Redux 的例子并不是想说它好,而是想支持之前的一句话,用的人多其实才是好事,集思广益才能加速促进。我对 Redux 也并不感冒,就不多加评判了。

#48 楼 @ugoa 抛开 Redux 不谈,“集思广益”其实并不一定能“加速促进”,Ember RFCs 就是很好的例子。

一个 Idea 的提出要比真正实现它容易得多,特别是在没有别人参与的情况下。然而这种速度却未必是好事,也许你的 idea 不够周全,也许你忽略了一些非常必要的应用场景,也许你根本就想歪了,其实还有更好的方式能达成目标。

RFC 的意义就在于最大可能性的排除或削减上述“也许”所带来的副作用,而这种副作用恰恰是很多看似繁荣的社区最大的隐患。

炒得火热并且用的人多并不一定能实现“集思广益”,因为这个词真正的核心在于“集”,而它要体现在两个方面:

  1. 用户知道哪里应该是集中探讨 ideas 的地方——比如 https://github.com/emberjs/rfcs
  2. 官方应该明确被广泛关注的 ideas 终将会得到官方的支持,或者有普适性足够好的周边支持,比如 ember addons

而一个 idea 要想足够成熟,它必然要经过探讨甚至争论的“集思”,然后要有人提出相对严谨周密的 solution,要有人写 demo,要有人测试,要有人拿去实战检验……之后才能变成正式的方案交给大部分人使用,让大家一起“广益”。这才是一个靠谱的、负责任的社区应该做的事情。

没有这些前提,如何把思“集中”起来并广益呢?你引用的 Redux 的例子,其实只是在你看来它很繁荣罢了(因为你其实也对它不是十分了解),可是它并没能做到“集思广益”,说好听一点顶多是“百花齐放”,观赏性挺高罢了。

@u1440247613 Ember 有一个插件是 ember-redux,有兴趣可以试用一下。

受益匪浅。

不过我现在已经专做后端了😁 我想问的是,一个好的后端工程师应该怎样与前端合作?

#41 楼 @nightire 你说的没错! 左传说道:“人谁无过,过而能改,善莫大焉。”。 我确实较真了。圣贤也是有过的,只不过圣贤善于改过,以致于过错越来越少。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号