前端架构,前端工程化

2,498 阅读32分钟
原文链接: blog.csdn.net

前端架构:

1.前端工程化

web应用复杂度的增加,特别是单页面应用的风靡。组件化,工程化,自动化成了前端发展的趋势。或者说一线的互联网公司就是这么做的。
每个前端团队都在打造自己的前端开发体系,这通常是一个东拼西凑,逐渐磨合的过程,在技术发展日新月异的今天,这样的过程真的是不可抽象和复制的么?本文希望能够通过系统的拆解前端开发体系为大家提供体系设计思路参考。

前端工程的3个阶段


第一阶段: 库/框架选型


Animate.css 
jQuery 
vue.js 
underscore.js 
React.js 
Backbone.js 
Bootstarp 
zepto.js 
jade 
normalize.css 
compass 
Angular.js 
解决开发效率


第二阶段: 简单构建优化


选择构建工具,对代码进行压缩,校验,之后再以页面为单位进行简单的资源合并。


第三阶段: JS/CSS模块化开发


解决维护效率 
js的模块化方案 
ADM/CDM/UMD/ES6 Module


css的模块化:less,sass。


第四阶段: 前端是一个技术问题较少,工程问题较多的开发领域


当我们要开发一款完整的Web应用时,前端将面临更多的工程问题,比如: 
- 大体量:多功能、多页面、多状态、多系统; 
- 大规模:多人甚至多团队合作开发; 
- 高性能:CDN部署、缓存控制、文件指纹、缓存复用、请求合并、按需加载、同步/异步加载、移动端首屏CSS内嵌、HTTP 2.0服务端资源推送。


组件化开发和资源管理


组件化开发: 
光有JS/CSS的模块化还不够,对于UI组件的分治也有着同样迫切的需求
资源管理: 
根据“增量”的原则,我们应该精心规划每个页面的资源加载策略,使得用户无论访问哪个页面都能按需加载页面所需资源,没访问过的无需加载,访问过的可以缓存复用,最终带来流畅的应用体验。
由增量原则引申的前端优化技巧成为了性能优化的核心: 
按需加载 
延迟加载 
预加载 
请求合并


浏览器的缓存


静态资源管理系统 = 资源表 + 资源加载框架


前端模块化框架肩负着模块管理和资源加载2个重要的功能


webpack已经成为了前端打包构建的主流。


开发框架则是形成了三国时代: 
React , Vue, Ng


移动端也以混合开发为主的方式,Native嵌入了Webview页面。


SPA依靠首次加载的Loading动画,来掩盖一些页面加载性能的问题。


用户验证问题,怎么来确认Native的用户身份,是用原来Web网站常用的session还是使用Native比较常用的token,但是不管用哪种,都需要Native帮忙来注入标识。


前端业务重量化,场景多样化。 
未来的趋势: 组件化。


美团的工程化


关于前端工程化,我看了美团团队的分享: 
他们分享的前端化的实践总结: 
1. 前端开发要自成体系,包括构建、部署及运维,不再和后端项目耦合,后端通过RESTful接口提供服务。 
2. 避免重量级的框架,没有一个框架可以满足所有的业务场景。 
3. 设计要分层,来应对需求和技术的变化。


前端工程化项目分为3大模块: 
1. Node服务,提供数据代理,路由,和服务器渲染,通过restful api和后端通信。 
2. web应用开发,专注于web交互体验。 
3. 前端运维:包含构建,测试,部署及监控等。


Node服务:用于实现前后端分离,核心功能是实现数据代理中转,附带url路由分发和服务端渲染功能。
Web应用开发:纯粹的前端模块,给予前端工程师极大的自由度进行技术选型,专注于Web交互体验的开发。
前端运维:主要指前端项目构建和部署、工程质量(源码质量检查和测试等)及监控服务(日志、性能等)等工作。
前后端分离: 
- 为了前后端彻底的分离,引入Node服务层。 
- 即在Node端通过HTTP请求得到数据后,Web端再通过Ajax的方式从Node端间接获取后端数据,Node服务起到“桥梁”的作用。 
- 路由分发 
- 服务器端渲染:Node服务端最后一个核心功能是渲染:输出 HTML Shell和 JSON。输出JSON字符串的用途是为了浏览器端能以Ajax形式动态获取数据,而输出的HTML内容则是我们Web应用的所需的HTML“壳子”。


这主要是SPA的快速发展,前端的用户体验大幅提升。


