导读:做者从 17 年双十一前开始接手天猫搜索前端,开发第一个需求—— H5 凑单页,到今天已经将近两年了。在这两年里,天猫搜索的前端体系发生了比较大的变化。今天分享一篇阶段性的总结文章,记录天猫搜索前端技术的过去、如今,以及本身做为业务目前的惟一前端对将来的思考。
大致划分css
首先基于前端技术的演进,大致上能够将天猫搜索前端的发展历程和将来趋势总结成几个时代:前端
之因此这么划分,主要是基于天猫搜索的前端技术方向以及天猫乃至淘系前端技术体系发生的较大变化。而在这其中能够再提炼时代的关键词:react
下面就来介绍各个时代天猫前端的技术状态和一些思考。webpack
PC 时代能够说是天猫搜索前端的上古时代,那仍是手机流量很是贵的 3g/2g 时代。所以大多仍是简单的 WAP 页面,大多数人都仍是习惯用 PC 进行购物。ios
▐ 技术方案web
模块化后端
PC 时代的前端技术方案采用的是 KISSY + MUI 3 ,MUI 3 就是那套 KISSY 的模块规范 KMD 。页面上还有一些很是老旧的 YUI 依赖。在那个 jQuery 王霸天下的时代,基本上天猫的 PC 页面都是采用集团内部根据 YUI 自研的大而全的 KISSY 框架。KISSY框架包含了前端所须要的几乎全部基础功能:模块加载器、 DOM 操做、事件处理、异步请求等等。浏览器
页面渲染缓存
PC 天猫搜索采用了同步渲染的方式,页面的主要内容经过 VM 模板渲染输出到前端,所以前端须要维护大量的 Velocity 模板代码以保证 HTML 中的内容和本身 JS 代码可以配合得当。需求修改一旦涉及到 HTML ,就须要改造 Velocity 模板从而陷入 aone 发布的同步模板和部署炼狱之中。性能优化
模块管理
而 PC 时代的天猫搜索前端页面的模块管理方式十分粗暴,基于业务逻辑划分的大量 KISSY 模块,他们共同操做一个统一的页面 DOM ,交叉修改时有发生。模块间的通讯也是直接调用模块实例方法来实现,模块耦合很是严重。
▐ 小结
由此能够看到那个时代最主要的问题有以下几个:
随着智能手机的普及,4g 技术的发展使得流量费用的大幅降低,无线端需求不断增多,流量不断增大,天猫前端也将方向定为 mobile first 。显然 PC 搜索这一套技术方案没法知足 H5 搜索需求,所以 H5 搜索采用了全新的技术方案。
▐ 技术方案
模块化
H5 搜索采用 Zepto + MUI 4 做为模块化方案,MUI 4 相对 MUI 3 主要变化是将 KMD 规范修改为了业内较为通用的 AMD 规范。同时引入了前端模板来实现 DOM 的更新,首先 Zepto 要比大而全的 KISSY 轻量许多,同时前端模板的引入使得模块自我管理了 DOM ,有效的下降了模块之间 DOM 操做交叉引起的混乱。
页面渲染
H5 搜索的页面渲染基于应用控制,但仅仅将框架、筛选等一些少许 DOM 同步渲染,大多数 DOM 如商品列表都是采用异步渲染前端模板的方式实现。所以同步模板中的内容量相对较小,维护成本大幅度下降。同时引入了先后端分离的 wormhole app ,前端再也不须要维护不熟悉的 VM 模板,而是维护和异步模板语法相同的 xtpl 模板,进一步下降了模板维护的成本。
模块管理
与 PC 连翻页都是页面跳转的方式不一样,如筛选、翻页等行为的渲染须要前端异步处理,模块通讯的需求也相对复杂。H5 搜索采用了 MDV 框架——经过将模块封装成一个个模型,再由 MDV 创建的模型之间的订阅机制进行模块的实例管理,以此来实现模块通讯。
▐ 小结
H5 搜索采用的技术解决了几个 PC 搜索时代的问题:
但随着业务的发展,依然发现有一些问题:
在 all in 无线的大环境下,因为搜索结构较为固定、无线端开发资源较为充裕等等各类缘由,天猫搜索业务在端内彻底被 Native 承接,而 H5 更加注重端外和站外。这也致使了 H5 搜索的业务能力和 Native 脱节,仅保留核心筛选功能以及唤端功能。所以 H5 搜索很长一段时间几乎没有前端资源投入,而在 2017 年 8 月左右因为组织架构调整,我手上的天猫商品业务交接后,我开始逐步接手天猫搜索前端业务。而我要作的第一个需求,就是一个包含 H5 搜索 80% 功能的 H5 搜索凑单页。
▐ 技术方案
模块化
我和团队同窗采用 Preact + MUI 5 方案来实现,MUI 5 其实就是 MUI 4 的升级,采用 CommonJS 的写法来编写模块,再通过构建工具编译封装生成 AMD 模块。其实当时会场已经大规模采用 Vue Weex 了,那咱们为何要采用 Preact 呢,主要是基于以下几点考量:
所以在这个阶段,咱们使用 Preact 作了不少的搜索周边的功能页面,如上面提到的 H5 凑单、还有猫搜的领券弹层、凑单领券页面、搜索分类页面等等。
页面渲染
因为 Preact 的异步渲染特性,页面渲染咱们直接抛弃了应用,而是采用斑马源码页面的方式。这样的好处是,前端再也不须要和 aone 频繁的打交道,服务端只须要封装一个 mtop 接口给前端,前端在斑立刻建立基础 HTML 引入资源并调用接口获取数据渲染便可,前端本身彻底掌控了调试、开发节奏。因为对于应用的依赖仅限于一个 mtop 接口,所以前端能够提早定好数据规范,在服务端开发接口的同时基于本地调试工具进行 mock ,大大下降了联调成本。
模块管理
React 生态有很是多的模块管理方案,咱们调研过的 Flux、Redux、Reflux 等等均可以知足咱们的需求。但通过仔细的思考咱们选择直接撸,不使用任何框架来管理模块通讯。如此考量的缘由主要遵循以下理念:
▐ 小结
引入 MV* 框架后,咱们的技术方案又获得了一些提高:
这里仍是有一些问题:
借鉴天猫超市极致 H5 经验,搜索在分类页作了很是多性能优化尝试,好比:
一、代码优化
二、DNS优化
三、接口优化
四、埋点优化
五、加载优化
六、体感优化
17 年双十一以后,搜索一成不变的模式也受到挑战,在这个拥有大量流量和强用户心智的场景下,搜索可以玩出更多场景化、行业化、品牌化的玩法。所以产品上须要更多快速试错的机会,也致使对于动态化的诉求则日益增长。而因为一些组织架构调整,天猫搜索的客户端缩减到 2 人—— 1 个 ios 和 1 个安卓。客户端需求开发由于须要发版而迭代缓慢。所以催生了 Native 内嵌 Weex 坑位的技术方案和 Weex 模板下发的 Oreo 平台。
▐ 技术方案
模块化
其实在我进入到搜索以前,Weex 坑位方案和 Oreo 就已经在小范围使用了,有一部分客户端同窗写的 Weex 1.0 的 Vue 模块,另外还有一些 Weapp 模块。这些模块因为人员调整和离职已经很难找到仓库源码了。另外这些模块也是仅面向 Weex 的,对于 H5 来讲是彻底没法使用的。所以在我进入搜索以后,提出了Prax的解决方案,本质上就是使用 Rax 0.x(当时仍是0.4) + Preact 经过编译转换供Weex和 Web 同时使用。之因此要用Preact,主要是考虑到咱们有端外 H5 场景,可是 Rax 当时 H5 性能是真的堪忧,并且当时的Weex团队方向对H5性能优化投入并很少。另外从上面 MV* 时代能够看出咱们在 Preact + MUI5 的技术方案上也有较多的沉淀。最终咱们肯定了采用编写 Preact 代码,经过自动化工具转换成 Rax 代码的方式来实现一份源码同时复用在 Weex 和 Web 的技术方案。前端的开发流程就变成了以下:
页面渲染
Prax 页面采用斑马来处理页面渲染。因为源码页面都是采用打包的方式,所以脚手架中分别有 Web 和 Rax 两个打包 webpack 配置,构建时候分别运行生成 Weex Bundle 和 Web Bundle 。因为 Web 端本质上就是以前 Preact 的方式,所以渲染沿用了过去 Preact 的页面框架。而Rax则是开发了一个全新的页面框架。斑马渲染 Weex 页面本质上是经过xtpl控制 Weex Bundle 代码生成,因此源码页面编译出来的 Weex bundle 只须要在外经过 xtpl 增长一层 Weex 的头尾就能够了。
对于 Native 内嵌坑位,则是采用模板下发的方式。前端会编译生成一个自身可运行的 Weex Bundle ,包含头尾等完整信息,而后经过发布推送到搜索应用的机器上。当客户端的搜索请求到达服务端,服务端基于业务逻辑肯定须要使用哪些模块,将模块相关的信息告诉客户端,这些信息包括模块名称、模块位置、模块数据。客户端渲染 Native 页面时根据模块位置建立对应容器,并根据模板名称请求 Weex 代码,最后将代码渲染到 Weex 容器中,并传入模块数据,实现模块最终渲染。而在 Rax 代码中,咱们能够经过 window.__weex_data__ 拿到客户端塞给容器的数据。固然这些适配均可以在构建层面处理,通常状况下开发者只须要关注纯粹的 UI 模块编写便可。
模块管理
Prax 页面的模块管理和 Preact 开发时期基本同样。可是对于 Native 内嵌 Weex 坑位,模块管理方案就彻底不一样了。看起来 Native 内嵌 Weex 坑位只展现一个Weex模块,但其实是一个只有单一模块渲染的完整 Weex 页面。所以 Weex 模块之间是没法通讯的,它们甚至都不在一个 Weex 容器内。正由于如此 Native 内嵌 Weex 大多作一些纯展现的需求,对于复杂联动需求依然是交给客户端完成。另外客户端提供了一些通用能力,封装在 Weex 模块中,如:
▐ 小结
通过了 Weex 时代,咱们的技术又获得了提高:
但这里仍是有几个问题没有解决:
至此咱们能够发现,如今搜索前端核心解决的问题逐渐变成了共建和规模化了,再也不是以前单纯前端技术问题了。既然要解决共建和规模化,咱们能够看看规模化成功的一个典型例子:会场。过去会场也是一个个页面前端人肉开发,到后来有了斑马就能够由运营模块化搭建了,前端只须要开发一些基础模块就能够知足全部行业的诉求,多么的美好!那么搜索是否是也能搭建呢?
答案是:“是的”,但毕竟场景不一样,咱们不能和会场同样楼层 duangduang 地堆砌,为何呢?
首先在场景的层面有比较大的不一样。在用户进入这个会场时,已经决定了当前的场景了,一个会场页面就是一个场景,所以在这个会场页面下,只须要圈出这个场景的模块就能够了。而对于搜索,全部的场景都须要在搜索这一个页面展现,而在搜索如何定义一个场景呢?
这么多维度,一个或多个交织在一块儿才定义了一个场景,而在这个场景下会展现一个或多个模块。
以 Query 举例:
固然,会场模块里面的货品彻底能够多样化,另外如今会场基于袋鼠也有千人千面模块的能力了,这里是拿以前的会场作例子
基于这样的思考,搜索启动了一个长颈鹿项目,以以前搜索域就有的一个产品——品牌 Minisite 做为切入点,为品牌商提供了一个全新的品牌运营阵地
如上图,从左往右分别是三个版本的 minisite 。这里能够看到, Minisite 做为品牌在搜索的一个搭建阵地,一直采用的是提供模块让品牌商填入数据的玩法。品牌商自定义程度很低、维护欲望很低,所以导购效率一直不高。而在长颈鹿项目中,搜索在商品列表层之下又新开了一个层,在这个层里展现一个品牌商家搭建的页面,在这个页面中品牌商家能够充分的自定义。而对于一个跨品类经营的大品牌,咱们也开放了品牌词+主营类目词的组合,方便其对每一个主营类目去搭建本身的页面。
而在品牌词下取得成功后,咱们将能力扩展到了行业侧,在搜索中台——美高上建设了心智造产品。让行业也能够基于一样的方式去经营品类词,搭建行业本身的页面。
心智造和 Minisite 分别是针对品类词和品牌词,相互不会交叉。而对于一些横跨多品类的平台级需求,好比一些频道相关的需求和拉新相关的需求,是很是容易与其余场景交叉的。为了解决这个问题,咱们在美高上沉淀了一套模块定投方案——无界,经过模块级别的投放,让场景之间的交叉变成可能,只须要简单定义模块展现的规则,就能让不一样场景的模块展现在同一个页面上。
▐ 技术方案
模块化
首先是心智造和 Minisite ,它们的核心技术方案是类似的——都是采用千叶(一个给商家用的页面搭建平台)做为模块搭建平台,并在千叶的搭建能力之上,包装了一层页面投放策略的管理。其实到这里,模块化方案和会场并没有二致,只是模块的实现采用了 Prax 来兼容 Weex 和 H5 :
一、编码阶段
二、渲染阶段
而到了无界,这些就彻底不 work 了。毕竟无界是走的模块级定投,容器只有一个,所以投放场景极可能和心智造、 Minisite 场景交叉:
而咱们采用了以下技术方案将无界的定投模块插入到页面中:
经过这样的方式,最终渲染出当前场景下全部的模块内容。另外在无界后台咱们有一套场景干预规则,解决场景交叉时进行一些手动干预。与此同时咱们还提供了一套动态数据源机制,方便三方 HSF、TPP 数据能直接绑定到模块上,实现模块和数据解耦。
页面渲染
页面渲染如上述所示,依旧是经过斑马。但与以前不一样的是:
因为是模块化搭建,页面经过 PI 统一管控,页面渲染依赖 PI 行为控制
对于长颈鹿容器,一样是 Native 建立 Weex 容器渲染,但与以前渲染一个仅包含一个模块的 Weex 页面显然是不一样的,长颈鹿容器内渲染的也是一个真正的模块化搭建的页面
对于无界定投的模块,提供了插入机制,解决了场景交叉时的展现问题
模块管理
对于页面内的通讯,因为页面经过 PI 统一管理,也就意味着模块的各类能力都须要依赖 PI 来进行实现。因为这样的楼层搭建通常通讯结构都是扁平的,因此基本上经过模块冒泡给 PI , PI 下发给对应模块便可。不过通常不建议模块之间进行通讯。
对于页面和容器通讯,咱们是在 PI 中提供了一些封装的能力,另外也能够本身调用容器提供的方法,与 Native 内嵌坑位的 weex-module 方案别无二致。
▐ 小结
因为长颈鹿内的技术方案已经脱离传统意义上的前端,更多设计客户端和服务端,是整个产品架构的设计,这里很难讲清楚,放一张图可能清晰一点:
这里前端技术又有了提高:
但这里咱们仍是有几个问题还没有解决:
搜索最擅长的显然就是搜索结果页那种商品瀑布流,将用户最想要、最有可能购买的商品推荐给他们。而这个能力也能够复用在诸如首页、频道、店铺、专辑等等地方。而当咱们要在不少不一样的地方去搭建这样一个列表页时,在上面所说的楼层搭建中,咱们通常会怎么作呢?
若是这么处理,若行业大面积规模化,会出现以下几个问题:
这些显然都是咱们不肯意看到的,咱们将组件的不一样场景彻底剥离,能够发现一些规律:
进一步提炼:
因此咱们有没有可能在这个理念上更深一步进行搭建呢?
模块化
答案显然是有的,深度搭建的概念其实就是用来解决这种问题。将页面上的模块基于功能进行了从新定义:
经过这样子的划分,容器模块控制了交互、展现模块控制了 UI 、数据模块控制了业务逻辑,好比一个包含筛选、商品流的列表更具体用 React hooks 来讲就是:
合理的场景划分相当重要,不一样业务场景应该是数据模块+容器模块+展现模块的组合,大多数状况下容器模块和展现模块能够复用,但数据模块都是须要从新开发的。尽量让数据模块来适配容器模块和展现模块,不改变交互就不改变容器模块,不改变UI就不改变展现模块。
在这里模块的编写切换到了 Rax 1.0,与会场的开发方式一致以实现复用。Rax 1.0 针对 Web 作了不少优化,打出来的 bundle 也更加轻量,性能也好了不少,已成为天猫前端业务开发主要方式,所以再也不须要使用 Prax 了。
页面渲染
这里和传统搭建有个很重要的不一样,模块之间出现了关联关系。好比以下关联:
那么咱们就须要一个全局方式来处理这些关联。首先须要在搭建模块的时候去指明模块之间的关联关系,好比我本身是定义了三个字端:
data 和 container 都是二段结构的,好比 data 的 a:b 表明使用 key 为 a 的数据模块的 b 字端内的数据,而 container 的 a:b 则表明使用key为a的容器模块,并将本身做为其 b 区域的展现模块使用。
这几个字端都会在脚手架里,初始化时生成到 schema.$attr 中。而真正负责识别这些字端并将模块串起来的天然是页面初始化脚本—— PI ,PI 干了以下事情:
模块管理
这里模块的通讯有两种,一种是基于公用数据模块的通讯,一种是基于 PI 的通讯。
一个页面上能够有多个数据模块,而每一个数据模块均可以对接到多个容器/展现模块(这也是为何 data 是二段结构的缘由)。所以当多个模块须要通讯的时候,能够经过dispatch触发数据模块行为,数据模块刷新数据影响另一个模块。
基于PI的通讯通常都是针对一些特殊场景,好比一个很经典的例子——筛选列表筛选栏变形吸顶:当页面有不少模块,筛选列表并非全屏大小而是跟着整个页面一块儿滚动,当筛选栏滚出视野外,它须要变成一个相对简单的结构吸顶。在这种场景下,因为吸顶层自己是一个绝对定位的层,而页面文档流也是一个层,两个层之间不基于 DOM 操做的话,最合理的方式就是基于一个数据模块进行状态共享。如吸顶组件定义了吸顶时的样式和正常的样式,而且暴露一个建立数据模块的方法, PI 在渲染吸顶组件时会单独为其建立一个数据模块来共享筛选栏状态。
▐ 小结
为何要搞的这么复杂?其实就是但愿能将 UI 和交互作的更加纯粹,当 UI 和交互都是针对单一场景、足够简单的时候,咱们就能引入一些产品来进行提效,好比:
经过这这样的方式,最终页面上大多数内容都变得能够复用,规模化的成本也就大大下降了。
因为搜索还在深度搭建时代探索,如下是我基于团队方向 YY 的,但我相信这个时代很快就会到来
但上述的各类方式终究仍是人肉的,须要人力投入的。既然工具能让咱们以配置的方式解决交互和 UI ,那么有没有可能连配置都不须要,机器自动帮咱们生成一个数据模块或者交互呢?
这就是咱们团队正在作的,目前团队的同窗正在尝试基于机器学习训练模型实现智能化UI。只须要给出一些关键信息(好比要展现商品的哪些字端),就会自动化的生成对应的展现模块或交互模块。这些模块使用到深度搭建之中,前端就只须要经过数据模块定义展现的内容来源就能完成整个页面的搭建。实现UI零成本。
而咱们进一步扩展去思考,把大象装冰箱分为三步,那么把搜索智能化应该也只须要三步:
具体一点多是:
所以,咱们可能须要一个三层的模型:
一、第一层基于不一样的内容,找出最合理的UI界面来进行展现,也就是智能UI模型。
二、第二层则是须要产出这些内容,这里分了三个维度:行业&平台+品牌&店铺+货品。
三、第三层则更为复杂
货品模型:从货品中提炼出货品中的最吸引人的一些特质,好比卖点、好评、销量,以及将货品结构化,方便货品在不一样的地方展现;
场景模型:基于用户的实时行为来定义当前用户的购买场景,他可能想买一台电视因此浏览了不少电视,抑或是在一家卖电视的专卖店里面找同型号线上价格,抑或是在过年准备给父母购置一台电视做为年货等等;
用户模型:基于用户的历史行为,将用户划归某个类型的人群,进行人群精细化运营。好比一个用户常常购买年轻人的潮流酷玩,但每到父亲母亲节或者特定时间就会购买一些长辈礼物的品类,说明是个有孝心的boy/girl,那么针对这类孝顺宝宝就能够在不一样的节日或其余重要日子推荐一些给长辈送礼的内容
那么咱们都有哪些数据呢?
One More Thing
因为咱们不是活在将来,所以没法判定前端的将来究竟是怎样的,但前端不会中止对于将来的探索。而这个将来不仅是技术的将来,也是业务的将来。技术和业务是咱们前进的两条腿,业务的诉求推进技术迈向新的高度,而更先进的技术也为业务带来更多的想象空间。
若是你不想再沉溺于过去,不想再埋头作为业务切页面的工具人,那就加入频道与 D2C 智能团队吧。有意向者请发送简历到 :tianxiang.wly@alibaba-inc.com
本文为云栖社区原创内容,未经容许不得转载。