lego系统一岁啦

logo

大概看了下去年的博客,我大概在五月初,对lego的第一次上线做了总结,那么现在大概就是lego的一周岁生日了。

lego 的定义

lego云图

支付lego平台是一个支持多维度线上配置的web组件化前后端同构渲染平台,覆盖从服务端到web前端再到数据监控的整体解决方案,目前服务于去哪儿网会员的【我的钱包】【我的银行卡】【绑卡服务】【实名认证】等服务。

lego 搭建背景

ykit

busiTypeId=WLHotelHD&
couponAmount=300& bannerLink=http%3A%2F%2Fwww.qunar.com%2F& HMAC=362b0da8eb2f95cb33608cf4584c7700&
agreement=&
did=865630020132708&
pid=10010&
extraJson=&
cardType=ALL& 
version=20140808& title=%E7%BB%91%E5%8D%A1%E9%A2%86%E7%BA%A2%E5%8C%85&
isObtainCoupon=1& 
couponSource=pay_test& 
userId=1444548113& 
successURL=http%3A%2F%2Ftcbeta2.qunar.com%2Factivity%2Fspringgift%3Ftpl%3Dredirect%26couponId%3Dundefined& 
gid=8438932D-5548-D769-1AF7-22274CDE88E4&
bindCardRule=%5B%22%E9%A6%96%E6%AC%A1%E7%BB%91%E5%8D%A1%E6%88%90%E5%8A%9F%EF%BC%8C%E4%B8%94%E8%AF%A5%E9%93%B6%E8%A1%8C%E5%8D%A1%E6%9C%AA%E5%9C%A8%E5%8E%BB%E5%93%AA%E5%84%BF%E7%BD%91%E7%BB%91%E5%AE%9A%E8%BF%87%E7%9A%84%E7%94%A8%E6%88%B7%EF%BC%8C%E5%8D%B3%E5%8F%AF%E8%8E%B7%E5%BE%97%E4%BC%9A%E5%91%98%E7%BA%A2%E5%8C%85%E3%80%82%22%2C%22%E6%AF%8F%E4%B8%AA%E7%94%A8%E6%88%B7%E5%8F%AA%E5%8F%AF%E7%BB%91%E5%8D%A1%E9%A2%86%E5%8F%96%E4%B8%80%E6%AC%A1%E4%BC%9A%E5%91%98%E7%BA%A2%E5%8C%85%E3%80%82%22%2C%22%E6%B4%BB%E5%8A%A8%E4%B8%AD%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%87%BA%E7%8E%B0%E4%BD%9C%E5%BC%8A%E8%A1%8C%E4%B8%BA%EF%BC%88%E5%A6%82%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C%E3%80%81%E6%81%B6%E6%84%8F%E8%B4%AD%E4%B9%B0%E3%80%81%E8%99%9A%E5%81%87%E4%BA%A4%E6%98%93%E7%AD%89%EF%BC%89%EF%BC%8C%E5%8E%BB%E5%93%AA%E5%84%BF%E7%BD%91%E5%B0%86%E8%87%AA%E5%8A%A8%E5%8F%96%E6%B6%88%E6%82%A8%E6%9C%AC%E6%AC%A1%E6%B4%BB%E5%8A%A8%E8%AE%A2%E5%8D%95%EF%BC%8C%E5%B9%B6%E6%9C%89%E6%9D%83%E5%86%BB%E7%BB%93%E8%B4%A6%E5%8F%B7%E5%B9%B6%E5%8F%96%E6%B6%88%E6%82%A8%E5%90%8E%E7%BB%AD%E5%8F%82%E4%B8%8E%E5%8E%BB%E5%93%AA%E5%84%BF%E7%BD%91%E4%BB%BB%E6%84%8F%E6%B4%BB%E5%8A%A8%E7%9A%84%E6%9D%83%E5%88%A9%EF%BC%8C%E5%BF%85%E8%A6%81%E6%97%B6%E8%BF%BD%E7%A9%B6%E6%B3%95%E5%BE%8B%E8%B4%A3%E4%BB%BB%E3%80%82%22%5D& 
vid=60001092&
merchantCode=WLHotelHDJK001&
returnURL=https%3A%2F%2Fmembermobilebetak.qunar.com%2Fm%2Fmember%2Fasset%2Fcoupon%2Fdetail.html& bindCardSource=coupon_bind& banner=https%3A%2F%2Fsource.qunarzz.com%2Fsite%2Fimages%2Fzhuanti%2Fhuodong%2Fflight_free_banner.jpg

使用的工具

编程语言的选择

Typescript

member-mobile 为了保证浏览器兼容性用的是 ES5,然而更多的代码库使用的是 ES6 编写,使用的时候再编译成 ES5。但是,无论 ES5 还是 ES6 都是动态类型 JS,无法对代码进行类型检查。

至于关于 typescript 的好处,我不在此多余阐述,可以参考我过去的记次分享

typescript干货

Typescript sucks but long live the types

TypeScript编译抽象语法树

架构设计

架构设计