静态资源与Node端衔接: 
- 前端静态资源构建工作与Node服务相互分离,Node服务在开启的过程中会读取前端构建生成的静态资源映射表。 
- 静态资源映射表的生成: 
- 预编译:ES6语法转义,css预编译器处理,源码质量审查,测试 
- 模块依赖解析 
- 压缩,静态资源版本号


前端构建工具基本都提供静态资源映射表生成插件,比如构建工具Webpack就存在插件assets-webpack-plugin来实现该功能。


鼓励遵循下面几条“约定”: 
- Ajax请求从Node端代理,而非具体后端服务。 
- 鼓励将JavaScript、CSS、HTML视为前端领域的“汇编”。 
- 重视前端页面状态管理,推荐的方案有Redux、vuex及MobX等。 
- 强调组件化,面向组件集开发。
项目的脚手架,来搭建项目的开发环境。


工程质量保证,在每次的commit,同个项目要求遵循同一套编码规范,并采用ESLint等工具进行约束,对于一些复用性高的核心组件也强制要求写测试。 
甚至是接入单独的系统测试。


总结


前端工程化体系的引入,让前端开发能和原生App应用项目开发一样“自成体系”,脱离了对后端项目的依赖。基于“约定优于配置”、“按照约定写代码”的原则对Node层功能的设定能够降低沟通协调成本,构建、部署等工作的规范化,使前端技术人员的开发重点回归到Web应用的交互体验本身,回归到“纯粹”的前端研发。

或许现在很多企业和团队尚未重视前端工程,或许前端工程在很多人眼里还只是“构建工具”的代名词,又或许未来前端领域的变革使得一切工程问题从根本上得到解决。不管怎样,我只是希望当下能认真的记录自己在前端工程领域的所见所想,与正在经历前端工程化改进,并被此过程困扰的同学交流心得。

先说概念:前端工程化是使用软件工程的技术和方法来进行前端项目的开发、维护和管理(曾经的前端开发可不是这样的,不然为什么要说工程"化"呢?)。

"前端工程化"里面的工程指软件工程,和我们一般说的工程是两个完全不同的概念。

  • 工程是个很泛泛的概念,你甚至可以认为建了个 Git 仓库就相当于新建了一个工程;
  • 软件工程的定义是:"应用计算机科学理论和技术以及工程管理原则和方法,按预算和进度,实现满足用户要求的软件产品的定义、开发、和维护的工程或进行研究的学科"(GB/T11457-2006《信息技术 软件工程术语》)。

很多时候,我们的前端确实是个工程,但并不是在以软件工程的方式方法去对待它。

为什么会出现"前端工程化"这个概念?

  • "这个活动页面,给张图切一下就行了嘛";
  • "这个管理后台已经通过 XXX 脚手架生成了,页面稍微改改就行";
  • ...

前端的开发工作在一些场景下被认为只是日常的一项简单工作,或只是某个项目的"附属品",并没有被当做一个"软件"而认真对待(无论是产品负责人还是开发者)。

然而无论你如何对待它,也无法否定前端是一种 GUI 软件的事实,因此其也就必然遵循时间、质量、成本相互制约的特性。对于时间和成本的控制必然将导致最终产出倾向于出现"质量低"、"可维护性差"、"可用性差"等问题。

过去我们以牺牲质量的方式换取时间和成本,现在趟了前辈们早已趟过的坑,然后发现还是要重新审视"前端"这一软件开发活动,并且使用软件工程这套早已存在的体系去对前端项目进行管理。


