fouber/blog

浅谈前端集成解决方案

fouber opened this issue · 102 comments

每个前端团队都在打造自己的前端开发体系,这通常是一个东拼西凑,逐渐磨合的过程,在技术发展日新月异的今天,这样的过程真的是不可抽象和复制的么?本文希望能够通过系统的拆解前端开发体系为大家提供体系设计思路参考。

什么是前端集成解决方案

前端集成解决方案,英文翻译为 Front-end Integrated Solution,缩写fis,发音[fɪs]

前端集成解决方案并不是一个新词汇,将这个词拆开来看,我们能得到:

  • 前端:指前端领域,即web研发中常用的浏览器客户端相关技术,比如html、js、css等
  • 集成:将一些孤立的事物或元素通过某种方式改变原有的分散状态集中在一起,产生联系,从而构成一个有机整体的过程。[1]
  • 解决方案:针对某些已经体现出的,或者可以预期的问题,不足,缺陷,需求等等,所提出的一个解决问题的方案,同时能够确保加以有效的执行。[2]

总结来说,前端集成解决方案就是:

将前端研发领域中各种分散的技术元素集中在一起,并对常见的前端开发问题、不足、缺陷和需求,所提出的一种解决问题的方案。

前端领域有哪些技术元素

前端行业经历了这么长时间的发展,技术元素非常丰富,这里列举出一般web团队需要用到的技术元素:

  1. 开发规范:包括开发、部署的目录规范,编码规范等。不要小瞧规范的威力,可以极大的提升开发效率,真正优秀的规范不会让使用者感到约束,而是能帮助他们快速定位问题,提升效率。
  2. 模块化开发:针对js、css,以功能或业务为单元组织代码。js方面解决独立作用域、依赖管理、api暴露、按需加载与执行、安全合并等问题,css方面解决依赖管理、组件内部样式管理等问题。是提升前端开发效率的重要基础。现在流行的模块化框架有requirejs、seajs等。
  3. 组件化开发:在模块化基础上,以页面小部件(component)为单位将页面小部件的js、css、html代码片段放在一起进行开发、维护,组件单元是资源独立的,组件在系统内可复用。比如头部(header)、尾部(footer)、搜索框(searchbar)、导航(menu)、对话框(dialog)等,甚至一些复杂的组件比如编辑器(editor)等。通常业务会针对组件化的js部分进行必要的封装,解决一些常见的组件渲染、交互问题。
  4. 组件仓库:有了组件化,我们希望将一些非常通用的组件放到一个公共的地方供团队共享,方便新项目复用,这个时候我们就需要引入一个组件仓库的东西,现在流行的组件库有bower、component等。团队发展到一定规模后,组件库的需求会变得非常强烈。
  5. 性能优化:这里的性能优化是指能够通过工程手段保证的性能优化点。由于其内容比较丰富,就不在这里展开了,感兴趣的同学可以阅读我的这两篇文章 [1] [2]。性能优化是前端项目发展到一定阶段必须经历的过程。这部分我想强调的一点是 性能优化一定是一个工程问题和统计问题,不能用工程手段保证的性能优化是不靠谱的,优化时只考虑一个页面的首次加载,不考虑全局在宏观统计上的优化提升也是片面的。
  6. 项目部署:部署按照现行业界的分工标准,虽然不是前端的工作范畴,但它对性能优化有直接的影响,包括静态资源缓存、cdn、非覆盖式发布等问题。合理的静态资源资源部署可以为前端性能带来较大的优化空间。
  7. 开发流程:完整的开发流程包括本地开发调试、视觉效果走查确认、前后端联调、提测、上线等环节。对开发流程的改善可以大幅降低开发的时间成本,工作这些年见过很多独立的系统(cms系统、静态资源推送系统)将开发流程割裂开,对前端开发的效率有严重的阻碍。
  8. 开发工具:这里说的工具不是指IDE,而是工程工具,包括构建与优化工具、开发-调试-部署等流程工具,以及组件库获取、提交等相关工具,甚至运营、文档、配置发布等平台工具。前端开发需要工具支持,这个问题的根本原因来自前端领域语言特性(未来我会单独写一篇文章介绍前端领域语言缺陷问题)。前端开发所使用的语言(js、css、html)以及前端工程资源的加载与定位策略决定了前端工程必须要工具支持。由于这些工具通常都是独立的系统,要想把它们串联起来,才有了yeoman这样的封装。前面提到的7项技术元素都直接或间接的对前端开发工具设计产生一定的影响,因此能否串联其他技术要素,使得前端开发形成一个连贯可持续优化的开发体系,工具的设计至关重要。

以上8项,1-3是技术和业务相关的开发需求,4是技术沉淀与共享需求,5-8是工程优化需求。

经过这些年的工程领域实践,个人觉得以上8项技术元素应该成为绝大多数具有一定规模的前端开发团队的标配。各位读者可以对照自己团队现状来思考一下团队开发体系还有哪些环节需要完善。

攒一套前端集成解决方案

不难发现,其实其他领域工程也基本需要解决上述这些问题。前端由于其领域语言的独特性,使得前端工程在解决这些问题上跟其他工程有很大区别,因此至今也没有形成一套比较好的理论体系指导团队实践前端工程。

仔细观察过一些团队的技术体系形成过程,大家都在努力拼凑上述8项技术元素的具体解决方案。单独观察每一项技术点,你或许会觉得都能各自找到已有的实现,但我要说,把所有8项技术点无缝的串联起来,是一项非常有挑战的工作,你信么?相信真正经历过这样事情的同学能明白我说的串联成本问题。

假设我们希望实践一套完整的前端集成解决方案,好了,如果我们单独去看每一项技术点,都可能会找来一两个现成的东西,假设我们东拼西凑的找全了所有8项技术要素对应的具体实现。接下来要用了,它们能很完整流程的跑起来么?

正如前面的贴图展示的那样,所有的技术点都有一定的内在联系:

  • 模块化开发涉及到性能优化、对构建工具又有一定的配套实现要求,也会影响开发规范的定制
  • 组件化开发应该基于模块化框架来加载其他依赖的组件,如果组件化框架自带模块管理功能,那么就可能导致工程性的性能优化实现困难
  • 组件库应该与组件化开发配套,组件仓库中的组件都应该按照相同的标准来实现,否则下载的组件不具有可复用性、可移植性,就是去了仓库的意义
  • 我们设计的开发规范工具是否能很容易的实现,如果部署上有特殊要求,工具是否能很容易的做出调整,而不是修改规范。
  • 工具是否能提供接入公司已有流程中的接口,比如命令调用,如果工具需要一些系统环境支持,公司的ci流程中是否能支持等问题。

前端领域语言的特点决定了攒一套集成解决方案有很高的实现成本。因为前端语言缺少包、导入、模块等开发概念,这使得各个技术点的解决方案在设计的时候都是考虑被独立使用的情况下如何工作,因此或多或少的会延伸自己的职责。比如模块化框架要附属构建工具,甚至要求后端服务(比如combo),组件化框架自带模块化框架,构建工具自带部署规范等,这就大大提高了将各个技术要素融合起来的成本。

总之,前述的8项技术要素之间有许多联系,这就为打造一套完整连贯的前端集成解决方案带来了较大的挑战。如何兼顾规范、性能、框架、流程、部署等问题,就不是东拼西凑那么简单的事了。后面我会单独撰文介绍如何实现一套集成解决方案。

遗漏了测试,应该是九项

@maxzhang
我之前的想法是测试是流程中的一部分,没有特别列出来讨论,主要是关于前端的测试始终处于一个启蒙状态,感觉还不能大规模的应用上,后续单开一个栏目讨论这个方向,如果觉得有比较成熟的解决方案,那必然应该放到这里面,完善这张图。

写的不错 补充点个人见解:

1、关于组件化和模块化,这个粒度实在是不好拿捏,模块可以很大,也可以很小,小到一个函数成一个模块,所以我觉得模块应该主要是通用工具、api、类的封装,而组件更多的是业务功能、UI块的封装

2、关于组件仓库,其实bower、component之类的并不够,还有文档的生成与管理,使用别人写的代码,最快入手的就是看文档,其次才是看代码

3、还有,测试。纯工具和api之类的模块,很容易自动化测试,蛋是到了组件层面,设计业务逻辑、UI什么的,自动化太难了,还得靠人肉

mark

@chemdemo

恩,是这样的,本文只是列出了一些技术要素,介绍前端工程中的基本概念。模块粒度、组件划分、仓库建设以及测试是要各个方向展开来说明。欢迎提供相应的开发经验及总结。

@chemdemo 开发阶段用尽可能小的粒度,发布时候合并

组件化应该不是仅限于 UI 功能组件,整个缓存数据结构都可以作为组件 。@chemdemo 粒度很大的组件,比如 SPA 的每个页面都可以作为大组件,每个页面对外的接口只有 show 和 hide,页面的状态内部维护;同样,粒度小的组件也只有简单的 API,状态内部维护。

@fouber 性能优化真的是个工程问题+1。优化研究理论的支撑、复杂环境得出的模拟数据分析、模拟环境的搭建,都需要整一套工具体系,不然成本太高了。

高大上

不错,收获挺大的

mark

写得很好,收藏一下

或许说这个有点不合适,但是这个集成方案,只适合产品型的前端团队。很多做企业软件项目的公司里,基本都是后端程序员兼做前端工作的,这个时候,前端不会很重视。

