Nerv实战 - 京东首页改版小结

DillonEd 发布于1年前
0 条问题

回想17年的京东首页改版,从上线到现在竟然已经过去了四个多月。这四个多月,除了不曾中断的日常维护需求,对首页孜孜不倦的优化工作,更多的是那些与拖延症抗争的日夜:是今天写,还是等好好休憩回味后再动手?很明显,在这几十上百个日夜里,我基本都选择了第三个选项: 不折腾了,先休息吧 。现在想起来,关于那一个月白加黑五加二加班生活的印象已经渐渐模糊。到现在依然能清晰记着的,大概是最为深刻的记忆了。

16版的京东首页,在性能、体验、灾备策略等各方面都做到了极致。站在如此高大的巨人肩上,除了满满的自信,我们心里更怕扑街。毫无疑问,我们在接到改版需求的那一刻,立马就敲定了新首页的技术选型:妥妥的 jQuery + SeaJS !

但很快,我们就发现这样一点都不酷。 jQuery 是2006年的框架了, SeaJS 停止维护也已经四年。这些项目的诞生都是为了解决当时业界的一些痛点:比如 jQuery 最开始是为了方便程序员在页面中操作DOM,绑定事件等; SeaJS 则是为了在浏览器中实现CMD规范的模块开发和加载。但在各种VirtualDOM框架横飞的现在,程序员已经很少会直接操作DOM元素,而模块的开发和加载也有早已有了别的方案。

就在这时, Nerv 项目的作者提出了建议:“ 不然用Nerv来一发? ”我记得,当时他脸上洋溢着淳朴的笑,Nerv也仅仅是部门内部的一个小项目。我们回想了首页这个业务,技术栈已经好几年未曾更新过,开发流程也不够理想。如果再不做出改变,明年的这个时候我们依然会面对一堆陈年老代码头疼不已。抱着试一试的心态,我们接受了他的提议。没想到,这个决定让首页从此摆脱了落后的技术架构,而Nerv现在也已经成长为GitHub上3k+ Star的热门项目。

Q: 为什么不使用 React / Preact / Vue ?

A: 这三者都是前端圈子中相当流行的项目。 React 有完善的体系和浓厚的社区氛围, Preact 有着羞涩的体积, Vue 则使用了先进的html模板和数据绑定机制。但是,上边这三者都 无法兼容IE8 。我们在经过相关数据的论证后,发现IE8的用户还是有一定的价值,这才最终激发了我们团队内部自己造轮子的想法。当然,在造轮子的过程中,我们也不忘向上面这些优秀框架的看齐。最终, Nerv 在完美兼容React语法的同时,具有着出众的性能表现,在Gzip后也只占用9Kb的体积。

整体架构

在这次的项目中,我们基于上一年久经考验的前端体系(详细介绍),进行了升级:

Nerv实战 - 京东首页改版小结

  • Athena前端工程化工具:团队自研的前端工程化工具。除了自动化编译、代码处理、依赖分析、文件压缩等常规需求,2.0版本还支持 基于npm的依赖管理更加先进的引入、导出机制 ,还有 最新的es语言特性
  • Athena管理平台:新增了 针对Nerv的项目模板 ,另外还有针对H5项目的特色模板可选。
  • Athena基础库与组件库:新增了基于 jQuery + SeaJS 的组件重构, 全新升级的Nerv组件
  • Athena模拟接口:除了已有的mock接口数据的能力,还支持 接口文档生成 ,便于沉淀项目接口信息。
  • Athena兜底接口:可以定时抓取线上接口的数据 生成兜底数据 ,还支持 接口数据校验 ,评估接口健康度。
  • Athena前端监控:我们部署了一系列的监控服务,对页面上的素材以及页面的完整功能进行监控。一旦图片尺寸/体积超限,某些特定的操作出现异常,或者接口成功率降低等异常情况,就会触发告警推送,开发者可以 实时收到告警信息
  • Athena可视化报表:Athena可视化报表平台上对上报的数据都有 直观的展示

开发模式

Athena2.0

1.0版本的 Athena ,基于 vinyl-fs 的流操作,或者说是类似于gulp的压缩、编译等等操作的任务流。而到了2017年, webpack 早已在前端圈中流行。同行们也早已经习惯在项目中直接基于最新的语言特性去开发,在 webpack.config.js 加上一个 babel-loader 就可以完美支持新语法并完成打包。Athena 1.0背着太沉重的历史包袱,已经很难快速实现对babel转译的支持。所以在首页的开发前,我们将Athena升级到了全新的2.0版本。

一如既往,Athena会为项目提供 init (初始化), serve (实时预览), build (编译), publish (发布)等功能。除此之外,由于2.0版本的Athena是基于 webpack 的,所以项目中可以 统一用npm来管理依赖 ,也可以直接 使用最新的ES语言特性 来进行开发。

使用Athena2.0开发时,建议的文件架构如下:

Nerv实战 - 京东首页改版小结

前后端协作

我们依然是采用了 前后端分离 的协作模式,由后端给出json格式的数据,前端拉取json数据进行渲染。对于大部分的组件来说,都会在 constructor 中做好组件的初始化工作,在 componentDidMount 的生命周期中拉取数据写入组件的 state ,再通过 render 函数进行渲染。

/* myComponent.js */
 
import Nerv from 'nervjs'
 
class MyComponentextends Nerv.Component{
  constructor() {
    super(...arguments)
    this.state = {
      xxx: 'xxx'
    }
  }
  async requestData() {
    // return await fetch('xxx').then(res => res.json())
  }
  componentDidMount() {
    this.requestData()
      .then(data=> {
        this.setState({
          xxx: 'yyy'
        })
      }).catch(()=> {
        this.setState({
          xxx: 'zzz'
        })
      })
  }
  render() {
    return (
      <div>{this.state.xxx}</div>
    )
  }
}
 
export default MyComponent

代码规范约束

有一千个读者,就会有一千个哈姆雷特。

上面这句名言,深刻地体现在了16版首页的代码仓库中。同一个组件,如果是基于 jQuery + SeaJS 的模式,一千个程序猿就会有一千种写法。结果在同一个项目中,代码风格不尽相同,代码质量良莠不齐,多人协作也会无从下手。

何以解忧?唯有统一代码风格了。通过 ESLint + Husky ,我们对每次代码提交都做了代码风格检查,对是否使用prefer const的变量声明、代码缩进该使用Tab还是空格等等的规则都做了约束。一开始定下规范的时候,团队成员或多或少都会有些不习惯。但通过偷偷在

代码里下毒

Athena的生成的项目模板中添加对应的规则,潜移默化地,团队成员们也都开始接受、习惯这些约束。

Nerv实战 - 京东首页改版小结

禁用变量重声明等规则,在