在JavaScript模块化和闭包和JavaScript-Module-Pattern-In-Depth这两篇文章中,提到了模块化的基本思想,但是在实际项目中我们还需要考虑哪些问题呢。知道问题在哪里,google大法就可以上场了。
前端工程的问题
JavaScript的模块化
流行的模块化解决方案现在有很多,主要分为以下两种规范
- AMD:AMD 规范是JavaScript开发的一次重要尝试,它以简单而优雅的方式统一了JavaScript的模块定义和加载机制,并迅速得到很多框架的认可和采纳。这对开发人员来说是一个好消息,通过AMD我们降低了学习和使用各种框架的门槛,能够以一种统一的方式去定义和使用模块,提高开发效率,降低了应用维护成本。
- CommonJS:node.js的方式,在前端需要打包工具配合使用。在后端比较好用。
我们站在开发的角度,当然希望一种规范打天下,但是现实情况往往复杂,需要不同的解决方法,这时候我们一般会增加层次,进行包装,比如在前端可以用node规范,用构建工具进行打包。
JavaScript的模块化需要解决下面几个问题
- 定义模块
- 管理模块依赖
- 加载模块
- 打包
- 包管理
CSS的模块化
- sass
- less
- 其他
CSS的模块化要解决CSS语法的一些问题:
- 没有变量
- 没有函数
- 不能嵌套等
- 文件不能互相引用
HTML的模块化
后端模版,前端模版和各种webapp框架都可以提供这种能力
- Jade:node.js的后端模版,基本上每个web框架都有一个默认的后端模版引擎
- ember.js:因为前端使用handlebars,所以有好感,不重复造轮子才是好人
- angular.js:不推荐使用,学习曲线比较陡峭,大部分概念在前端不适用,实际上把面向对象和很多设计模式拿到前端,属于探索性质,没有太多实际意义。
- backbone.js & marionette.js:我比较喜欢,因为简单可靠,backbone本身并不提供MVC中V的能力,可以考虑marionette
- react.js:现在很火,一直没机会实践
- handlebars.js:这个比较好,就是一个模版引擎,前后端都可以用,可以配合backbone和ember使用
当然,webapp的框架一般都提供了js的模块化管理能力,这里主要看中她们对html的模块化设计。
HTML模块化要解决:
- 数据绑定
- 定义界面组件
- 组装界面组件
- 输出渲染界面组件
- 性能的优化
组件化
解决了模块化问题以后,我们需要把页面按照功能分离出来,组成一个个模块,这样复合面相对象和分治的思想,也方便复用。
- 组件化:开发的时候分好功能模块
- 组件仓库:独立出模块,放到组件仓库,比如npm
开发
- 文件监听: 文件改动时自动编译
- 页面自动刷新:基于文件监听功能,当代码改动的时候,自动刷新浏览器
- 调试插件:ember等webapp框架都有自己的浏览器调试插件
- 开发脚手架:rails的流行可能和方便的cli脚手架关系密切哦,打一个命令mvc都相应的在合适的文件夹下出现。
- 合理的目录结构:
- 按组件划分文件
- 支持多个应用
- 资源定位:资源定位能力,可以有效的分离开发路径与部署路径之间的关系,工程师不再关心资源部署到线上之后去了哪里,变成了什么名字,这些都可以通过配置来指定。而工程师只需要使用相对路径来定位自己的开发资源即可。这样的好处是 资源可以发布到任何静态资源服务器的任何路径上而不用担心线上运行时找不到它们,而且代码 具有很强的可移植性,甚至可以从一个产品线移植到另一个产品线而不用担心线上部署不一致的问题。
- 内容嵌入:内容嵌入可以为工程师提供诸如图片base64嵌入到css、js里,前端模板编译到js文件中,将js、css、html拆分成几个文件最后合并到一起的能力。有了这项能力,可以有效的减少http请求数,提升工程的可维护性。
- 依赖声明:按需加载资源
打包构建
模块化可以解决开发中代码管理,团队分工的各种问题,让小组成员集中精力完成自己的模块并复用模块。当我们的项目完成后,接下来的问题就是打包。
打包这里面有个核心问题就是静态资源合并和如何让浏览器加载页面更快速。
- 为了快速,不能过多的请求文件(合并请求)
- 为了快速,请求文件越小越好(按需请求)
- 为了快速,命中缓存的次数越多越好(浏览器缓存,CDN缓存,服务器缓存)
现在最流行的是基于task的任务管理工具,核心任务之一就是打包喽:
- grunt
- gulp
- webpack:模块加载和打包功能(非taskbase)
打包需要解决以下问题:
- javascript最小化,合并,验证
- css最小化,合并
- html模版的编译
- 静态资源的管理
- 静态资源的版本,比如加时间戳或者md5后缀
- 图片base64嵌入
- 资源的引用
- 解耦开发规范和部署规范:开发目录和部署目录可以配置,不依赖相对路径
持续集成
- 挑选一个喜欢的前端测试框架。
- 提交代码后自动跑测试脚本。
- 及时反馈给提交代码的人,是否提交有问题(多人合作的时候比较重要)。
但是测试一般用在对接口输入输出做白盒测试,自动测试界面的monkey测试或者更高级的模拟人点击的测试方法也可以在这个阶段尝试自动化(monkey测试就是计算机脚本模拟人的点击行为,胡乱点击测试,)。功能性的测试还是人去测试比较好,这边的CI目标主要是提前发现代码有没有不符合规范,或者build失败等比较初级的任务,如果很要写复杂的测试用例,开发起来不比做一个功能简单,浪费开发大量精力,一般只有很大的公司才有资源做吧。
给大家推荐一个很好用的工具组合,jira+git+gerrit+jenkins。jira用来项目管理,git用来代码版本管理,gerrit用来review代码,jenkins用来跑测试,对java,JavaScript等语言也可以检查代码错误和风格,让开发人员提交的代码更符合规范。
发布
打包好了以后,需要发布,发布也有几个问题:
- 不同版本如何管理
- 静态资源的发布问题:如CDN如何更新
- 增量更新问题
- 线上性能问题(这个不是发布可以做的事情,主要是发布后需要考虑,所以放在这里了):
- 请求合并
- 按需加载
运行监控
当我们的服务运行以后,需要监控web server的运行状态,服务器的运行状态,设置报警机制,现在的云服务提供上一般都有服务器运行情况,恶意攻击的报警,我们在选择的时候注意提供商提供的这类服务也是很有必要的。
上面只是一个大纲,姑且先把问题总结出来,欢迎大家来补充。
但是为啥简单的编写页面变得这么多问题呢?我想这和web技术在不断快速发展有关,目前还没有一个非常成熟的整体解决方案出来。web比传统的PC客户端程序复杂,浏览器是一个通用的客户端,所展示的页面都是从服务器获取的,这里就有网络延迟的问题,浏览器解析性能问题等等。想到以前曾经写过的windows客户端程序,在微软的集成开发环境visual studio中,拖拖拽拽就开发好了项目,资源管理也有比较成熟的方案,使用的开发语言也是C++,C#这种支持模块化,面向对象的语言,顿时感觉前端开发在工程管理上的复杂性了。
好了,现在我们如何解决这些问题呢?
前端工程解决方案
很确信ruby on rails
可以解决上面所有问题,给大家推荐一个学习ruby和rails的好地方:learnruby,需要vpn。。。这里我们手动打造一套解决方案,有些方案需要后端支持,比如后端模版和一些性能优化方法。
在《JavaScript模块化-require.js,r.js和打包发布》这篇文章中,我们看到require.js,r.js,grunt配合使用来打包和发布的一个过程,可以说已经适合小型网站的使用了,但是我们一一对应上面要解决的问题,看看是否能够满足我们的需求。
|需求|老方案是否可以满足|备注|
|---|---|
|js模块化|可以|require.js可以满足|
|css模块化|可以|grunt,gulp可以用来执行编译sass,less的任务|
|HTML模块话|可以|使用webapp框架或者模版技术|
|组件化|可以|划分好目录和打包规则,代码编写需要模块话|
|组件仓库|没有涉及|老方案并没有考虑建立npm这种组件仓库|
|文件监听|可以|grunt,gulp可以做到|
|页面自动刷新|可以|grunt,gulp可以做到|
|开发脚手架|没有考虑|老方案并没有|
|合理的目录结构|没有考虑|老方案希望开发人员自己定义目录结构|
|资源定位|不可以|老方案需要让开发规范和发布规范一致,依赖相对路径|
|内容嵌入|不可以|老方案没有考虑这个问题,需要使用url,请求次数比较多,或者只能手动嵌入,比如base64的图片|
|依赖声明|可以|require.js配合插件text可以管理各种资源的依赖,并按需加载|
|合并文件|可以||
|最小化文件|可以|grunt,gulp任务的最常见的一种|
|模版的编译|可以||
|缓存管理|没有|打包后缓存的命中会下降|
|文件的版本|没有|导致发布是覆盖模式,缓存容易失效|
|图片的合并嵌入|可以|比如制作css sprite|
|开发目录和部署目录解耦|没有仔细考虑|只能通过相对路径,而相对路径之间的关系不能改变|
|CI|可以|可以设置自动化任务跑测试|
|配置CDN|没有考虑||
|增量更新|可以|rsync工具|
|请求合并|没有仔细考虑|只是把文件合并在一起,并不支持同时返回多个文件,需要服务器支持|
|按需加载|没有仔细考虑|如果合并了文件,就不能按需加载;如果按需加载,就会导致请求数目的增加,解决这个问题需要提前知道依赖的文件的列表,利用请求合并的技术去一次性加载|
我们提出了问题,剩下的就是解决问题了,既然上一篇文章太简单了,我们需要一个复杂点的例子来看看一个中等规模的前端项目,应该如何的展开。请看下一篇文章吧。