@knightuniverse 前端的概念确实非常广泛,做企业软件项目的公司不在这个讨论之列,因为没有严格意义上的前端。这篇文章的适用范围主要是互联网公司。

菜鸟,问一下,前端包括那些切图的事儿吗?

@WenTao-Love

当然包括啦。不过光关注切图恐怕很难应对大型互联网公司的集团军开发需求。十几个甚至几十个工程师团队问题蛮多的

看了两遍,也许还会看更多遍,好文常读读,结合自身在开发中遇到的问题,每次都有新的体会

@bubkoo 多谢关注!

这样的流程对小公司是个很大的挑战,对于小公司来说,没有多余的人手和时间去做组件化或单元测试

@boiawang

恩,除了组件化需要借助大公司的产出之外,其他是很需要的。

opoo commented

文章不错啊,收藏了!

ps:把GitHub的Wiki当作博客用,其实挺有创意的。

@opoo

我也是看到别人这么做的

写的不错。但是这样不利用积累传播啊。比如我想订阅你的博客,就无解了。不如用github pages + octopress搭blog吧。

opoo commented

@Hao-Wu 你只要watch这个库,就能收到新内容的邮件通知了,多好。

广告:用java的童鞋,可以考虑用GitHub Pages+OpooPress搭建博客。 :)

对我们这些搞前端的很有启发性。期望云龙兄能出更多更好有关前端集成的文章。watch!

@jia58960

多谢关注

高大上

干货 !

@fouber 我的公司现在就是这么个情况,去年因为公司规模扩大,所以将整个前端代码从GWT改为使用js重写,使用seajs模块加载框架,现在大约有了300多个js 文件,不包括引用的其他js库。第一版的时候因为没有好的压缩打包策略,所以不做任何处理直接请求200多个js。现在使用gruntjs进行打包压缩,最后只需要请求8个js,开发和压缩模式切换也非常方便,这种方案已经使用1年多了,很稳定。

最近有点时间,于是研究了一直很想试一试的fis,花了3天时间,将整个项目使用spmx改造下,项目可以正常运行了。

通过实际使用fis,我认为它给项目带来了如下好处:

  • 文件名可以带md5,能够开启永久强缓存
  • 对CDN支持更加方便了
  • 内容嵌入很赞,我用它来嵌入handlebars模板,以前整个网页是要先加载编译所有的模板文件才能运行其他js的
  • 支持定制自己的fis,这个巨有用,我以后都不用给其他jser安装各种工具了

还有一点,我非常喜欢fis的架构,有点像nginx,也有11个阶段,非常的优雅。

但是,在使用过程中也存在问题,因为我是整个项目一个fis配置,在release时要耗时3秒以上,时间有点长啊,到底是哪个因素会影响它呢?文件数量,还是大小?这点还没有弄懂。

我想知道,fis除了我已经使用到的能力,还有什么能够对我公司这种前端规模的项目带来好处呢?

@googleyufei

fis-conf.js所在目录即整个工程目录,所以如果整个目录下有很多文件,fis在构建的时候是会全部文件收集起来再作处理的,所以文件查找会成为时间大头。但一般情况下前端工程也不会出现个别多的文件,如果你的工程里混有一些非前端代码,比如nodejs的node_modules等,建议用 fis.config.set('project.exclude', /正则/); 来排除掉。

当然,有些前端工程确实特别大,我们在百度的时候采用的做法是把一个网站的代码拆成多个子系统,每个子系统一个fis-conf.js,每个子系统一个svn仓库,子系统可以独立编译、独立上线发布。这样系统的并行开发程度就提高了很多。子系统中有一个特殊的子系统,叫公共资源子系统(common),其他子系统不允许有相互的资源依赖,只允许它们唯一依赖公共资源子系统。而依赖的功能是通过模块化框架实现的。

全部放在一起也没有什么问题,就是构建速度差一些,代码合并会多一些,规模上会有一定的瓶颈。分开来也会有一些小问题,而且框架设计成本略高,有时候甚至要在后端模板层实现一套后端的模块化框架,略麻烦。

你用的spmx是我之前一个下午随便搞的,不是很严谨,也没有充分考虑到seajs的设计理念,所以可能用起来效果稍差一些,如果有需要可以在spmx的issues里提,我尽量满足,或者给你们开权限,以及npm上的发布权限,如果可以将它发展成一个强大的解决方案,那真是一件非常不多的事情。

fis从你的描述中我已经感觉你们用的比较好了,这里我可以做一个总结和补充:

关于前端工程的核心问题

说的有点大,其实呢,前端工程只有两个核心问题:

一个是 资源定位,另一个是 模块化开发

模块化

