Web应用的组件化(二)——管控平台 #7

Web应用的组件化(二)

管控平台

在上一篇中咱们提到了组件化的大体思路,这一篇主要讲述在这么作以后,咱们须要哪些外围手段去管控整个开发过程。从各类角度看,面对较大规模前端开发团队,都有必要创建这么一个开发阶段的协做平台。前端

在这个平台上,咱们要作哪些事情呢?node

1. HTML片断

咱们为何要管理HTML片断?由于有界面要用它们,当这些片断多了以后,须要有个地方来管理起来,能够检索、预览它们,还能看到大体描述。git

这应该是整个环节中一个相对很简单的东西,照理说,有目录结构,而后剩下的就是单个的HTML片断文件了,这就能够解决存储和检索的问题了,但咱们还要考虑更多。后端

已有的HTML片断,如何被使用呢?这确定是一种相似include的方式,经过某种特殊标签(无论是前端仍是后端的方式)把这些片断引用进来,这时候就有了第一个问题:前端工程化

假设有界面A和界面B同时引用了片断C,在某个开发人员修改片断C内容的时候,他如何得知将会影响到界面A和B呢?一个比较勉强的方式是全项目查找,但这在不少状况下是不够的。浏览器

若是咱们的HTML片断是做为独立的公共库存在的,它已经不能经过项目内查找去解决这一问题了,由于无论A仍是B,只要他不处于片断C的项目空间,就无从追寻。服务器

这时候不少人会问两个问题:markdown

  1. 跨项目的界面片断重用,意义在哪里?架构

    若是咱们的产品是针对一个小领域,它的复杂度根本不须要划分多个项目部分来协做完成。设想场景是面对很大的行业,各项目都是子产品,未来多是其中若干个联合部署,这时候,保持其中的一致性是很是重要的。好比咱们有个基本配置界面,在多个子产品中都要用,若是各自开发一个,其操做风格极可能就是不一致的,给人的印象就是不专业。因此会须要把常见的界面片断都归集起来,供业务方挑选使用。框架

  2. 修改C,只提供说明,可是不通知A和B,不实时更新他们的版本,而后自行决定怎样升级,如何?

    这会有一个问题,每次有小功能升级的时候,代码是最容易同步合并的,因此才会有“持续集成”这个概念,若是是一直伴随升级,总要比隔一个大阶段才升级好,升级成本应尽可能分摊到平时,就像农妇养小猪,小猪天天长一点,天天都抱来抱去,不以为吃力,即便长大了也还能抱得动。

如今问题就很明确了,必定要有一种方式来把这个依赖关系管理起来,很显然,已有的版本库是确定管不了这些的,因此只能在外围作一些处理。

咱们创建一个管理平台,除了管理实体文件的版本,还管它们之间的关系。具体这个关系如何收集整理,有两种方式:手动配置,代码分析。

手动配置是比较土的方式,开发人员每提交一个文件,就去这系统上手动配置它的依赖关系。代码分析的话,要在每次提交文件的时候解析文件的包含规则,找出确切的文件。这二者各有利弊,前者比较笨,但容易作,后者对代码格式的要求比较高,要考虑的状况较多。

咱们的界面每每不是那么简单,HTML片断也可能有层次的,举例来讲:

界面A里面包含了片断B,可是片断B自身又包含了片断C,因此这个依赖关系也是有层级的,须要在设计的时候一并考虑。

2. JavaScript模块

JavaScript代码的管理,比HTML片断的情况好一些,由于业界不少这方面的解决方案。但它们仍是没有解决当依赖项产生变动的时候反向通知的问题。

因此咱们仍是得像HTML片断同样,把它们的依赖关系都管理到平台里。因而,每一个JavaScript模块都显式配置了本身所依赖的其余模块,经过这种单向关系,造成了一套完整的视图。

在JavaScript模块的代码实现中,咱们是不提倡直接写依赖关系的。不少通用规范,好比AMD,每每建议咱们这样写模块:

    define(['dep1', 'dep2'], function (dep1, dep2) { var moduleA = function () {}; return moduleA; });

但咱们的系统是面向行业的,比这种通用解决方案要苛刻一些。好比说,若是有一天重构代码,JavaScript模块们调整了目录或者名字,这么写的就痛苦了,他必须把全部影响到的都去调整一遍,这是要搜索替换的。何况,就像上面HTML模板的部分提到的,影响了处于其余项目中依赖它的代码,缺乏合适的方式去通知他们修改。