目前来说,Web业务日益复杂化和多元化,前端开发已经由以WebPage模式为主转变为以WebApp(eg:https://app.ft.com/)(httpshttps其实就是建构在SSL/TLS之上的 http协议,所以要比较https比http多用多少服务器资源,主要看SSL/TLS本身消耗多少服务器资源。)模式为主了。现在随便找个前端项目,都已经不是过去的拼个页面+搞几个jQuery插件就能完成的了。工程复杂了就会产生许多问题,比如:如何进行高效的多人协作?如何保证项目的可维护性?如何提高项目的开发质量? 前端工程化是前端架构中重要的一环,主要就是为了解决上述大部分问题的。而前端工程本质上是软件工程的一种,因此我们应该从软件工程的角度来研究前端工程。 那么前端工程化需要考虑哪些因素?本人总结经验,认为前端工程化主要应该从模块化、组件化、规范化、自动化四个方面来思考,下面一一展开。## 模块化简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。只有这样,才有多人协作的可能。### JS的模块化在ES6之前,JavaScript一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍。对此社区制定了一些模块加载方案,如CommonJS、AMD和CMD等,某些框架也会有自己模块系统,比如Angular1.x。现在ES6已经在语言层面上规定了模块系统,完全可以取代现有的CommonJS和AMD规范,而且使用起来相当简洁,并且有静态加载的特性。规范确定了,然后就是模块的打包和加载问题:1. 用Webpack+Babel将所有模块打包成一个文件同步加载,也可以打成多个chunk异步加载;2. 用SystemJS+Babel主要是分模块异步加载;3. 用浏览器的<script type="module">加载目前Webpack远比SystemJS流行。Safari已经支持用type="module"加载了。### CSS的模块化虽然SASS、LESS、Stylus等预处理器实现了CSS的文件拆分,但没有解决CSS模块化的一个重要问题:选择器的全局污染问题。按道理,一个模块化的文件应该要隐藏内部作用域,只暴露少量接口给使用者。而按照目前预处理器的方式,导入一个CSS模块后,已存在的样式有被覆盖的风险。虽然重写样式是CSS的一个优势,但这并不利于多人协作。为了避免全局选择器的冲突,各厂都制定了自己的CSS命名风格:BEM风格;

Bootstrap风格;Semantic UI风格;我们公司的NEC风格;...但这毕竟是弱约束。选择器随着项目的增长变得越多越复杂,然后项目组里再来个新人带入自己的风格,就更加混乱了。所以我很赞同这句话:与其费尽心思地告诉别人要遵守某种规则,以规避某种痛苦,倒不如从工具层面就消灭这种痛苦。从工具层面,社区又创造出Shadow DOM、CSS in JS和CSS Modules三种解决方案。Shadow DOM是WebComponents的标准。它能解决全局污染问题,但目前很多浏览器不兼容,对我们来说还很久远;CSS in JS是彻底抛弃CSS,使用JS或JSON来写样式。这种方法很激进,不能利用现有的CSS技术,而且处理伪类等问题比较困难;CSS Modules仍然使用CSS,只是让JS来管理依赖。它能够最大化地结合CSS生态和JS模块化能力,目前来看是最好的解决方案。Vue的scoped style也算是一种。
### 资源的模块化Webpack的强大之处不仅仅在于它统一了JS的各种模块系统,取代了Browserify、RequireJS、SeaJS的工作。更重要的是它的万能模块加载理念,即所有的资源都可以且也应该模块化。资源模块化后,有三个好处:依赖关系单一化。所有CSS和图片等资源的依赖关系统一走JS路线,无需额外处理CSS预处理器的依赖关系,也不需处理代码迁移时的图片合并、字体图片等路径问题;资源处理集成化。现在可以用loader对各种资源做各种事情,比如复杂的vue-loader等等。项目结构清晰化。使用Webpack后,你的项目结构总可以表示成这样的函数:
dest = webpack(src, config)## 组件化首先,组件化≠模块化。好多人对这两个概念有些混淆。模块化只是在文件层面上,对代码或资源的拆分;而组件化是在设计层面上,对UI(用户界面)的拆分。从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。其实,组件化更重要的是一种分治思想。Keep Simple. Everything can be a component.
这句话就是说页面上所有的东西都是组件。页面是个大型组件,可以拆成若干个中型组件,然后中型组件还可以再拆,拆成若干个小型组件,小型组件也可以再拆,直到拆成DOM元素为止。DOM元素可以看成是浏览器自身的组件,作为组件的基本单元。传统前端框架/类库的思想是先组织DOM,然后把某些可复用的逻辑封装成组件来操作DOM,是DOM优先;而组件化框架/类库的思想是先来构思组件,然后用DOM这种基本单元结合相应逻辑来实现组件,是组件优先。这是两者本质的区别。其次,组件化实际上是一种按照模板(HTML)+样式(CSS)+逻辑(JS)三位一体的形式对面向对象的进一步抽象。所以我们除了封装组件本身,还要合理处理组件之间的关系,比如(逻辑)继承、(样式)扩展、(模板)嵌套和包含等,这些关系都可以归为依赖。其实组件化不是什么新鲜的东西,以前的客户端框架,像WinForm、WPF、Android等,它们从诞生的那天起就是组件化的。而前端领域发展曲折,是从展示页面为主的WebPage模式走过来的,近两年才从客户端框架经验中引入了组件化思想。其实我们很多前端工程化的问题都可以从客户端那里寻求解决方案。目前市面上的组件化框架很多,主要的有Vue、React、Angular 2、我们公司 @郑海波 的Regular、Avalon等。你感兴趣可以都研究一下,选择一套中意的。其实Vue文档中的对比其他框架一文已经讲得很详细了。## 规范化模块化和组件化确定了开发模型,而这些东西的实现就需要规范去落实。规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。我能想到的有以下一些内容:目录结构的制定编码规范前后端接口规范文档规范组件管理Git分支管理Commit描述规范定期CodeReview视觉图标规范...其中编码规范最好采取ESLint和StyleLint等强制措施,配置git hooks可以实现Lint不过不能提交代码等机制,因为人是靠不住的。前后端接口管理可以了解一下我们公司出的NEI - 接口管理平台。## 自动化作了这么多年程序猿的我,一直秉持的一个理念是:任何简单机械的重复劳动都应该让机器去完成。
所以我也认为,前端工程化的很多脏活累活都应该交给自动化工具来完成。### 图标合并不要再用PS拼雪碧图了,统一走Webpack吧;
不要再用Icomoon了,统一走Webpack吧。### 持续集成### 自动化构建### 自动化部署### 自动化测试前端自动化测试能够提高代码质量、减少人肉测试等,这些优点是不言而喻的。市面上前端测试框架有很多,选择哪个都不会有太大问题,我们用的是:Karma + Mocha + Chai

非要介绍的话,那前端工程化就是这些:
1. 高性能
2. 稳定性(reliability)
3. 可用性(usability)
4. 可维护性(maintainability)
5. 可访问性(accesibility)

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


前端集成解决方案,英文翻译为 Front-end Integrated Solution,缩写fis,发音[fɪs]
前端集成解决方案并不是一个新词汇,将这个词拆开来看,我们能得到:


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


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


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

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


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


攒一套前端集成解决方案


不难发现,其实其他领域工程也基本需要解决上述这些问题。前端由于其领域语言的独特性,使得前端工程在解决这些问题上跟其他工程有很大区别,因此至今也没有形成一套比较好的理论体系指导团队实践前端工程。
仔细观察过一些团队的技术体系形成过程,大家都在努力拼凑上述8项技术元素的具体解决方案。单独观察每一项技术点,你或许会觉得都能各自找到已有的实现,但我要说,把所有8项技术点无缝的串联起来,是一项非常有挑战的工作,你信么?相信真正经历过这样事情的同学能明白我说的串联成本问题。


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


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


模块化开发涉及到性能优化、对构建工具又有一定的配套实现要求,也会影响开发规范的定制
组件化开发应该基于模块化框架来加载其他依赖的组件,如果组件化框架自带模块管理功能,那么就可能导致工程性的性能优化实现困难
组件库应该与组件化开发配套,组件仓库中的组件都应该按照相同的标准来实现,否则下载的组件不具有可复用性、可移植性,就是去了仓库的意义
我们设计的开发规范工具是否能很容易的实现,如果部署上有特殊要求,工具是否能很容易的做出调整,而不是修改规范。
工具是否能提供接入公司已有流程中的接口,比如命令调用,如果工具需要一些系统环境支持,公司的ci流程中是否能支持等问题。
前端领域语言的特点决定了攒一套集成解决方案有很高的实现成本。因为前端语言缺少包、导入、模块等开发概念,这使得各个技术点的解决方案在设计的时候都是考虑被独立使用的情况下如何工作,因此或多或少的会延伸自己的职责。比如模块化框架要附属构建工具,甚至要求后端服务(比如combo),组件化框架自带模块化框架,构建工具自带部署规范等,这就大大提高了将各个技术要素融合起来的成本。


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

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


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


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

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 又设计开发了一个模块化框架,并以此衍生出了一套解决方案,可以作为你们的参考。今年还做了一个分享,可以看看:

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


模块化框架和工具做好了之后,就在模块化框架里做性能优化,比如请求合并、按需加载、localstorage缓存(移动端)等,然后就是开发过程和持续集成与部署结合,内网搭建jenkins,提交即构建,构建结果存放到代码仓库 ,然后实现部署推送。接下来将历往项目中的通用模块抽取出来,放到生态里,比如GitHub上,然后在开发工具中集成一个install的小工具,用于项目初期获取这些模块,可以进一步提高效率。最常见的例子就是处理css合并了,css中经常会有图片资源的路径引用,如果保留相对路径,会对css文件合并带来很多负担。有这么几种情况:


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


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


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