前端工程的所有工作都是围绕着这两个核心问题展开的。资源定位的主要**就是将 工程路径 转换为 部署路径,也就是把相对路径变成绝对路径并且加上md5戳和域名。这样做的目的是解决静态资源缓存更新的问题,同时为模块化开发这个问题做准备。因为只有将所有相对路径转换成绝对路径才能实现模块的独立性,模块才能被任何地方使用都不用担心里面资源加载的问题。你所喜欢的内嵌功能,也是要建立在路径转换的基础上,因为内嵌会改变路径关系,绝对化处理可以让任意文件间的内嵌成为可能。

模块化开发呢,在解决了资源定位的前提下,核心问题就是依赖管理和加载了。fis最推崇的做法就是:

尽量依靠框架实现,最少依赖构建工具处理。

就是说,尽量不要让构建工具做太多事情,因为那很黑盒,fis的设计是,构建工具只负责生成依赖关系表,这就足够了,然后框架自己决定什么时候该加载哪些资源,表的关系可以让框架加载时完成按需、请求合并等需求。

基于上述设计理念,能发挥fis最大价值的地方就在于如何利用静态资源依赖表来实现一个合理的模块化框架。

spmx是我根据seajs的模块化设计而做的适配,其实可以更精简一些的。我到UC之后根据他们的业务特点与小伙伴 @hinc 又设计开发了一个模块化框架,并以此衍生出了一套解决方案,可以作为你们的参考。今年还做了一个分享,可以看看:

@googleyufei

前端工程可以在 前端开发性能优化持续集成自动部署模块生态、甚至 CMS运营系统 中都能发挥功效,其中CMS运营系统的前端工程化实践我们还在探索中,你可以看一下自己团队还有哪些需要补充。

模块化框架和工具做好了之后,就在模块化框架里做性能优化,比如请求合并、按需加载、localstorage缓存(移动端)等,然后就是开发过程和持续集成与部署结合,内网搭建jenkins,提交即构建,构建结果存放到代码仓库 ,然后实现部署推送。接下来将历往项目中的通用模块抽取出来,放到生态里,比如GitHub上,然后在开发工具中集成一个install的小工具,用于项目初期获取这些模块,可以进一步提高效率。

CMS运营系统,这个我们现在只是做了个初步的东西,还很不成熟,以后再拿出来跟大家分享。

高大上,学习来了。

well done ~ continue to heat

现在的框架,缺少对前端模块化的支持

看了你的文章,收获颇多!对于刚接触前端的同学!读的有点累!以后是否按照做一个项目或者是产品的方式来讲解呢?是不是更接地气一点?期待你的“如何攒一套前端集成解决方案”?这样的文章发表!!!谢谢

@lixiansky 我觉得可以先熟悉吧, 刚接触前端分为两种, 一种是后端转前端, 一种是纯新手。
都建议多阅读, 然后实践(不一定是基于fis/scrat)的实践, 文章里面的都是前人踩坑的总结, 如果你没真正踩过坑,就不一定好理解。
如果是后者,只需了解前端工程有这些概念,直到遇到的时候再思考下如何处理。

就我自己而已, 之前阅读过一遍几篇blog,但也只限于知道。
最近实地搭建的时候,反复阅读了很多次, 也跟云龙点对点沟通了很多次,才逐渐理解。

至于你期望的讲解方式, 我觉得 #2#3 就很不错 。

@atian25 谢谢你的解答!还是得自己动手做东西!!!完全看文章还是不行的!以后多动手做东西!估计那时在看这篇文章就有所感悟了吧

来学习,很赞

正在学习中,突然发现之前的眼光太过狭隘,前端也是一个庞大的工程

龙哥,拜过.....

@fouber 以前看过这篇,后来又看了还是不太懂,现在再看,开始懂了些
我有个问题请教下。'因为只有将所有相对路径转换成绝对路径才能实现模块的独立性,模块才能被任何地方使用都不用担心里面资源加载的问题。'这句话,组件或者模块内部为什么要把相对路径转化成绝对路径呢?对于独立的模块,不依赖与其他模块,对于这个模块的一些资源的引用写成相对路径不是更好一些么
我记得以前看的时候也有这个问题。忘云龙哥不吝赐教

@Galen-Yip