因此咱们指望的是,在每一个编写的JavaScript模块中只存放具体实现,而把依赖关系放在咱们的平台上管理,这样,即便当前模块做了更名之类的重构处理,处于外部项目中依赖它的那些代码也没必要修改,下一次版本发布的生成过程会自动把这些事情干掉。

对应到上面的这段代码,咱们须要开发人员作的只是其中的实现,也就是moduleA的那个部分,外面这些依赖的壳子,是会在发布阶段根据已配置的依赖关系自动生成的。

若是须要,JavaScript模块还能够细分,好比相似Angular里面那样,把factory,controller和directive分离出来,这会对后续有些处理提供方便。

如今咱们有必要讨论一下模块的粒度了,咱们这里提到的都是基本的粒度,每一个JavaScript模块中存放的应该只有一个很具体东西的实现。那么,有个问题,在咱们发布的时候,是否是就按照这个粒度发布出去呢?

很显然不行,若是这么作,极可能会出现复杂界面一次要用10多个HTTP请求才能加载完它所须要的全部JavaScript代码的状况,因此须要作一些合并。

那么,合并的策略是什么?在咱们这个平台上,开发人员又是要怎样定义这个合并关系的呢?咱们须要在模块之上定义一个更大粒度的组织方式,这个方式与模块的关系,就比如Java里面,jar文件与class的关系。若是开发人员不显式配置,也能够经过全局策略,好比按最下层目录来合并。

这个时候,在实际使用这些代码的时候,须要带两个配置信息过去,一个是要动态载入的JavaScript文件(合并以后的),二是每一个JavaScript文件中包含的原始模块。

3. 单元测试

若是JavaScript模块都已经被良好有序管理起来,就能够为它们考虑单元测试的事情了。单元测试对于提升基础单元的可靠度,是有很是重要意义的。

在咱们这个平台里,能够把单元测试跟JavaScript模块关联起来,每一个JavaScript模块能够挂一组单元测试代码,这些代码能够在线编写,在线运行。

单元测试的本质就是编写模拟代码来调用已有模块,考虑到咱们的模块是JavaScript,因此不少思路都倾向于在浏览器端执行它们,对于单个模块的单元测试,这不是个问题。

若是要批量执行整个系统的单元测试,那就不同了。把JavaScript代码先加载到浏览器中,而后再执行,不少时候并不须要这么复杂。咱们彻底能够在服务端把它们作了。

借助Node.js的能力,咱们能够在服务端执行JavaScript代码,也就意味着可以把绝大多数JavaScript模块的单元测试在服务端就执行掉。固然,咱们为此可能要多作很多事情,好比说,有些库须要移植一份node版的,常见的有AJAX调用等等。

注意了,可以在服务端作JavaScript单元测试是有先决条件的,代码的分层必须很良好,除了视图层,其余任何层面都不能操做DOM。因此咱们这里主要测试的也正是除了视图层以外的全部JavaScript业务逻辑。至于视图层怎么办?这个真的很难解决,这世界上不是全部东西都能自动作的,只能先把可作的作了,之后再来考虑这些。

4. 文档和示例管理

4.1. 文档

如今咱们有HTML片断和JavaScript模块了,须要给它们多一些描述信息。简单描述显然是不够的,咱们还要详细文档。

这种详细文档能够经过某种方式生成,也能够由开发人员手动编写。与传统的离线文档不一样,在线的文档更实时,而且,每当一个开发人员变动了他的文档以后,不须要通过全量构建,访问者能够实时访问到他的最新版本。

熟悉GitHub的朋友们可能早已习惯这种方式,在项目库里面存在一些以md格式结尾的文本文件,使用markdown语法来编写一些说明文档。

毫无疑问,这类格式很适合在线协做,因此咱们也会在平台上集成这么一种编写文档的方式,不管是针对HTML模板仍是JavaScript模块,或者是其余什么类型,甚至还能够用来当博客,就像月影同窗的gitpress平台,能直接从GitHub上拉取文本或者HTML文件造成博客。

文档除了以集成的形式浏览以外,应当也能够以单独连接的方式发出去,这时候用户就能够像看一个新闻网页同样去浏览。若是再进一步作下去,还能够作电子书的生成,提供打包的离线文档。

4.2. 示例

在编写代码文档的过程当中,可能免不了要插入示例,示例有两种形态,一种是纯文本,相似gist这样,一种是可在线运行,相似jsfiddle和jsbin这样。

这两种都有各自的优势,因此能够都作,示例的存放能够与文档相似,也应当能经过一个连接独立运行。

4.3. 幻灯片