lego 参考了公司内普遍使用的增加一层 node 层作为渲染层的方案,然而工程上利用 webpack 可以分别打包以及 js 可以在双端运行的特性,实现了前后端同构方案,这样再开放上无需在 node 层增加开发人员,具体的实现请参考【erʌpt】一个前后端同构的设计思想

Qxf 作为 node 服务框架

Qxf 是 Qunar 的 node 服务框架,基于 Express,Express 也是目前被最广泛使用的框架。

Qxf 包含的模块使得 lego 在搭建初期不需要重建轮子,节省了很多时间。同时因为其基于 Express, 更有利于搭建 restfull 接口。

Preact 作为同构渲染框架

Preact logo

lego 使用 preact 作为前后端的渲染框架,preact 的包大小是 react 的 1/20,同时 preact 对 typescript 的支持是目前除 angular 外最好的框架。

统一路由地址

lego 在 node 端使用 preact-router 渲染路由路径,而在客户端结合 HashHistory 使得客户端无需刷新页面更新路由。

# node

/bindCard/default/index

# client

/bindCard/defaut/index#/index/auth

HTTP 连接

起初 lego 使用的是 fetch 作为前后端接口交互框架,然而实际使用后我们全部改用了 Axios,主要原因有下。

QConfig 配置

在 QConfig 中,每一个项目都有自己的配置文件(JSON类型)

QConfig配置

每个 JSON 文件都有一个 solutions 字段,里面是按照来源存放的配置文件,每次使用的时候配置文件会和 default 混合一次确保配置的完整性。

JSON

Hybrid 桥

用于 Qunar 端的 HYSDK 并没有完全适配公司的客户端,我们开发了 PayDevice 来补足短板

class PayDevice {
    static readonly NAME_IOS_FIX: string;
    static readonly NAME_IPX_FIX: string;
    static readonly QUNAR_IPHONE: string;
    static readonly QUNAR_APHONE: string;
    static readonly GONGLUE: string;
    static readonly FIX_NAV_IOS_HEIGHT: number;
    static readonly FIX_NAV_IPX_HEIGHT: number;
    static readonly FIX_STATUS_IOS_HEIGHT: number;
    static readonly FIX_STATUS_IPX_HEIGHT: number;
    static readonly FIX_BOTTOM_IPX_PAD: number;
    private static readonly regularExp;
    private static getLowerUA;
    private static getMatchArray;
    static getAppProtocol: typeof getAppProtocol;
    static sniff: typeof sniff;
    static isIPad: typeof isIPad;
    static isIPod: typeof isIPod;
    static isIPhone: typeof isIPhone;
    static isCtripApp: typeof isCtripApp;
    static isApp: typeof isApp;
    static isAppIPhoneX: typeof isAppIPhoneX;
    static isCtripAppIPhoneX: typeof isCtripAppIPhoneX;
    static trim: typeof trim;
    static getCookie: typeof getCookie;
    static getQN270: typeof getQN270;
    static getBodyFixClass: typeof getBodyFixClass;
    static sniffmiddleware: typeof sniffmiddleware;
}

监控系统

我们修改了 Qxf 的 logger 和 monitor 以适配支付中心的鹰眼系统,更新 member-mobile 的 payGa 以接收前端埋点。

支付组件库

PayUI

我们经过和 UE 协调,利用 Yo 制作了一套 PayUI.css,可以直接作为支付中心样式使用。

PayUI

TS PAY COMS

利用 payUI 制作的组件库,使用 rollup commonJS 打包,提供工厂方法构建。

TS PAY COMS

export const FormID = Factory.input(
    Component, h, { CheckUtil, PayInput, PayList, MemICO },
);

export const FormIDTlist = Factory.list(
    Component, h, { FormID, CheckItem, PayPopup, PayList },
);

打包系统优化

打包系统

typescript编译优化

使用 HappyPack 分别使用3个线程处理前后端编译,利用 ForkTsCheckerWebpackPlugin 使用一个线程做类型检查,使用 cache-loder 缓存已编译的内容,减少重复编译时间。

经过优化,ts 的编译时间减少到原来的 1/2。

CSS的优化

使用 PostCSS 逐步代替 Yo

Yo 的缺点

/*** Yo 源代码 ***/
.foo {
    @include yoflex();
}

.bar {
    display: flex;
}
/*** 生成代码 ***/
.foo {
    display: -moz-flex;
    display: -webkit-flex;
    display: flex;
}

.bar {
    display: flex;
}

使用 CSS-modules 避免全局类名覆盖

CSS 一直存在很严重的类名覆盖问题,由于 CSS 的类名都存在于一个全局域中,当两个组件中存在重名类名,其中一个会被覆盖。

/**a-button.css**/
.button {
    background: red;
    background: blue;
}
/**b-button.css**/
.button {
    background: blue;
}

使用 CSS-modules 后,编译好的 CSS 文件会处理掉重名类名。

.button-a {
    background: red;
}
.button-b {
    background: blue;
}

发布使用 node_cache_share 缓存 node_modules

异步处理生成文件

使用了以上优化,我们最终将编译速度由初期的五分钟优化到现在的26秒。

过去一年遇到的问题

解决方案