最常见的例子就是处理css合并了,css中经常会有图片资源的路径引用,如果保留相对路径,会对css文件合并带来很多负担。有这么几种情况:

  1. 代码中使用相对路径,合并后不做任何路径处理。这种情况下,有两种开发模式:
    1. 所有css在同级维护,构建中合并css,并且合并后的css也是同级目录。优点是不依赖工具,简单直观。缺点是不能把css和对应的html、js维护在一起,而且项目变大之后一个目录下都是css文件,又不能分二级,很恶心。
    2. 所有css中写图片路径的时候,都是写那个合并后文件的相对路径。优点是css可以分级,但是写资源地址要时刻想着是在另外一个文件中使用的,这和写绝对路径有什么分别?而且IDE不友好,很多IDE会报错,别小看这个,很多程序员都是神经质,烦。
  2. 代码中使用相对路径,合并后根据合并后生成的文件的位置做相对路径计算。解决了1.2中的问题,通过工具重新计算相对路径。缺点是同一个文件只能被合并,不能被其他方式复用,否则会带来相对路径不一致问题。而且这都用上工具了,为啥不直接转成绝对路径。
  3. 代码中使用相对路径,合并后替换成绝对路径。先说缺点,依赖工具,没了。然后说说优点:
    1. 开发中使用相对路径,各种直观与友好
    2. 没有规范,组件任意移植,部署路径都能正确
    3. 目录任意分级,可以实现完全的组件化/模块化开发
    4. 有些时候,我们可能需要把css的文件嵌入到js中,通过js动态插入到页面上,或者嵌入到html的style标签中使用,转换成绝对路径永远不用担心资源找不到的情况
    5. combo随便,还是因为资源定位都是绝对路径。

js也有相同问题,当你在js中想要通过逻辑加载一个图片、加载一个css文件,加载其他js文件的时候,使用绝对路径可以让这个js无论在哪个页面,无论在哪一级路径下都能正确运行,有百利而无一害。(其实路径会很长,算是一害)。

有了绝对路径,资源的合并、复用、移动才能不被运行时的文档路径限制。我觉得,绝对路径才叫资源定位,才是真实的完整的定位信息,相对路径更像是一种“变量”,它使得同一段代码在不同的路径下执行会有可能发生定位错误。

其实前端页面也是一种GUI软件,传统的桌面软件,所有程序资源都部署(安装)在客户端,所以从来没有在资源上遇到过想前端的这种的定位概念。前端程序资源是部署在其他设备上的,通过运行时加载到客户端来执行,这种程序资源部署上的差异我觉得正是前端工程与GUI软件工程的最大区别,几乎所有前端开发、维护、模块化、性能优化等特殊的工程问题都是围绕着这个差异点产生的。

@fouber 痛哭流涕 感激不尽
没有考虑到合并css这个的问题 不过确实 绝对路径才能叫做真正的资源定位
获益颇多 深受启发

学了

写得相当赞!!!

相当赞,mark

@fouber 请教一下,关于性能优化方面,比如说排查网站内存泄露情况,有什么好的建议

@majianxiong

case by case

我们是企业网站,网站在使用过程中内存一直再涨,界面结构主要是通过tabpage + iframe实现的多TAB页界面菜单,通过在关闭tabpage 的时候释放iframe。但是好像只解决了部分的问题。

@fouber 不知道前端这块有没有关于内存监控这块的工具,可以帮忙定位需要优化的代码

这个,需要手动清除下吧,直接remove掉iframe,ie下内存基本不会被释放

发自我的 iPhone

在 2015年4月17日,上午10:17,majianxiong notifications@github.com 写道:

我们是企业网站,网站在使用过程中内存一直再涨,界面结构主要是通过tabpage + iframe实现的多TAB页界面菜单,通过在关闭tabpage 的时候释放iframe。但是好像只解决了部分的问题。


Reply to this email directly or view it on GitHub.

@fouber 下面是关于内存释放的代码

/*
 * Internet Explorer释放内存的函数。
 */
function iframeDestroy( $iframe ){
    if ( !$iframe.length ) {
        return;
    }
    var ifrElem = $iframe.get(0),
        frameWin = ifrElem.contentWindow;

    try {
        ifrElem.src = 'about:blank';
        frameWin.document.write(''); // 清空iframe的内容
        frameWin.close();
        frameWin.document.clear();
    } catch( e ){

    }
    try {
        if( $.browser.msie ){
            CollectGarbage();
        }
    } catch( ex ){
        // 不支持该函数调用
    }

    // $iframe.remove();
}

@majianxiong

写一个空的html,命名为 blank.html,然后:

/*
 * Internet Explorer释放内存的函数。
 */
function iframeDestroy( $iframe, callback ){
    if ( !$iframe.length ) {
        return;
    }
    var ifrElem = $iframe.get(0);
    ifrElem.src = 'blank.html';
    $iframe.on('load', callback);
}

用空页面去卸载资源占用。如果仅仅是打开文档清除DOM,iframe的那些js内存占用还在啊。

@fouber 呵呵,谢谢了,还想问下,对于前端内存方面的优化,有什么方案策略没?

@majianxiong

没有通用的手段,都是case by case的定位、分析和解决

@fouber 谢谢!

Mark,学习了

@fouber 有使用过Google 的开发工具来定位内存泄露吗?始终还是没弄懂这个工具在内存分析方面的精髓

公司只有自己搞前端,但是也想形成一整套的前端解决方案和规范化的流程,为后人铺路,向产品负责。各位大大指点一下吧。

看到这边大牛挺多的,提个不太相关的个人问题。不知道能否有幸得到各位大牛的解答。

