blog
blog copied to clipboard
未来Web应用的前端技术选型畅想
上半年,我写过一篇《2015前端组件化框架之路》,现在大半年过去了,这段时间一直在思考,未来的东西是怎样的。
目前我主导着苏宁的云计算相关的所有前端项目,这些项目以控制台为主,几乎都广泛使用了Angular 1.x,一方面因为个人技能之前有积累,一方面因为产品的开发人员基本都是Java方向转岗,对Angular的接受度较高,上手非常快,开发效率也非常高。
但2015年,前端的世界发生了很多变化,这些变化快得超出我想象。在这个巨变的时代,产品的技术选型是个麻烦的事情,具体来说,有几个方面:
- 如果2-3年后新开始一个业务项目,可能会有什么样的技术方案?
- 如果现在立刻开始一个新业务项目,可能会有什么样的技术方案?
- 如果持续维护老的项目,后面可能会对它们有怎样的迁移方案?是逐步迁移,还是推倒重做?
- 在PC端项目为主体的业务体系里,如果将来某个时机出现了移动端项目,该如何去选型,并且利用之前的业务代码?
我之前没有预料到的,是ES6的普及之快。在此之前,对于新的语言特性,人们一般会等到支持的浏览器普及之后,才会大量使用,比如ES5,但由于Babel这样转译的工具出现,我们可以渐进使用,所以,开发过程中可以完全使用ES6甚至ES7的特性编写代码,然后通过构建去达到兼容的结果。
有鉴于此,在未来的项目中,使用ES语言新特性进行开发,是一个必然要做的事情。但,这并不能算是整体方案。整体的方案应当包括但不限于:
- 使用什么基础框架
- 业务代码如何规划
- UI组件如何规划
- 样式和主题如何规划
- 构建方案怎样
- 人员如何协作
- ……
所以,我们面临的,还是基础框架选型这么一个重大问题。照理说,使用Angular 1.x,后续应当选择往2.0版本过渡,但现在这个阶段,乱花迷人眼,谁也不知道未来的事情怎样,在这一层上,我个人觉得还是要再看看。
于是就卡在这里了,这个选不了,后面的事情都没法考虑做了吗?
也不尽然,我考虑了一段时间,觉得虽然每个层面都比较麻烦,但至少可以分层隔离一下。比如说,我们选了某个UI层的组件化框架,并不意味着对下层的数据模型和业务逻辑就有很强约束,至少说,这层还是有很多可选方案。
通常我们在前端,可以对一个Web应用这样分层:
UI层(View) -- 业务逻辑层(ViewModel / Controller) -- 数据层(Model)
比如说,数据层,有Relay,有GraphQL,有Falcor,但我们还可以继续使用原先的RESTful API啊。我们可以不使用某框架自带的请求库,比如$.get,比如$http,但我们还可以使用super agent这样独立的,框架无关的辅助请求库啊。甚至说,我们不想使用XHR了,还可以使用Fetch啊。
所以,把Web应用的前端先分层一看,发现每个层里面,都有很多独立的可选方案,而这些方案是可以组合的,比如说:
上层用React,下层用Falcor或者RESTful,然后把上层换成Vue,好像也没有什么不对啊?下层完全可以不动,也不需要就把每层代码都改一遍啊?
这样一来,我们可以先不管UI层,直接先把下面两层全部构建出来,这个部分不对DOM产生任何依赖,所以,跟上层框架没有关系,也无需按照上层框架的约定。
我们引入一个框架,对整个系统来说,最大的影响是会产生一些约定。有时候我们需要这些约定来帮我们规范代码,但在现在这种形势下,会尽可能希望框架本身不要产生约定,由我们自己,按照ES自身的一些机制来形成代码规范。
比如说,我们使用module,class之类的语法特性,基于传统的OO方法论进行一些规划,利用各种设计模式。或者,我们也可以基于函数式的理念,进行另外一个方向的规划。总之,这个层面的东西是纯业务的,可测试的,可独立运行的。
在构建模型层和业务逻辑层的过程中,我们可以使用ES6,也可以使用TypeScript。之前我曾经有个断言:如果ES6普及得快,TS的形势就会不太好。这主要是因为考虑到如果一个开发者已经在使用ES6,他去使用TS的可能性并不会很大,而如果他到ES6流行的时候尚未接触TS,后面接触TS的可能性就比较小,直接用ES6的可能性比较多。
不过,当业务逻辑比较复杂的时候,使用TS会有一些优势。即使不使用TS,我也建议把数据模型预先定义出来,在实体类里面做一些事情,尽可能使用实体类来构建数据,而不是直接用字面量来定义。当应用规模变大的时候,“严谨性”变得更加重要。
另外一个角度,如果我们要尽可能构建框架中立的业务逻辑层代码,最好是脱离上层框架的绑定监控机制,自己通过比如getter,setter这样的方式,实现数据模型的内部联动,所以从这个角度,预定义数据模型也是必要的。
在这个基础上,再回到我们的现实来,在文章开头,我提出了几个要考虑的可能,现在可以逐一回答了:
1. 如果2-3年后新开始一个业务项目,可能会有什么样的技术方案?
底层如上所述,上层根据当时情况判断选择
2. 如果现在立刻开始一个新业务项目,可能会有什么样的技术方案?
底层如上所述,上层使用Angular 1.4或者Vue之类的成熟框架,同时,使用ES6开发
3. 如果持续维护老的项目,后面可能会对它们有怎样的迁移方案?是逐步迁移,还是推倒重做?
先逐步重构,维持UI层框架不变,把底层重构成上述那样,然后引入ES6,先搞成方案2这样,后续再考虑迁移上层。
4. 在PC端项目为主体的业务体系里,如果将来某个时机出现了移动端项目,该如何去选型,并且利用之前的业务代码?
先把PC端重构如方案3,然后,PC端可继续使用Angular,移动端上层选用Vue之类性能较好的轻量库,PC端与移动端共用业务逻辑层。
以前有一段时间,我一直觉得Angular的all in one是一种挺好的策略,但最近考虑了很多事情之后,觉得将来这种方案的优势会逐渐削弱,所以,现在我也觉得纯粹做上层视图框架的Vue之类有不少好处。在未来,约束越强的框架很可能越不受欢迎,基于ES自身的语言特性做业务代码约束才是王道。
这篇主要是比较笼统地谈一些想法,后面会写两篇具体细节策略的考虑。
+1
叔,还记得大明湖畔的李凤姐吗
民工叔棒棒哒
好文!
还是从技术角度来分析的,技术选型,在于前端整体的发展形式,ES6的定稿以及已经可以以ES6来进行开发,所以目前的选择会有些难以明确的地方。但是,即便如此,我们依然可以根据功能或者职能的不同,在合理的范围内做出符合当前利益的选择。 有没有发现,all in one和web应用分层选型,在某种形式上很像IOS和Android?也就是封闭还是开放,当然,前端领域纯粹的封闭只能是死路一条。我们是用一个框架把整个web应用整个都覆盖掉,还是每个部分是独立的,保持各部分的纯粹性,由开发人员根据各自的情况来进行整合?
在我看来,通常,对个有能力的大公司,每个部分都拆开来,选择最好的配件,以此来达到最优的收益,这就有点像定制的东西,虽然成本高,但是很适合。 对于实力或者资金不是那么雄厚的公司来说,选择all in one是比较有优势的,首先,它有一套完善的解决方案,不需要人力去研究各部分细节,虽然不是特别定制的那么顺手,但拿起来就能用。其次,一整套的方案比较容易出成果,它做出来东西快。这会使得普通开发者普遍喜爱,比较容易拥有广泛的群众基础,广泛的群众基础又会促进其生态圈的完善,如此循环影响。
所以,通常目前国内的大公司内部的技术选型,都不太会被广泛使用,主要在于它只适合相对于自己业务或者同样体量的公司。
但并不是说大公司出的东西就不会有广泛的应用,非常有代表性的例子比如:AngularJS、ReactJS,一个是出自Google,一个出自Facdbook。之所以它们的框架会非常流行,我认为是由于其设计高度,也就是站的层次的问题,其不仅仅是出于公司自身业务。
一点拙见,还有点跑题,欢迎拍砖。
human readable data tree => react component tree => dom tree human readable data tree => vue component tree => dom tree
react 的 virtuail-dom 本质是 json 数据,有了这层隔离,映射到 dom \ native \ canvas 都行。
human readable data tree 是新的隔离层,不管 view 层是什么,都可以桥接过去。
这是我对前端编程模型的的大概思路。
+1回家看。
前排占坑
围观
react 果真影响了前端界 :smile:
Angular 1.4或者Vue之类的成熟框架....
虽然我也在用 vue,但是不敢这么说啊
@sinoon 支持这种说法,得分场景
前排占坑
滋慈,不过关于typescript这里想说一下,其实TS和ES6并不冲突,TS本身定义的就是JS的超集,最新版已经引入了ES6的绝大部分特性,而且完好的支持TSX。它最主要的目的是解决动态弱类型语言的在开发过程中的缺陷,力求达到C#/Java开发体验,而JS再怎么发展发展出花来也不可能引入静态类型,于是强类型静态语言才能有的开发优势也就享受不到。
上个月去听了Anders来北京关于TS的讲座,虽然没讲完,但是很好的暴露出JS开发的坑并如何用TS去解决这些问题,所以我个人推荐有精力的人还是去学习一下,官方文档2个小时就能搞定,况且Angular 2也要用这个
膜拜之。。
厉害。。 好文要常读
组合各个层次,还真需要点能力
ES6普及真是好快,react 项目基本都是ES6。
前排围观
膜拜……
对于前端工程化,MVC之类的分层设计,确实很有必要,否则牵一发动全身,说到底,都是软件,需要设计!
不过感觉楼主对React的态度比较冷淡。 之前我也很不感冒,不过最近一周看了下React和Redux的官方相关文档,态度有所转变。 再加上我在公司项目使用MVVM框架(RactiveJS)编写组件的时候遇到的一些问题:大部分由于项目变大以后组件化带来的复杂性和双向绑定所引起。发展到这个阶段,这种“传统的”MVVM框架的优势显得不再那么明显,而由此引发的新问题却非常难以解决。 React入门不难,但是真要开发实际项目要学习的东西还是挺多的,开发效率在初始阶段对比传统MVVM框架也没有任何优势。但是他的组件化以及单向数据流的设计思想确实先进,在项目膨胀以后不管是发现问题还是解决问题都比传统的MVVM框架要方便的多。
我发现angular的公用指令很容易写的很庞大,但是写组件的人对业务不可能100%覆盖,加上API和设定有会繁琐(因为支持的功能多),业务开发自己写自己用的又是一个分分钟的事,导致不太受欢迎 感觉组件想通用很难,在业务逻辑差不多的情况还行
@sutaking 这个问题,我觉得是这样的,我们写一个公用组件,往往还会用第一代前端框架的思维去考虑,无数的配置项,无数的内部解析,不庞大是不可能的,而且还会出现互斥需求。
但在Angular这样的体系里,没有必要这样去做,我一直强调一个观点:模板本身也是配置项。在用Angular之类东西做组件的时候,应当把模板作为配置项来使用,分离到组件主体功能的外部去,组件自身只做基础布局的增强用。
https://github.com/xufei/blog/issues/22
我这篇里面有个DataGrid的例子,就是这个意思。
@simongfxu 我确实对React的态度比较冷淡,其实不仅是我,MVVM流派的不少人都不太接受React,并不一定要那样的方式才是组件化,并不一定要那样的方式才是单向数据流,才能导致可控,部分观点我也谈过:http://www.zhihu.com/question/31613336/answer/62814977
在这个主题下面,尤雨溪和刘骥的答案是我深为认同的。
面对大型Web应用,我们要的是两个东西:
- 可控,组件化是一种策略,我们要的是两种东西可控,一种是组件之间的关系,一种是组件内部的数据,这两者,不同框架有不同策略去做,并无高下之分,主要还是取决于使用者的水平
- 高效,从开发效率讲,带双向绑定的框架有其不可阻挡的优势。
哈哈,感觉最近都在反思这些,上周末也写了一个类似的: https://github.com/phodal/repractise/blob/gh-pages/chapters/frontend.md
引用部份原文:
前端的演进在这一年特别快,Ruby On Rails也在一个合适的年代里出现,在那个年代里也流行得特别快。RoR开发效率高的优势已然不再突显,语法灵活性的副作用就是运行效率降低,同时后期维护难——每个人元编程了自己。
如果不能把Controller、Model Mapper变成ViewModel,又或者是Micro Services来解耦,那么ES6 + React只是在现在带来更高的开发效率。而所谓的高效率,只是相比较而意淫出来的,因为他只是一层View层。将Model和Controller再加回View层,以后再拆分出来?
现有的结构只是将View层做了View层应该做的事。
首先,你应该考虑的是一种可以让View层解耦于Domain或者Service层。今天,桌面、平板、手机并不是唯一用户设备,虽然你可能在明年统一了这三个平台,现在新的设备的出现又将设备分成两种类型——桌面版和手机版。一开始桌面版和手机版是不同的版本,后来你又需要合并这两个设备。
其次,你可以考虑用混合Micro Services优势的Monolithic Service来分解业务。如果可以举一个成功的例子,那么就是Linux,一个混合内核的“Service”。
最后,Keep Learning。我们总需要在适当的时候做出改变,尽管我们觉得一个Web应用代码库中含桌面版和移动版代码会很不错,但是在那个时候需要做出改变。
对于复杂的应用来说,其架构肯定不是只有纯MVP或者纯MVVM这么简单的。如果一个应用混合了MVVM、MVP和MVC,那么他也变成了MVC——因为他直接访问了Model层。但是如果细分来看,只有访问了Model层的那一部分才是MVC模式。
模式,是人们对于某个解决方案的描述。在一段代码中可能有各种各样的设计模式,更何况是架构。
Mark好文
现在前端选型确实是个纠结的时间,angularjs 1 or 2 or react.js? 感觉Angularjs适合大规模的后台项目,团队整体前端技术一般的场景; React.js更适合C端项目,对团队整体前端技术能力要求相对高一些
如果现在有一个全新的webapp项目,我应该会选择用 webpack+npm 来做模块化。然后用react或者vue.js来做UI层的MVVM和组件化。应该还会结合webpack的babel-loader来使用ES6和jsx,或许还会永css-modules来处理css的复用和模块化。
强力插入,也许快速开启一个项目也很重要,推荐下基于 LeanCloud 的 Web 方案。 https://github.com/leancloud/LeanEngine-Full-Stack