公司网站制作设,wordpress 最大上传文件大小 8m,汕头手机网页制作,济南小程序开发制作前言 一位计算机前辈曾说过#xff1a; Controlling complexity is the essence of computer programming.随着前端开发复杂度的日益提升#xff0c;组件化开发应运而生#xff0c;并随着 FIS、React 等优秀框架的出现遍地开花。这一过程同样发生在美团#xff0c;面临业务… 前言 一位计算机前辈曾说过 Controlling complexity is the essence of computer programming.随着前端开发复杂度的日益提升组件化开发应运而生并随着 FIS、React 等优秀框架的出现遍地开花。这一过程同样发生在美团面临业务规模的快速发展和工程师团队的不断扩张我们历经引入组件化解决资源整合问题、逐步增强组件功能促进开发效率、重新打造新一代组件化方案适应全栈开发和共享共建等阶段努力“controlling complexity”。本文将介绍我们组件化开发的实践过程。 组件化 1.0资源重组 在美团早期前端资源是按照页面或者类似业务页面集合的形式进行组织的。例如 order.js 对应订单相关页面的交互account.css 对应账户相关页面的样式。这种方式在过去的较长一段时间内持续支撑了整个项目的正常推进功勋卓著。 随着业务规模的增加和开发团队的扩张这套机制逐渐显示出它的一些不足 资源冗余页面的逐渐增加交互的逐渐复杂化导致对应的 css 和 js 都有大幅度增长进而出现为了依赖某个 js 中的一个函数需要加载整个模块或者为了使用某个 css 中的部分样式依赖整个 css冗余资源较多对应关系不直观没有显而易见的对应规则导致的一个问题是修改某个业务模块的 css 或者 js 时几乎只能依靠 grep。靠人来维护页面模块 html、css 和 js 之间的依赖关系容易犯错常常出现内容已经删除但是 css 或 js 还存在的问题难于单元测试以页面为最小粒度进行资源整合不同功能的业务模块相互影响复杂度太高自动化测试难以推进2013 年开始在调研了 FIS、BEM 等方案之后结合美团开发框架的实际我们初步实现了一套轻量级的组件化开发方案。主要的改进是 以页面功能组件为单位聚合前端资源自动加载符合约定的 css、js 资源将业务数据到渲染数据的转换过程独立出来 举例来说美团顶部的搜索框就被实现为一个组件。 代码构成 www/component/smart-box/
├── smart-box.js # 交互
├── smart-box.php # 渲染数据生产、组件配置
├── smart-box.scss # 样式
├── smart-box.tpl # 内容
└── test├── default.js # 自动化测试└── default.php # 单测页面调用组件变得十足简单 echo View::useComponent(smart-box, [keyword $keyword
]);对比之前可以看到组件化的一些特点 按需加载只加载必要的前端资源对应关系非常清晰组件所需要的前端资源都在同一目录职责明确且唯一对应关系显著易于测试组件是具备独立展现和交互的最小单元可利用 Phantom 等工具自动化测试此外由于前端资源集中进行调度组件化也为高阶性能优化提供了空间。例如实现组件级别的 BigRender、通过数据分析进行资源的合并加载等等。 组件化 2.0趋于成熟 组件化 1.0 上线后由于简单易用很快得到工程师的认可并开始在各项业务中应用起来。新的需求接踵而来一直持续到 2014 年底这个阶段我们称之为组件化 2.0。下面介绍下主要的几个改进。 Lifecycle 组件在高内聚的同时往往需要暴露一些接口供外界调用从而能够适应复杂的页面需求例如提交订单页面需要在支付密码组件启动完成后绑定提交时的检查。Web Components、React 等都选择了生命周期事件/方法我们也是一样。 组件的生命周期 一个组件的完整生命周期包括 init初始化组件根节点和配置fetch加载 css 和 js 资源render内容渲染默认的渲染内容方式是 BigRenderready进行数据绑定等操作update数据更新destroy解除所有事件监听删除所有组件节点组件提供 pause、resume 方法以方便进行生命周期控制。各个阶段使用 Promise 串行进行异步的管理更清晰。使用自定义语义事件在修改默认行为、组件间通信上充分利用了 YUI 强大的自定义事件体系有效降低了开发维护成本。 举个例子页面初始化时组件的启动过程实际也是借助生命周期实现的 var afterLoadList [];
Y.all([data-component]).each(function (node) {var component new Y.mt.Component(node);// 绑定 init 生命周期事件在 init 默认行为完成后执行回调component.after(init, function (e) {// 如果配置了延迟启动if (e.config.afterLoad) {// 暂停组件生命周期e.component.pause();// 压入延迟启动数组afterLoadList.push(e.component);}});// 开始进入生命周期component.start();
});Y.on(load, function () {// 在页面 load 事件发生时恢复组件生命周期afterLoadList.forEach(function (component) {component.resume();});
});回过头来看引入生命周期除了带来扩展性外更重要的是理顺了组件的各个阶段有助于更好的理解和运用。 Data Binding 数据绑定是我们期盼已久的功能将 View 和 ViewModel 之间的交互自动化无疑会节省工程师的大量时间。在组件化减少关注点和降低复杂度后实现数据绑定变得更加可能。 我们最终实现的数据绑定方案主要参考了 Angular通过在 html 节点上添加特定的属性声明绑定逻辑js 扫描这些内容并进行相应的渲染和事件绑定。当数据发生变化时对应的内容全部重新渲染。 ul classaddressListlimt-bind-repeataddr in addrListmt-bind-htmladdr.text/li
/ulscript
Y.use([mt-bind, mt-scope], function () {Y.mt.bind.init(document.body);var scope Y.one(.addressList).getScope();// 将 scope.addrList 设置为一个数组DOM 上将自动渲染其内容 scope.$set(addrList, [{ text: first address },{ text: second address }]);
});
/script使用属性声明绑定逻辑的好处是可以同时支持后端渲染这对于美团团购这样的偏展现型业务是非常必要的用户可以很快看到页面内容。 Flux 实现数据绑定后我们不得不面对另外一个问题如何协同多个组件间的数据。因为某个组件的数据变化很有可能引起其他组件的变化。例如当修改购买数量总金额会变化而总金额超过 500 后还需要展示大额消费提醒。 为了解决这个问题我们引入了 Flux使用全局消息总线的思路进行跨组件交互。 例如因为交互复杂而一直让我们非常头疼的项目购买页在应用组件 Flux 重构后各模块之间的互动更加清晰 其他方面的改进还有很多包括引入模板引擎 LightnCandy 约束模板逻辑、支持组件任意嵌套、支持异步加载并自动初始化等。 随着组件化 2.0 的逐步完善基本已经可以从容应对日常开发在效率和质量方面都上了一个台阶。 组件化 3.0重启征程 时间的车轮滚滚前行2014 年底我们遇到一些新的机遇和挑战 基于 Node 的全栈开发模式开始应用前后端渲染有了更多的可能性YUI 停止维护需要一套新的资源管理方案新业务不断增加需要找到一种组件共享的方式避免重复造轮子结合之前的实践以及在这一过程中逐渐积累的对业内方案的认知我们提出了新的组件化方案 基于 React 开发页面组件使用 NPM 进行分发方便共建共享基于 Browserify 二次开发建设资源打包工具 Reduce方便浏览器加载建设适应组件化开发模式的工程化开发方案 Turbo方便工程师将组件应用于业务开发中React 在组件化 2.0 的过程中我们发现很多功能和 React 重合例如 Data Binding、Lifecycle、前后端渲染甚至直接借鉴的 Flux。除此之外React 的函数式编程思想、增量更新、兼容性良好的事件体系也让我们非常向往。借着前端全栈开发的契机我们开始考虑基于 React 进行组件化 3.0 的建设。 NPM Reduce NPM Reduce 构成了我们新的资源管理方案其中 NPM 负责组件的发布和安装。可以认为是“分”的过程粒度越小重用的可能性越大Reduce 负责将页面资源进行打包。可以认为是“合”的过程让浏览器更快地加载一个典型的组件包 smart-box/
├── package.json # 组件包元信息
├── smart-box.jsx # React Component
├── smart-box.scss # 样式
└── test└── main.js # 测试NPM 默认只支持 js 文件的管理我们对 NPM 中的 package.json 进行了扩展增加了 style 字段以使打包工具 Reduce 也能够对 css 和 css 中引用的 image、font 进行识别和处理 {style: ./smart-box.scss
}只要在页面中 require 了 smart-box经过 Reduce 打包后js、css 甚至图片、字体都会出现在浏览器中。 var SmartBox require(mtfe/smart-box);
// 页面
var IndexPage React.createClass({render: function () {return (HeaderSmartBox keyword{ this.props.keyword } //Header...);}
});
module.exports IndexPage;整体思路和组件化 1.0 如出一辙却又那么不同。 Turbo 单单解决分发和打包的问题还不够业务开发过程如果变得繁琐、难以 Debug、性能低下的话恐怕不会受到工程师欢迎。 为了解决这些问题我们在 Node 框架的基础上提供了一系列中间件和开发工具逐步构建对组件友好的前端工程化方案 Turbo。主要有 支持前后端同构渲染让用户更早看到内容简化 Flux 流程数据流更加清晰易维护引入 ImmutableJS保证 Store 以外的数据不可变采用 cursor 机制保证数据修改/获取同步支持 Hot Module Replacement改进开发流自动化通过这些改进一线工程师可以方便的使用各种组件专注在业务本身上。开发框架层面的支持也反过来促进了组件化的发展大家更乐于使用一系列组件来构建页面功能。 小结 发现痛点、分析调研、应用改进的解决问题思路在组件化开发实践中不断运用。历经三个大版本的演进组件化开发模式有效缓解了业务发展带来的复杂度提升的压力并培养工程师具备小而美的工程思想形成共建共享的良好氛围。毫无疑问组件化这种“分而治之”的思想将会长久地影响和促进前端开发模式。我们现在已经准备好迎接新的机遇和挑战用技术的不断革新提升工程师的幸福感。