先说说个人情况:
我学前端大概是 1 年吧,单个页面的制作不成问题。但是最近开始实习,甚至 1 年之后就要找前端开发的工作了,肯定会接触到整个网站的开发这样的需求和业务。但是在此也有所疑惑。

估计搞前端开发的都有这样的体会:网上的教程,包括书籍、视频教程等待,在教授我们前端知识时,绝大多数都是从知识点入手的,而不是以实践为出发点。所以估计很多前端开发的孩纸,包括我自己,都会遇到这样的问题:知识点都知道,但是真要实践起来,总会有各种思路上的问题没理清,譬如:

  1. 一个大型网站前端页面这么多,相同类型的页面怎么快速分类(相同类型页面不需要重复开发),并快速确定具体有多少个页面需要开发?
  2. 网站页面这么多,能否使用 组件化 的思路来写 HTML?(我先解释下,我所理解的 组件化 HTML 是什么:例如,整个网站使用同样结构的导航栏,那么是否可以单独把导航栏的 HTML 独立成一个 HTML 文件,我称之为 组件化导航栏 ,其他页面在开发的时候就不需要把导航栏的 HTML 写进去了,只需要浏览器在请求该页面时,由后台服务器将 独立的导航栏 HTML 嵌入到请求的页面中,合并成一个完整的 HTML 文件,输出给用户。 我觉得这种方式,对前端页面开发的效率会有很大程度的提升。试想如果一个网站有 50 个页面,每个页面都需要前端开发人员复制粘贴同样的 导航栏、页面 footer HTML,这将是一个很蛋疼的工作
  3. 不知道上面 2 中这种方式是不是 CMS 的工作方式咧?

说一说我为什么会想到这几个问题:
学前端开发一年有余,单独的页面都会写,但是没遇到过整站的开发工作。玩过 Wordpress,但不懂 PHP,没碰过 Wordpress 的主题开发,所以对 CMS 的工作模式不是很了解。
但我一直致力于提高前端性能和开发效率,所以最近在看和学 前端 Workflow ,并决定把所学用到即将开始的一个单页面网站开发中去。

这个前端 Workflow 的主要技术是这样的:

  1. 使用 npm 作为依赖管理;
  2. 使用 YEOMAN 作为项目初始化工具;
  3. 使用某个开发者开发的 YEOMAN Generator,作为项目脚手架,这个脚手架包括的技术点:YEOMAN、H5bp(HTML5 模板)、Gulp(实现项目开发过程中的文件监听、开发完成后文件打包等,还有 CSS、Javascript 检查、合并、自动添加时间戳,以及图片的压缩、雪碧图制作等等)

这种前端 Workflow 很好地解决了很多前端开发中很麻烦复杂的事情,可是我看着看着,发现这套流程对 HTML 好像没什么用。由于整套流程对 CSS 和 Javascript 实现了很多上面提到的 组件化 思路,但是对 HTML 貌似没有涉及,所以很自然而然地,我就想到了一开始上面的三个问题了……

那三个问题,简单地总结起来,然后再经过一点点延展,大概是这样的:

  • HTML 是否可以实现组件化,像 CSS 和 Javascript 一样实现合并?
  • 如果目前技术没达到,但是觉得这个想法在现在时刻都说前端组件化的前端开发环境下,很适用啊?而如果业内还没有这样的最佳实践,那具体是什么原因导致的呢?
  • 是否有比我上面提到的这个想法更好的想法,正在业内实践多时,只是我不知道?如果有,是什么?
  • 现在前端大热的 React,以及其他一些宣传组件化的开发框架等,它们所说的 组件化 跟我上面提到的组件化,是同一个概念吗?(我看过一些文章,前端大热的组件化貌似是一个功能点力求用尽可能小的颗粒度来区分,貌似也会涉及到 HTML 文件的 分治
  • 业内的大型网站,比如腾讯公众平台这样功能点也蛮多的项目,到底是用 CMS 写出来的,还是前端开发人员一个个页面,每个页面一个 HTML 文件这样开发出来的?
  • 还有一种需要 变化 的功能点,是怎么实现的?(例如,网站登录前和登陆后,用户栏分别有不同的 HTML 和 CSS 样式,这个前端开发怎么顾及?开发流程和开发逻辑是怎样的?HTML 和 CSS 写在同一个文件里?

麻烦分点描述一下,先谢了!

@Loyalsoldier WordPress 的主题就是你说的那种组件化,不过那不是 HTML 组件化,而是通过 PHP 实现的。通过诸如 header.php、footer.php、category.php、single.php、comments.php 这样的文件组织页面

如你说的根据用户不同登录状态改变页面局部,也是通过 PHP 判断状态然后输出不同的 HTML。HTML 本身只是一个标记语言,并没有逻辑判断等功能,这些都是后端的事

nimoc commented

@Loyalsoldier
回复一下最后一点:

还有一种需要 变化 的功能点,是怎么实现的?(例如,网站登录前和登陆后,用户栏分别有不同的 HTML 和 CSS 样式,这个前端开发怎么顾及?开发流程和开发逻辑是怎样的?HTML 和 CSS 写在同一个文件里?

这种根据数据显示不同的效果是使用模板引擎实现的,这里的数据指的是用户登录状态。

传统方式

前端实现登录前 header 和登录后 header ,在注释中说明登录前 header html 样式和登录后 header html。最终是一份或多份HTML,将这个HTML交付给后端。后端会转换为后端的模板引擎代码,例如:

前端开发的html文件:

<!-- 未登录情况 -->
<ul>
    <li>
        <a href="/login.html">登录</a>
        <a href="/register.html">注册</a>
    </li>
</ul>

<!-- 已登录情况 -->
<ul>
    <li>
        Nimo 欢迎您!
    </li>
</ul>

后端将HTML转换为后端模板:

<ul>
    <li>
        {{if $user}}
            <a href="/login/">登录</a>
            <a href="/register/">注册</a>
        {{else}}
            {{$user.name}} 欢迎您!
        {{/if}}
    </li>
</ul>

前端渲染方式

由前端使用 AJAX获取 JSON,这个JSON包含了用户信息。前端将这个JSON(数据)与前端模板引擎结合渲染页面。

$.getJSON('/user/', function (data) {
    /*
    // 已登录返回用户信息
    data: {
        "user": {
            "name": "nimo"
        }
    }
    // 未登录返回空对象
    data: {

    }
    */

    var tpl = '<ul>'+
                '<li>'+
                    '{{#if user}}'+
                        '<a href="/login/">登录</a>'+
                        '<a href="/register/">注册</a>'+
                    '{{else}}'+
                        '{{user.name}} 欢迎您!'+
                    '{{/if}}'+
                '</li>'+
            '</ul>'
    // Handlebars 是前端模板引擎
    var template = Handlebars.compile(tpl)
    var header = template(data)
    $('#header').html(header)
})

直接由前端书写后端模板

第一种后端“翻译HTML”的方式需要前端在HTML中写上大量的注释和说明。第二种前端渲染不是每个项目都适用。为了提高工作效率前端就开始利用一些mock server(模拟后端渲染服务器)直接写后端的模板。每次开发时候不是写HTML,而是在mock server 中定义页面渲染所需的数据和页面模板。直接写

user.php

<ul>
    <li>
        {{if $user}}
            <a href="/login/">登录</a>
            <a href="/register/">注册</a>
        {{else}}
            {{$user.name}} 欢迎您!
        {{/if}}
    </li>
</ul>

mock server 配置

$.view({
  url: '/user/',
  data: {
     user: {
         name: "nimo"
     }
  },
  template: 'user.php'
})

前端开发结束后只需要将模板和页面渲染数据文档交付给后端同事即可。(这里的数据文档指的是哪些页面需要什么数据)


这里的mock server 都是前端自己开发的。与后端正式环境所用服务器不一样。仅作为前端测试用。

mock server 每个团队的实现不一样。比如 fis 有 fis server ,我们是自己实现的 node server。

当然有些团队是不使用 mock server 的直接在PHP正式环境中开发,但开发效率没有在mock server 中自由模拟方便。


前端接管后端模板的开发不只是优化后端“翻译HTML”的工作流程,前端可以利用模板引擎做很多前端工程的事。关注 FIS和 fouber 其他文章会发现前端工程是需要和后端模板引擎精密结合的(与后端框架紧密结合)

可参考这个项目 http://demo.fmsjs.org/ https://github.com/nimojs/fms-demo

@nimojs
直接由前端书写后端模板 这种方法是否就是前后端分离
POSTMAN 这个 Chrome 插件就是你所说的 mock server 的一种吗?

Mock server 这块不太懂……

nimoc commented

直接由前端书写后端模板应该不属于完全的前后端分离,但是是一种低成本高回报的解决方案。大公司包括一些小团队也都在以这种方式开发。好的工作流程里后端模板应该由前端写

POSTMAN 也可以算是 mock server ,但是他不能模拟页面渲染只是模拟AJAX。完整的 mock server 应该能渲染任何后端模板引擎。

@nimojs 很赞同mock server 的方式,但是,有个疑问,比如,前端模拟调试的时候,用mock server,渲染的时候,名称叫 {{$u_name}},但是,后端他们写代码的时候,也许用的是{{$user.name}}。
这种命名上的不同,如何解决和避免?
另外,有没有好的mock server推荐?最好能直接使用,重新开发一个mock server感觉成本略高。

nimoc commented

@zhangwenan mock server 会改变前后端开发流程,所以需要增加数据约定这个步骤。
我们团队利用 fms 写好mock代码后会自动生成文档

我们将这个文档交付给后端,后端按照文档中的数据从 Controler 向 View 传递数据即可。

mock server 可以用FIS的 mock数据

也可以用我开发的 FMS (Front Mock Server)
请先参考示例,后续更新模拟AJAX和模拟后端模板引擎渲染文档。
https://github.com/nimojs/mock-server-demo

// 引入 fms
var fms = require('fms')

// 让 fms 监听 127.0.0.1:3000
fms.run({
    port: 3000
})

// 配置 ajax post 响应代码
fms.post({
    title: '登录',
    url: '/ajax/login/'
}).ok({
    status: 'success'
}).error({
    status: "error",
    msg: "密码错误"
})

PHP 直接解析HTML渲染模拟


名称叫 {{$u_name}},但是,后端他们写代码的时候,也许用的是{{$user.name}}

如果使用 Mock Server 后端模板是前端写的,不是后端写。后端只需要根据文档从 Controler 向 View 传递数据。

@nimojs @fouber
modjs 能用来加载css么,我在js里这样写,fis3 release的结果包含了css,但同时也会报错说找不到less/index模块。

    <script type="text/javascript">
        require.resourceMap(__RESOURCE_MAP__);
        require('less/index.less')
        require('common-ui:/js/components/main');
    </script>

如果我写成:fis3 release 后会路径并不会被替换,这个位置因为对less的预编译和发布时的地址转换会导致找不到文件。

require.loadCss({url:'./less/index.less'});
oldfu commented

学习了!

求教,在不用独立部署的应用之间进行界面集成,应该会存在跨域的问题,不知道大家是怎么解决的呢?

nimoc commented

@majianxiong
界面集成是什么意思?

www.a.com/header/index.htmlwww.b.com/footer/index.html 组合在一起?

@nimojs 意思是说,将多个独立的系统在界面端集成在一起,让用户觉得就是一个应用。类似于门户网站(portal),但是不想用portal来实现。

nimoc commented

我没有这样用过,但是fouber 在博客文章中有说过。
百度的一些页面是跨部门协作的,一个页面由多个前端部门开发的模块拼装而来,都是基于 FIS 的静态资源表实现的。

建议看看这篇 前端工程——基础篇

@nimojs 与界面跨部门协作没关系,与界面应用分开独立部署,然后集成到一起,当互相访问时(iframe),因各自应用访问地址不一样,会存在跨域的问题。

道理是非常到位的,就是觉得达到整体流程的流利运作或者说无缝串联是个难于上青天的事!部门与部门之间有技术、职责、以及个人责任感的局限性,达不到完全统一的效果。只能说做到最优的最大化,这个最大化实际上也是很小的。

看了好几次了,每次看一遍就有更深的认识。没看完一回就会研究一小部分,感觉要完全实现还有很长的路要走呢!

mishe commented

收藏转帖mishe/blog#78

xuess commented

不错。。

赞,时隔两月再次阅读,对文章中讲的很多东西有了更深的理解。

最近在学习前端集成构建。了解过fis3,感觉很是不错,有些遗憾的是没有把测试加进去。不知道测试这块有计划加入?

mark

龙哥一下子铺开了前端工程应该掌握的知识体系,非常感谢。前两天还在为前端工程的事情发愁,看了龙哥的文章觉得努力方向灰常明确了。

不得不赞一个,Github还可以这么用,当博客了~

@nimojs 你这里的流程是前端定义数据接口(前端驱动型),完善文档,然后后台接口返回对应的数据。
其实好多公司的流程正好和这个相反,后台定义接口(和前端会有一些约定),然后更新接口文档,前端根据接口文档来调试,或者mock数据等

nimoc commented

@haledeng

  1. 后端定义接口 + 最终前端提出修改意见
  2. 前端定义接口 + 最终后端提出修改意见

选哪种方式根据公司时间情况决定,谁来主导也不重要,只要大致流程是

  1. 先阅读接口并编写文档
  2. 前端根据接口文档调试模拟 ajax 模拟后端模板渲染,后端根据接口文档coding 测试。

就可以了

nimoc commented

@haledeng
最好是前后端共同在一个在线平台编写接口文档,最终接口文档系统生成一个本地 node 环境,供前端测试模拟。

在线平台可记录修改记录和强制编写修改原因。
有时候还需要对接口的修改做版本控制

mark

学习了,两年过去了,读了之后仍然很有收获

文中提到的工程角度,能否具体描述一下,谢谢

读过之后还是很有收获的,来学习了,谢谢

学习哈!谢谢分享!


http://www.laoguo.xyz/

mark

666

菜鸟,问一下,前端包括那些切图的事儿吗?

你成功的逗笑了我。

图裂了

14的你还是程序员,19年的你已经是创始人