从工程化角度讨论如何快速构建可靠React组件
原文链接 前言React 的开发也已经有2年时间了,先从QQ的家校群,转成做互动直播,主要是花样直播这一块。切换过来的时候,业务非常繁忙,接手过来的业务比较凌乱,也没有任何组件复用可言。 为了提高开发效率,去年10月份也开始有意识地私下封装一些组件,并且于今年年初在项目组里发起了百日效率提升计划,其中就包含组件化开发这一块。 本文并不是要谈如何去写一个 React 组件,这一块已经有不少精彩的文章。本文关键词是三个,工程化、快速和可靠。工程化是手段和工具,快速和可靠,是我们希望达到的目标。 前端工程化不外乎两点,规范和自动化。 读文先看此图,能先有个大体概念: 规范目录与命令规范规范,主要就是目录规范和代码规范。跟同事合作,经过将近20个的组件开发后,我们大概形成了一定的目录规范,以下是我们大致的目录约定。哪里放源码,哪里放生产代码,哪里是构建工具,哪里是例子等。有了这些的约定,日后开发和使用并一目了然。 __tests__ -- 测试用例 | example -- 真实demo | dist -- 开发者使用代码 | src -- 源代码 | config -- 项目配置 |------project.js -- 项目配置,主要被 webpack,gulp 等使用 | | tools -- 构建工具 | |——————start.js -- 开发环境执行命令 |——————start.code.js -- 开发环境生成编译后代码命令 | package.json 命令我们也进行了规范,如下, // 开发环境,服务器编译 npm start 或者 npm run dev // 开发环境,生成代码 npm run start.code // 生产环境 npm run dist // 测试 npm test // 测试覆盖率 npm run coverage // 检查你的代码是否符合规范 npm run lint 代码规范代码规范,主要是写 自动化开发与发布自动化规范是比较人性的东西,凭着人对之的熟悉就可以提高效率了,至于那些工作繁复的流程,单凭人的熟悉也会达到极限,那么我们就需要借助自动化的工具去突破这重极限。 例如代码规范,单凭人的肉眼难以识别所有不合规范的代码,而且效率低下,借助代码检测工具就可让人卸下这个重担。如 css ,我们推荐使用 stylelint ,js 则是 eslint。有这种自动化的工具协助开发者进行检查,能更好地保障我们的代码质量。 自动化最为重要的任务是,去保证开发过程良好的体验还有发布生产代码。实际上,开发和发布组件的整个过程跟平时开发一个任务很像,但却又略有差异。 首先是开发过程中,我们希望一边开发的时候,我们开发的功能能够显示出来,这时最好能搭建一个demo,我们把 demo 放到了 example 目录下,这点对 UI 组件(像toast,tips等组件) 尤为重要,逻辑组件(像ajax,utils等组件),可以有 demo,也可以采取测试驱动开发的方式,先制定部份测试用例,然后边开发边进行测试验证。 开发过程中的这个 demo, 跟平时开发项目基本一致,我们就是通过配置,把 但是发布组件的这个过程跟开发项目却又很不同。开发项目,我们需要把所有的依赖都打包好,然后一并发布。但对于组件来说,我们只需要单独将它的功能发布就好了,它的相关依赖可以在实际开发项目中引用时一并再打包。因此这里的 鉴于我们项目一般采用 webpack 打包,因此我们一般只需要 es6 import 的引入方式,那我们直接用 babel 帮我们的项目进行生产代码的编译打包就可以了,这样能有效减少冗余代码。配置好 .babelrc,然后配置 babel src --out-dir dist --copy-files 但有时候,你也想组件能兼容多种引用方式,即 output: { // other config library: "lib",// 表示以什么名字输出,这里,会输出为如 exports["lib"] libraryTarget: "umd",// 表示打包的方式 }, 另一点要注意的是,我们只需打包组件的逻辑就好了,那些依赖,可以等实际生产项目的时候再进行解析。但 打包完成之后,根据指引进行 测试自动化上述讲的都跟如何提升开发效率有关的,即满足 “快速” 这个目标,对 ”可靠“ 有一定帮助,如稳定的流程和良好的代码规范,但并没有非常好地保证组件地稳定可靠。需要 ”可靠“的组件,还需要测试来保证。 不少开发者做测试会使用
测试逻辑组件问题倒不大,UI组件对于大部份的情况都可以,许多事件都可以通过 对于 test('scroll to bottom',(done) => { const wrapper = mount(<Wrapper />); window.addEventListener('scroll',function(e) { setTimeout(() => { try { // expect 逻辑 done(); } catch(err) { done.fail(err); } },100); jest.runAllTimers(); }); let scrollTop = 768; window.document.body.scrollTop = scrollTop; // 指明当前 scrollTop到了哪个位置 window.dispatchEvent(new window.Event('scroll',{ scrollTop: scrollTop })); }); 细心的你会发现,上图还有一些定时器的逻辑。原因是在组件中会有一些截流的逻辑,滚动时间隔一段时间才去检测滚动的位置,避免性能问题,因此加一个定时器,等待数据的返回,而 除此之外,定时器里还有个 安卓测完了,那iPhone呢?iPhone 的 Object.defineProperty(window.navigator,"userAgent",(function(_value){ return { get: function _get() { return _value; },set: function _set(v) { _value = v; } }; })(window.navigator.userAgent)); let str = "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML,like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"; window.navigator.userAgent = str; 然后,去找到这个绑定的元素,进行事件监听和分发就好了: const wrapper = mount(<Wrapper />),scrollComp = wrapper.find(Scroll),scrollContainer = scrollComp.nodes[0].scrollContainer; scrollContainer.addEventListener('scroll',function(e) { //... }); scrollContainer.dispatchEvent(// ... ); 总结本文主要是提取了开发组件工程化的一些关键要点,具体的开发脚手架可以参考 steamer-react-component,里面主要举了pure-render-deepCompare-decorator 和 react-list-scroll,一个逻辑组件,一个UI组件,共两个示例,对照着脚手架的文档,从目录规范、开发流程、发布都写得较为清楚,大家开发组件的时候,可以根据情况做些调整。 如有谬误,恳请斧正。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |