前端基建

这两三年我自学了一些前端知识,有幸在一个小型团队里经历了从 0 建设前端项目的整个过程。这期写写我在这次经历中的一些体会吧。 代码规范 基建的第一点自然是代码风格了,我记得早些年网上没事还在争吵 tab 是两个空格还是四个空格的问题。虽然听着有点无厘头,但是团队的代码规范就是该细节到空格层面。 Linter linter 就是所谓的代码美化工具,最常用的有eslint——javascript 的美化工具,stylelint——CSS 的美化工具。小型团队安装 lint 后就基本不要思考规范了,直接使用 airbnb,google 等大厂的标准配置即可(一般也没心思去规定小括号和大括号间隔几个空格才比较美观的问题)。这些 lint 工具自带 fix 功能,能自动修复空格、换行、分号、逗号等一些小毛病;结合 vscode 插件,在编码阶段就可以显示 error 或是 warning,codeActionsOnSave设置为fixAll也能帮你修改或补全绝大多数 lint 问题。 Git Hooks Git Hooks 就是在提交代码前再做一次检查,一般包括上面提到的 lint 检查、commitlint(git message 格式检查)、单元测试、前端 build 错误检查等等吧。配得越多就越慢,小团队的话至少要包含 lint 和 commitlint。我自己用的是一个叫husky的工具,在 package.json 里简单加一个 hook 就能在git commit时做检查了。 // package.json "husky": { "hooks": { "pre-commit": "yarn lint", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }, CI 前两步校验发生在开发环境里,事实上可以手动跳过的;你经常能碰到这样的事,有人还没安装依赖(lint 和 husky)就直接提交了,还有人会强行注释掉 hooky。不要觉得奇怪,这就是现实。但是,CI 中的校验他们是绕不过的,因为是在服务端进行的。所以 CI 中要尽可能多的覆盖各种规则检测,包括上面提到的 lint、单元测试、build、e2e 测试、代码分析等等,一旦出错立即 revert 代码。 // package.json "scripts": { "lint": "eslint && stylelint ", "unit": "jest", "build": "nuxt build" }, CI 的选择可以是 Jenkins、gitlab 或是一些云服务商的 pipeline。小团队还是尽量购买云服务,价格也不贵;有些小厂成本核算能力较弱,以为自己搭建才划算。事实上 CI 最基本的投入就有服务器、机房空调、电费,还需要投入人力到容灾上,不划算的! CI 功用比较多,这一节我们还是把目光集中在 lint 上。上面提到 CI 校验不可绕行,但是也不要过分依赖 CI,频繁出错并不是一个健康项目的体现。项目管理上还是要以前两者为重。管理人员需要时常介入:及时升级 lint 工具覆盖更细节的校验;时常观察团队代码短板,强化或是修改某些特定的 style 配置;过于牵强的 lint 检查,也应该及时 ignore;一些 lint 规则在开发环境下会带来不便,可以将 develop 模式和 production 模式分开处理;还要和某些开发当面谈心,有些人喜欢利用注释,disable 掉 lint 检查。。。 编码 IDE 集成开发环境基本没啥好犹豫的,就是 vscode。我用过 webstorm,先不说收费问题,实在是太卡了;sublime 和 atom 也用过,都过气了,就没必要留恋了。开发阶段可以把.vscode 文件夹一并 push 到 git 上:launch.json 里的 debug 命令一开始就应该配好;settings.json 里存放常用的插件配置,新手可以开箱即用。 Webpack & nodemon Webpack 是生产环境下的最主流的打包工具;开发环境中也基本离不开它,热加载实在是太赞了。不过项目大了也有点卡。最近 vue 作者尤雨溪同志正在实现一款叫vite的工具,开发环境下能按需热部署,希望能早日完工。 Nodemon是后端 nodejs 的热加载工具,结合 vscode 它还能同时完成 debug 功能。尽早在团队内普及 chrome 和 vscode 的 debug 方法;真的,很多人一辈子都在console.log。 Babel & postCss 在老派开发的印象中更新语言就意味着伤筋动骨的;但是现代前端完全不是这么一回事。前端代码会有各式各样的 compiler 帮你把新语法转换成旧语法,不用太担心兼容问题。Babel 和 postCss 就是最有名的编译工具,分别帮你把 JS 和 CSS 为编译为低版本浏览器支持的语法。开发阶段,一般在 Chrome 或 Firefox 等现代浏览器下完成功能,然后再花少许时间确认 IE 功能即可。当然,低版本浏览器的支持要至始至终,中间一旦断档还是很难恢复的。 Babel: Use next generation JavaScript, today. PostCss: A tool for transforming CSS with JavaScript 刻意保持低版本语法是无知的,我听说某些厂为了支持 IE11 竟然还在强制要求 ES5 语法;枉顾时代变迁,从开发人员的角度,这就是灾难:无论是个人工作体验,还是技术成长都不会带来任何有益的助力。ES6 之后的 JS 语法,如 Promise、class、箭头函数、可选链等等是开发效率下线的保障。CSS 新 feature 中以网格布局最为耀眼,将 html 语义标签和布局功能分离,可以说是划时代的进步。 当然语法追新也是有成本的,首先要保证团队内写出“同一个时代的”的代码。讲真,不是所有人都愿意学习新语法的。我还是能看到自己参与的某个项目里,callback和async/await在同一个文件里共存——es3 和 es7 的代沟。相比 JS,CSS 开发的下限更低,很容易看到一个及其简单的布局会随着一大堆冗长的margin、padding、height、width……会写 flex 布局的人就不多,更无论 Grid 了。 所以基建很重要,学习更不能停止,要像学习 java、C++一样学习 JS 和 CSS。我曾尝试每天“早读”技术书籍,只需要两三个月,即便是我这样的后进生也可以实现较大的提升。 UI UI Library UI 库请优先选用知名的开源框架,这是大家用脚投票出来的结果;不要太自信,更不要搞些奇怪的风格。众口皆碑的组件库是不存在的,也只有极其有限的公司能提供可维护的基础控件,而且还是大家提了无数 issue 的结果。我所在母公司曾集全厂之力造就具有我厂特色的 Material Design 主义的“轮子”,花了无数工时,现在已经弃之不用了。但是很多人依旧雄心不死,总想着再来一回。 Storybook 除了基础 UI 控件,每个产品还需要进一步封装业务组件。如何管理这些组件会是一个难题:怎么说呢,这些 UI 组件至少能单独展示、单独调控吧?有个叫Storybook的开源库提供了一个很出彩的解决方案。它是一个沙箱工具,能隔离地构件 UI 组件。我开发的时候,大量的时间就是在写 storybook,一般步骤如下: 新建特定的业务组件(如 Button.vue),并在它旁边创建一个对应的 storybook——Button.stories.js 编写组件功能,在 storybook 里——支持热加载——调试样式、入参和事件响应 git commit & git push 所有业务组件完工后,再放到 page 里排版、集成 api 等等,最后收工 前三步都是作用于沙箱,所以不用担心到处污染,之后的 bugfix 也大多在沙箱完成,高效简洁。官方推荐的文件结构如下,组件和 storybook 一一对应。 Button |---Button.vue |---Button.stories.js 我使用 storybook 的初衷很简单:项目大了,webpack 热加载太慢了;在沙箱里调试组件比页面上调试高效很多。写多了发现好处更多:组件一目了然,减少了组织内部重复的轮子;一些依靠全局魔改生存的组件,因为很难放到 storybook 里,我又进行了重构,功能组件和布局组件划分更加清晰,项目更容易维护了。Storybook 支持几乎所有主流前端框架,建议一开始就安装。 Test 刚入职的时候,领导让我写单元测试,当时觉得很奇怪,为什么要判断一些理所当然的输入输出呢?时间久了才感受到测试的意义:防止别人改动你的代码;当代码被修改后,连那些理所当然的输入输出也不能保证时,就要告警了。 测试覆盖率低,我觉得几乎所有软件公司都是这个德性。早些年大家觉得前端很难写测试,但是 Jest、Cypress 这类框架出现后,前端测试已经不比后端难写了。但大家的印象依旧,这不是态度的问题,是认知和成本的问题。我看过一篇文章,讲外包公司是不写测试的。我所在部门的测试主要就靠印度的外包软件公司“点点点”。我不清楚领导层有没有比对过这样成本,是让我们外包写 Cypress 的 e2e 测试来得便宜,还是反反复复地“点点点”来得划算?我也曾听人说起过前端自动化测试,后来某领导发表了重要讲话,然后就没有然后了…… 虽然问题很多,但是做基建绝不可偏废测试。这里推荐Jest做单元测试,Cypress做 e2e 测试;文件结构就是在组件旁边再加一个.spec.js 文件。当然难点并不在框架,是在如何推动 TDD。 Button |---Button.vue |---Button.stories.js |---Button.spec.js API Graphql v.s. REST API 架构风格最主流的自然是 REST 风,翻译过来叫表现层状态转换。REST 具有划时代意义,要知道现在方兴未艾的前端框架(react、vue)都是得益于 Restful api 解耦了前后端。不过,REST 也有不如意之处。你打开一个页面常常会发现满屏的组件都在向后端发送 api;浏览器单次最大并发的请求数一般在 6 个以内,过多的 api 请求会导致卡顿。主要原因还是 REST 在设计上就太细碎了:比如一个叫 /user/{id} 的 api,望文生义自然是只能包含用户的信息;实现上你可以不按 REST 套路出牌,一并返回 Job、task 等其他不相关信息,只是这样 REST 语义就没有实际价值了,积累技术债呗。后来有人为了减少请求数,想到了所谓的 Flux 风——就是加个叫 store 的中间层,组件不再直接发送 api,由全局的 store 代为处理,这样可以提高 api 复用性;store 还可以在前端重组、裁剪不同来源的 api 数据,也一定程度上减少了过于细碎的功能性 api。 不过,api 数量还是在不可逆的上升中。有人就提出只请求一条 api 的设想,直接在后端聚合所有需要的数据,前端按需查找即可,这就是后来的 graphql。大多数新创公司没有历史包袱,前端团队也相对精干,一般就直接上手 graphql 了。就编写单一 api 来说,graphql 要比 rest 麻烦很多;当然麻烦的好处就是你不愿写太多的 api 方法,这倒也符合 graphql 设计初衷。我自己实现的时候就喜欢一个页面一个 graphql 请求,数据也不放在 store 里,仅仅父子组件传递;当然实现上需要 DOM 结构较为扁平,UI/UX 尽量走极简风吧。 API Docs Graphql API 一般就用 apollo 自带的文档系统——playground;它是强类型语言,下限较高,这里不多说了。Restful API 文档就多得多了,最经典是 Swagger,我还用过同类产品 OpenAPI,注释型文档 apidoc,国产的 YApi 也极力推荐。文档类产品功能倒是其次,维护才是难点。我个人认为 99%的 API 文档会烂掉。还是上面提到的话题,认知和成本。写文档不像 linter 工具,几乎是一劳永逸的,它需要跟随代码不断地迭代;只有那些执行力极强,文档文化根深蒂固的企业才能落实到位。我曾听说,某领导天天发表重要讲话要完善 Swagger;但直到他离职,API 信息还是靠口口相传。这里没有讽刺那位领导的意思,他既发表了重要的讲话,又没有增加底层人员的开发成本,无功无过呗。Anyway,文档和测试一样,工具不是最重要的,最重要的是执行力。 Mock 我一直有个梦想:即便后端宕机,打开前端也能完成所有操作。这需要 Mock 服务,但是现实中绝大多数 Mock 服务也很快会烂掉。Graphql 有强类型,auto-mock 数据兴许能维持久一点;REST 就不要妄想了,api 太多了,修修改改,很少人会一直跟进。所以个人不主张在 Mock 服务上浪费太多时间,开发阶段反向代理一下特定的 api 就行了;至于之后,烂了就烂了吧,别心疼。 Mock api 在 Test 环境里意义非凡,某些组件需要异步请求数据才能完全加载(但是这种组件越少越好),mock api 可以帮助在隔离的沙箱里进行单元测试。这里推荐一款神器——miragejs,极简的 mock 服务,可以在客户端和 test case 里拦截 api 并返回 mock 数据。 小结 这期名字叫得很大,但主要就是介绍了一些比较常用的前端工具。这些工具基本都是大众晚期产品,如果还没听说过可能真的有点“脱产”了。有兴趣的小伙伴最好尽快补一补。虽然大家天天说学不动了,但真到面试的时候,一个比一个会。

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):