有时候咱们看到一些在线的幻灯片,以为效果很帅,好比reveal.js,咱们的开发人员有时候做代码分析或者走查的时候也难免要写一些演示,若是能把这些东西也随项目管理起来,能在线查看,会是很不错的一件事。因此咱们也能够考虑给它们加个存储界面,甚至作个简易的在线编写器。

5. 项目与目录管理

说到如今,咱们彷佛还遗漏了一点什么。那就是以上提到的这些东西,以什么为组织单位来存储?

考虑到咱们的这个平台是要管理一整个大产品的所有前端内容的,它里面应该分了不少项目,对应到子产品上,这么一来,很天然地,项目就成了第一级组织单位。项目之下,没有悬念地,只有目录了。

对于一个项目而言,它有哪些要作的事情呢?首先要能配置其实体存储位置。前面提到的这么多代码、文档之类,最终都是要实体存储的,怎么存?咱们固然能够本身搞一套,在文件系统上作起来,可是还要考虑它们的版本管理,很是麻烦,因此不如直接对接某个版本库,调用它的接口去存取文件,这里配置的就是版本库的路径。

其次,要考虑从已有项目复制,相似GitHub里面的fork功能,不过内部处理机制能够略有不一样,fork的项目默认未必要有实体文件,只有当产生了修改或者新增操做的时候才建立,剩下的还引用原来的就能够了。咱们这里的项目复制功能是为项目化版本而考虑的,常常出现一个产品版本支持多个客户项目的状况,因此可能会用得着这个特性。

而后,也要考虑项目的依赖关系。依赖一个项目,意思是须要用到它里面的组件,因此实质是组件的依赖。提供项目依赖这个视图,只是为了将来变动的一些考虑。

6. 评论管理

以前提到,咱们整个平台的目的是为了提升大型前端团队的协做能力,协做是离不开交流的。上述的任何功能,都应当带有交流沟通的能力。

好比说,若是开发人员A使用了其余人写的一个代码组件a,对其中一些细节有疑问,他应当能够对它进行评论。在他评论的时候,任何参与维护过这个组件的人员都能收到一个提醒,这时候他能够选择过来看看,回复这个疑问。同理,在文档、示例下也能够如此操做。

在互联网上有这类产品,用于在任意URL下挂接评论交流系统,比较有名的就是Disqus,咱们能够看到不少网站下面挂着它,用于作交流评论,这样用户能够用一个帐号在多个网站之间交流。国内也有同类的,好比多说,可以用微博、QQ等帐号登陆进行交流。

从咱们这个平台自己看,若是是部署在企业内部做流程提高,引入外部评论系统的可能性就比较小了。由于在企业内部用,必定是但愿这个员工的帐号信息跟工号挂钩,也可以跟版本服务器帐号等模块做集成,权限也便于控制。

从另一个角度讲,某我的员登陆这个系统的时候,他可能收到不少消息,来自不一样的代码或文档位置,挨个点过去回复也有些麻烦,咱们应当给他提供一个全局视图,让他能在一个统一的界面把这些问题都答复掉,若是他须要的话,也是能够点进去到实际的位置。

7. 用户和权限控制

从以上部分咱们已经看到,这个系统是一个比较复杂的开发过程管控平台。这样的话,每一个使用的人就应当能够登陆,而后分配不一样的权限等级。

未登陆用户应当有一些东西的查看权限,可是不能发表评论。已登陆的用户根据权限级别,能够控制可否建立、修改项目,建立、修改目录,代码,单元测试,文档等。

8. 国际化字符串管理

一个跨语言区域的Web应用不可避免要跟国际化打交道,这个事情一般是在服务端作,好比经过在界面代码中嵌入相似<% =getRes(key, lan) %>这样的代码,去获取相应的字符串,替换到界面里来。

这个事情是要占用应用服务器资源的,并且国际化自己实际上是一个在运行以前就已经肯定的事,彻底能够把这个过程放在发布阶段就作掉。好比说,咱们给每种语言预先就把代码生成多份,只是部署在一块儿,根据须要的状况来动态加载特定的那一份。

有很多客户端的国际化方案,是把资源文件拆细,以页面为单位存储,但这实际上是不太合理的。第一个缘由就是在Web2.0时代,“页面”这个概念自己就已经弱化了,到了单页应用里,整个应用都只是一个页面,这个时候,资源文件以什么粒度来组织呢?

咱们提到过,采用MV*框架去作Web应用的架构,有一个目标是作组件化。组件化的意图就是某个组件能够尽量为所欲为地放在须要的地方用。若是把资源文件的粒度弄小到对应HTML片断和JavaScript模块这一级,灵活性却是有了,带来的问题就是管理成本增大。

作一个行业应用,最重要的就是业务一致性,这包括逻辑的一致性,也包括了术语的一致性。某一个词,可能在多个资源文件中都出现,这就增长了不一致的可能性。

因此,应当有一个统一的术语管理平台,一切界面上出现的文字或者提示,都必须来自这个平台。

9. 静态资源的管理

在发布系统的时候,除了须要发布代码,还须要发布图片等静态资源,这些东西也应当被管理起来。

静态资源在两种状况下可用:随产品发布,在本平台被引用。好比说有一个图片,在这个平台上做了管理,它能够被配置到某个项目上,在发布的时候导出。这个图片还能够被用连接的方式查看或者下载,若是本平台内部的一个文档或者示例要引用它,也是能够的。

10. 样式与主题管理

在Web系统里,样式和主题是很重要的一环。样式的管理和发布一直是一个比较复杂的话题,早几年通常都是分块写,而后组合合并,最近这些年有LESS,SASS和Stylus这类技术,解决了编写和发布的分离问题。

咱们看看发布的最大问题是什么?是不一样部分的合并。为了追求灵活性,不得不把东西拆得很细,以前HTML片断和JavaScript模块的处理方式都是这样。这么作,咱们就须要另一件事:这些细小的东西,尽量要覆盖全面。

对应到CSS里面,咱们要作的是把每种在系统中可能出现的元素、类别都做为单独的规则维护起来,生成一个全局的规则列表。不一样项目间,实现能够不一样,但规则的名字是固定的,定制只容许修改实现,不容许修改规则。若是要新增以前没有的规则,也必须在全局规则列表里先添加,再做实现。

样式规则被管理以后,能够在界面组件上对它做关联,也能够不作。作的好处是发布的时候能只把用到的那些样式规则生成发布出去,若是能接受每次发布全量CSS,那也无所谓。

除了规则,也须要考虑一些变量的管理,在CSS中合理使用变量,会大为减轻定制化所致使的工做量。

11. 一键发布

咱们引入了这么一堆东西,实际上是增长了发布的复杂度。为何呢?

以前无论HTML、JavaScript仍是CSS,都是手写出来,最多通过一个minify的工做,就发布了,整个过程很简单,两句脚本搞定。

如今可复杂了,先要分析依赖关系,而后提取文件,而后国际化字符串替换,而后合并,而后代码压缩,整个过程很折腾,不给配置管理员一个解释的话,他必定过来砍人。

咱们有个原则:解决问题的过程当中,若是引入了新的问题,要求负责解决原问题的人也一块儿解决掉。如今为了一些意图,增长了版本发布的复杂度,那也要有个办法再把这事摆平,至少不能比原来复杂。

因此咱们就要把这些过程都集成到管控平台里,作一个一键发布的过程,把全部的这些操做都集成起来,配置管理员发布版本的时候只要点一下就能够把全部这些事情作掉。甚至说,这些流程还能够配置,可以加减环节。

这时候咱们作到了跟以前发版本同样方便,能不能多作点什么呢?

能够把JavaScript单元测试集成到版本发布阶段。由于咱们已经把JavaScript按照职责作了分层,而且把UI部分作了隔离,就能够在浏览器以外把这个单元测试作掉,平时提交代码的时候也能够作,最终在版本发布阶段再全量作一下,也是颇有意义的。

代码依赖关系管理的另外一个目的是什么呢?是最小化发布,既然咱们都管理了文件之间的关系,那么,从根出发,显然是可以得出哪些代码文件在本项目中使用的,就能够每次从咱们的全量代码库中取得确切须要的一部分来发布。这也是咱们整个管控平台带来的优点。

12. 小结

咱们这一篇比较复杂,提出了一整套解决大规模前端协做的管控机制。这套理论的本质是在开发和版本发布之间加了一个环节,把Web体系中除了服务以外的一切静态资源都归入其中,强化了现有主流的一些基于命令行的前端工程化组织模式。

相比于传统行业,好比汽车制造,咱们这个环节至关于生产流水线的设计,其中一些组件的存储就相似仓储机制,发布就相似出厂过程。

这个平台自己还有很多其余的可作的东西,好比甚至能够在上面作界面的可视化定制等,这些是长远的终极目标,在后面的文章里会谈谈一些考虑。

后续文章中,咱们会展望有了这个平台以后,整个前端的协做流程是怎样的。

相关文章
相关标签/搜索