【第1797期】京喜首頁(yè)跨端開(kāi)發(fā)與優(yōu)化實(shí)踐
優(yōu)采云 發(fā)布時(shí)間: 2022-06-21 01:46【第1797期】京喜首頁(yè)跨端開(kāi)發(fā)與優(yōu)化實(shí)踐
前言
在業(yè)務(wù)的實(shí)踐分享。今日早讀文章由京東@凹凸實(shí)驗室授權分享。
在微信后臺 回復關(guān)鍵詞 京東前端 查看專(zhuān)欄
正文從這開(kāi)始~~
背景介紹
隨著(zhù)今年的雙十一落下帷幕,京喜(原京東拼購)也迎來(lái)了首捷。雙十一前夕微信購物一級入口切換為京喜小程序,項目順利通過(guò)近億級的流量考驗,在此與大家分享一點(diǎn)自己參與的工作。
在接手項目前,京喜業(yè)務(wù)已在線(xiàn)上穩定運行較長(cháng)時(shí)間。但經(jīng)過(guò)一段時(shí)間迭代維護后,發(fā)現首頁(yè)存在以下問(wèn)題:
綜上所述,京喜迎來(lái)一次改版契機。
改版目標
從前端角度來(lái)看,本次改版要實(shí)現以下目標:
技術(shù)選型
京喜業(yè)務(wù)擁有非常豐富的產(chǎn)品形態(tài),涵蓋了 H5、微信小程序以及獨立 APP 三種不同的端,對支持多端的開(kāi)發(fā)框架有著(zhù)天然的需求。
京喜豐富的產(chǎn)品形態(tài)
在技術(shù)選型上,我們選擇團隊自研的 [1] 多端統一開(kāi)發(fā)解決方案。
Taro 是一套遵循 React 語(yǔ)法規范的多端開(kāi)發(fā)解決方案。
現如今市面上端的形態(tài)多種多樣,Web、React-Native、微信小程序等各種端大行其道,當業(yè)務(wù)要求同時(shí)在不同的端都有所實(shí)現的時(shí)候,針對不同的端去編寫(xiě)多套代碼的成本顯然非常高,這時(shí)候只編寫(xiě)一套代碼就能夠適配到多端的能力就顯得極為需要。
使用 Taro,我們可以只書(shū)寫(xiě)一套代碼,再通過(guò) Taro 的編譯工具,將源代碼分別編譯出可以在不同端(微信/百度/支付寶/字節跳動(dòng)/小程序、快應用、H5、React-Native 等)運行的代碼。
選它有兩個(gè)原因,一來(lái)是 Taro 已經(jīng)成熟,內部和外部都有大量實(shí)踐,內部有京東 7FRESH、京東到家等,外部有淘票票、粵省事等多個(gè)案例,可以放心投入到業(yè)務(wù)開(kāi)發(fā);二來(lái)團隊成員都擁有使用 Taro 來(lái)開(kāi)發(fā)內部組件庫的經(jīng)驗,對業(yè)務(wù)快速完成有保障。
組件庫開(kāi)發(fā)實(shí)錄
由于首頁(yè)改版的開(kāi)發(fā)排期并不充裕,因此充分地復用已有基礎能力(比如像請求、上報、跳轉等必不可少的公共類(lèi)庫),能大量減少我們重復的工作量。話(huà)雖如此,但在三端統一開(kāi)發(fā)過(guò)程中,我們仍遇到不少問(wèn)題,同時(shí)也帶來(lái)解決方案,以下我們一一闡述。
H5 篇
我們所有的頁(yè)面都依賴(lài)現有業(yè)務(wù)的全局公共頭尾及搜索欄等組件,這就不可避免的需要將 Taro 開(kāi)發(fā)流程融入到現有開(kāi)發(fā)和發(fā)布流程中去。同時(shí)公共組件都是通過(guò) SSI[2] 的方式引入和維護的,為了能在運行 npm run dev:h5 時(shí)預覽到完整的頁(yè)面效果,需要對 index.html 模版中的 SSI 語(yǔ)法進(jìn)行解析,index.html 模版文件代碼結構大致如下:
<p>京喜</p>
可以看到模版中存在很多類(lèi)似 格式的代碼,這些就是通過(guò) SSI 方式引入的 H5 公共組件,它的 virtual 屬性指向的文件不存在于本地而是存在于服務(wù)器上的,所以我們遇到的第一個(gè)問(wèn)題就是在本地解析這些文件,確保能預覽到完整的頁(yè)面效果,不然開(kāi)發(fā)調試起來(lái)就非常的低效。好在 Taro 有暴露出 webpack 的配置,我們可以通過(guò)引入自定義加載器(這里就叫 ssi-loader)來(lái)解析這些代碼的路徑,然后請求服務(wù)器上的文件內容并進(jìn)行替換即可,要實(shí)現這個(gè)功能只需在項目的 config/dev.js 中加入如下代碼即可:
<p>module.exports = {
h5: {
webpackChain(chain, webpack) {
chain.merge({
module: {
rule: {
ssiLoader: {
test: /\.html/,
use: [
{
loader: 'html-loader'
},
{
loader: 'ssi-loader',
options: {
locations: {
include: 'https://wqs.jd.com'
}
}
}
]
}
}
}
})
}
}
}
<br /></p>
這樣就解決了本地開(kāi)發(fā)調試難點(diǎn),然后開(kāi)開(kāi)心心的進(jìn)行頁(yè)面開(kāi)發(fā)。
當頁(yè)面開(kāi)發(fā)完成之后,接下來(lái)遇到的問(wèn)題就是如何將前端資源部署到測試和生產(chǎn)環(huán)境。由于現有開(kāi)發(fā)和發(fā)布流程都是基于內部已有的平臺,我們臨時(shí)定制一套也不太現實(shí),所以需要將它融入到 Taro 的流程中去,這里我們引入了 gulp 來(lái)整合各種構建和發(fā)布等操作,只要構建出符合發(fā)布平臺規范的目錄即可利用它的靜態(tài)資源構建、版本控制及服務(wù)器發(fā)布等能力,這樣我們就打通了整個(gè)開(kāi)發(fā)和發(fā)布流程。
這套拼湊起來(lái)的流程還存在不少的問(wèn)題,對于新接手的同學(xué)有一點(diǎn)小繁瑣,有著(zhù)不少改善的空間,這也是接下來(lái)的重點(diǎn)工作方向。另外 Taro 的 H5 端之前是基于 SPA 模式,對于有著(zhù)多頁(yè)開(kāi)發(fā)需求的項目來(lái)說(shuō)不太友好,當時(shí)反饋給 Taro 團隊負責 H5 的同學(xué),很快得到了響應,目前 Taro 已支持 H5 多頁(yè)開(kāi)發(fā)模式,支持非常迅速。
小程序篇
由于開(kāi)發(fā)完 H5 版之后,對應的業(yè)務(wù)邏輯就已經(jīng)處理完了,接下來(lái)只需要處理小程序下的一些特殊邏輯(比如分享、前端測速上報等)即可,差異比較大的就是開(kāi)發(fā)和發(fā)布流程。
這里講一下如何在一個(gè)原生小程序項目中使用 Taro 進(jìn)行開(kāi)發(fā),因為我們的 Taro 項目跟已有的原生小程序項目是獨立的兩個(gè)項目,所以需要將 Taro 項目的小程序代碼編譯到已有的原生小程序項目目錄下,第一步要做的就是調整 Taro 配置 config/index.js,指定編譯輸出目錄以及禁用 app 文件輸出防止覆蓋已有文件。
<p>const config = {
// 自定義輸出根目錄
outputRoot: process.argv[3] === 'weapp'? '../.temp': 'dist',
// 不輸出 app.js 和 app.json 文件
weapp: {
appOutput: false
}
}</p>
由于京喜以前是主購小程序的一個(gè)欄目,后面獨立成了獨立的小程序,但是核心購物流程還是復用的主購小程序,所以這讓情況變得更加復雜。這里還是通過(guò) gulp 來(lái)進(jìn)行繁瑣的目錄文件處理,比如我們的小程序頁(yè)面和組件都需要繼承主購小程序的 JDPage 和 JDComponent 基類(lèi),所以在進(jìn)行文件復制之前需要進(jìn)行代碼替換,代碼如下:
<p>// WEAPP
const basePath = `../.temp`
const destPaths = [`${basePath}/pages/index/`, `${basePath}/pages/components/`]
const destFiles = destPaths.map(item => `${item}**/*.js`)
<br />
/*
* 基類(lèi)替換
*/
function replaceBaseComponent (files) {
return (
gulp
.src(files || destFiles, { base: basePath })
.pipe(
replace(
/\b(Page|Component)(\(require\(['"](.*? "'"")\/npm\/)(.*)(createComponent.*)/,
function(match, p1, p2, p3, p4, p5) {
const type =
(p5 || '').indexOf('true') != -1 ||
(p5 || '').indexOf('!0') != -1
? 'Page'
: 'Component'
if (type == 'Page') p5 = p5.replace('))', '), true)') // 新:page.js基類(lèi)要多傳一個(gè)參數
const reservedParts = p2 + p4 + p5
// const type = p1
// const reservedParts = p2
const rootPath = p3
<br />
const clsName = type == 'Page' ? 'JDPage' : 'JDComponent'
const baseFile = type == 'Page' ? 'page.taro.js' : 'component.js'
<br />
console.log(
` Replace with \`${clsName}\` successfully: ${this.file.path.replace(
/.*?wxapp\//,
'wxapp/'
)}`
)
return `new (require("${rootPath}/bases/${baseFile}").${clsName})${reservedParts}`
}
)
)
.pipe(gulp.dest(basePath))
)
}
<br />
// 基類(lèi)替換
gulp.task('replace-base-component', () => replaceBaseComponent())</p>
還有很多類(lèi)似這樣的騷操作,雖然比較麻煩,但是只需要處理一次,后續也很少改動(dòng)。
RN 篇
對于 開(kāi)發(fā),也是第一次將它落地到實(shí)際的業(yè)務(wù)項目中,所以大部分時(shí)候都是伴隨著(zhù)各種未知的坑不斷前行,所以這里也友情提示一下,對于從未使用過(guò)的技術(shù),還是需要一些耐心的,遇到問(wèn)題勤查勤問(wèn)。
由于京喜 APP 是復用京東技術(shù)中臺的基礎框架和 JDReact 引擎,所以整個(gè)的開(kāi)發(fā)和部署都是遵循 JDReact 已有的流程,畫(huà)了一張大致的流程圖如下:
京喜開(kāi)發(fā)發(fā)布流程
JDReact 平臺是在 Facebook ReactNative 開(kāi)源框架基礎上,進(jìn)行了深度二次開(kāi)發(fā)和功能擴展。不僅打通了 Android/iOS/Web 三端平臺,而且對京東移動(dòng)端基礎業(yè)務(wù)能力進(jìn)行了 SDK 級別的封裝,提供了統一、易于開(kāi)發(fā)的 API。業(yè)務(wù)開(kāi)發(fā)者可以通過(guò) JDReact SDK 平臺進(jìn)行快速京東業(yè)務(wù)開(kāi)發(fā),并且不依賴(lài)發(fā)版就能無(wú)縫集成到客戶(hù)端(android/iOS)或者轉換成 Web 頁(yè)面進(jìn)行線(xiàn)上部署,真正實(shí)現了一次開(kāi)發(fā),快速部署三端。
由于京喜 APP 的 JDReact 模塊都是獨立的 git 倉庫,所以需要調整我們 Taro 項目配置 config/index.js 的編譯輸出路徑如下:
<p>rn: {
outPath: '../jdreact-jsbundle-jdreactpingouindex'
}</p>
這樣,當我們運行 yarn run dev:rn 進(jìn)行本地開(kāi)發(fā)時(shí),文件自動(dòng)編譯到了 JDReact 項目,接下來(lái)我們就可以用模擬器或者真機來(lái)進(jìn)行預覽調試了。當我們在進(jìn)行本地開(kāi)發(fā)調試的時(shí)候,最高效的方式還是推薦用 Taro 官方提供的 taro-native-shell[3] 原生 React Native 殼子來(lái)啟動(dòng)我們的項目,詳細的配置參照該項目的 README 進(jìn)行配置即可。
由于 React Native 官方提供的 Remote Debugger[4] 功能非常弱,推薦使用 React Native Debugger[5] 來(lái)進(jìn)行本地 RN 調試,提供了更為豐富的功能,基本接近 H5 和小的調試體驗。
React Native Debugger 界面
這樣我們就擁有了一個(gè)正常的開(kāi)發(fā)調試環(huán)境,接下來(lái)就可以進(jìn)行高效的開(kāi)發(fā)了,由于我們前面在 H5 和小程序版本階段已經(jīng)完成了絕大部分的業(yè)務(wù)邏輯開(kāi)發(fā),所以針對 RN 版本的主要工作集中在 iOS 和安卓不同機型的樣式和交互適配上。
在樣式適配這塊,不得不提下 Taro 針對我們常見(jiàn)的場(chǎng)景提供了一些最佳實(shí)踐,可以作為布局參考:
Taro RN 最佳實(shí)踐集錦
在實(shí)際開(kāi)發(fā)過(guò)程中也遇到不少兼容性問(wèn)題,這里整理出來(lái)以供大家參考:
文本要用 標簽包起來(lái),因為 RN 沒(méi)有 textNode 的概念;
使用 Swiper 時(shí)在外面包一個(gè) View,否則設置 margin 后會(huì )導致安卓下高度異常;
Cannot read property 'x' of undefined,Swiper 底層使用的 react-native-swiper 導致的問(wèn)題,Disable Remote JS Debug 就不會(huì )出現。
圖片默認尺寸不對,RN 不會(huì )自動(dòng)幫助設置圖片尺寸,而是交給開(kāi)發(fā)者自己處理,故意這樣設計的;
Image 組件上不可以設置 onClick
實(shí)現基線(xiàn)對齊:vertical-align: baseline,用 把需要基線(xiàn)對齊的組件包住即可。
<p>abc
123</p>
盡量避免使用 line-height ,在安卓和 iOS 下表現不一致,而且即使設置為與 fontSize 相同也會(huì )導致裁剪;
android 調試生產(chǎn)環(huán)境的 bundle,搖手機,選 Dev Setting,取消勾選第一項 Dev 即可;
iOS 調試生產(chǎn)環(huán)境的 bundle,AppDelegate.m 中增加一行語(yǔ)句關(guān)閉 dev 即可:
<p>[[RCTBundleURLProvider sharedSettings] setEnableDev:false];
// 找到這行,并在它的上面增加上面這行
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];</p>
與 支持的 style 屬性不相同。
<p>> [TextStyleProps](https://facebook.github.io/react-native/docs/text-style-props "Text Style Props") & [View Style Props](https://facebook.github.io/react-native/docs/view-style-props)</p>
render 方法中不要返回空字符串
下面的代碼在 android 下會(huì )報錯(empty_string 內容為空字符串)
<p> {empty_string && }</p>
因為 empty_string && 的返回值是空字符串,RN 嘗試把字符串添加到 View 的 children 時(shí)在安卓環(huán)境下會(huì )報錯:
<p>Error: Cannot add a child that doesn't have a YogaNode</p>
border-radius 導致背景色異常,單獨給某個(gè)角設置圓角時(shí),沒(méi)有設置圓角的邊會(huì )出現一塊與背景色顏色相同,但半透明的色塊。
透明 View 無(wú)法點(diǎn)擊的問(wèn)題,給設置了 onClick 的元素添加透明背景色即可:style={{backgroundColor:'transparent'}},不可以用 scss 寫(xiě),只有寫(xiě)在 JSX 上的才有效,Taro 編譯時(shí)可能把透明背景色忽略了。
一像素縫隙問(wèn)題
可能是 RN 布局引擎的問(wèn)題,或單位轉換以及瀏覽器渲染中的精度損失問(wèn)題??梢哉{整頁(yè)面結構來(lái)繞過(guò)?;蛘吆?jiǎn)單粗暴一點(diǎn),設置負 margin 值蓋住縫隙。
跨平臺開(kāi)發(fā)JS 文件
1、文件拆分的方式
要"完美"的編譯出三端代碼,首先要解決的是公共類(lèi)庫的適配問(wèn)題,好在兄弟業(yè)務(wù)團隊已經(jīng)沉淀有完成度較高的三端公共類(lèi)庫,利用 Taro 提供的跨平臺開(kāi)發(fā)能力,抹平三端方法名和參數不統一的情況,即可很好的解決公共類(lèi)庫的適配問(wèn)題,如下所示:
<p>.
├── goto.h5.js
├── goto.rn.js
├── goto.weapp.js
├── request.h5.js
├── request.rn.js
├── request.weapp.js
└── ...</p>
以 request 公共組件為例,三端代碼如下:
request.h5.js
<p>import request from'@legos/request'
export{ request }</p>
request.rn.js
<p>import request from'@wqvue/jdreact-request'
export{ request }</p>
request.weapp.js(由于小程序的公共組件沒(méi)有發(fā)布至 npm,這里引用的本地項目源文件)
<p>import{ request } from'../../../common/request/request.js'
export{ request }</p>
如遇到需要適配的方法參數不一致或者增加額外處理的情況,可進(jìn)行再包裝確保最終輸出的接口一致,如下:
goto.rn.js
<p>import jump from'@wqvue/jdreact-jump'
<br />
functiongoto(url, params= {}, options = {}) {
jump(url, options.des || 'm', options.source || 'JDPingou', params)
}
<br />
exportdefaultgoto</p>
文件引入的時(shí)候我們正常使用就好,Taro 在編譯的時(shí)候為我們編譯對應的平臺的文件
<p>importgotofrom'./goto.js'</p>
2、條件編譯的方式
解決了公共類(lèi)庫適配之后,接下來(lái)就可以專(zhuān)注于業(yè)務(wù)代碼開(kāi)發(fā)了,同樣業(yè)務(wù)代碼在三端也可能存差異的情況,可以用 Taro 提供的環(huán)境變量來(lái)達到目的,示例代碼如下:
<p>if(process.env.TARO_ENV === 'h5') {
this.speedReport(8) // [測速上報] 首屏渲染完成
} elseif(process.env.TARO_ENV === 'weapp') {
speed.mark(6).report() // [測速上報] 首屏渲染完成
} elseif(process.env.TARO_ENV === 'rn') {
speed.mark(7).report() // [測速上報] 首屏渲染完成
}</p>
CSS 文件
以上是 js 的代碼處理方式,對于 css 文件及代碼,同樣也有類(lèi)似的處理。
1、文件拆分的方式
比如 RN 相對于 H5 和小程序的樣式就存在比較大的差異,RN 支持的樣式是 CSS 的子集,所以很多看起來(lái)很常見(jiàn)的樣式是不支持的,可以通過(guò)以下方式進(jìn)行差異化處理:
<p>├── index.base.scss
├── index.rn.scss
├── index.scss</p>
這里以 index.base.scss 作為三端都能兼容的公共樣式(名字可以任取,不一定為 xxx.base.scss),index.rn.scss 則為 RN 端獨特的樣式,index.scss 則為 H5 和小程序獨特的樣式,因為 H5 和小程序樣式基本上沒(méi)有什么差異,這里合為一個(gè)文件處理。
2、條件編譯的方式
Taro 也支持樣式文件內的條件編譯,語(yǔ)法如下:
<p>/* #ifdef %PLATFORM% */
// 指定平臺保留
/* #endif */
<br />
/* #ifndef %PLATFORM% */
// 指定平臺剔除
/* #endif */</p>
%PLATFORM% 的取值請參考 Taro 內置環(huán)境變量[6]
以下為示例代碼:
<p>.selector {
color: #fff;
/* #ifndef RN */
box-shadow: 1px1px1px rgba(0, 0, 0, .1);
/* #endif */
}</p>
編譯為 H5 和小程序的樣式為:
<p>.selector {
color: #fff;
box-shadow: 1px1px1px rgba(0, 0, 0, .1);
}</p>
RN 的樣式為:
<p>.selector {
color: #fff;
}</p>
兩種方式選其一即可,這樣就能開(kāi)開(kāi)心心的編寫(xiě)業(yè)務(wù)代碼了。
有些許遺憾的是產(chǎn)品經(jīng)理對這次新版首頁(yè)有著(zhù)明確的上線(xiàn)優(yōu)先級:先 H5 版,再微信小程序版,最后是 RN 版,這就為后續 RN 版本跟 H5 和 小程序版本分道揚鑣埋下了伏筆,條件允許的話(huà)建議優(yōu)先以 RN 版本為基準進(jìn)行開(kāi)發(fā),以免開(kāi)發(fā)完成 H5 和小程序之后發(fā)現對結構和樣式進(jìn)行大的調整,因為 RN 對樣式確實(shí)會(huì )弱一些。
性能優(yōu)化圖片優(yōu)化
電商性質(zhì)的網(wǎng)站,會(huì )存在大量的素材或商品圖片, 往往這些會(huì )對頁(yè)面造成較大的性能影響。得益于京東圖床服務(wù),提供強大的圖片定制功能,讓我們在圖片優(yōu)化方面省去大量工作。以引入商品圖片 "!q70.dpg.webp" 為樣本,我們對圖片應用做了部分優(yōu)化:
為 Image 標簽設置 lazyload 屬性,這樣可以在 H5 和小程序下獲得懶加載功能。
接口聚合直出
起初京喜首頁(yè)的首屏數據涉及的后端接口多達 20 余個(gè),導致整體數據返回時(shí)間較長(cháng);為了解決此項痛點(diǎn),我們聯(lián)合后端團隊,獨立開(kāi)發(fā)首屏專(zhuān)用的聚合直出接口。一方面,將眾多接口請求合并成一個(gè),減少接口聯(lián)動(dòng)請求帶來(lái)的性能損耗;另一方面,將復雜的業(yè)務(wù)邏輯挪到后端處理,前端只負責視圖渲染和交互即可,減少前端代碼復雜度;通過(guò)此項優(yōu)化,頁(yè)面性能和體驗得到極大改善。
緩存優(yōu)先策略
由于京喜業(yè)務(wù)主要圍繞下沉市場(chǎng),其用戶(hù)群體的網(wǎng)絡(luò )環(huán)境會(huì )更加復雜,要保障頁(yè)面的性能,減少網(wǎng)絡(luò )延時(shí)是一項重要措施。
為了提升用戶(hù)二次訪(fǎng)問(wèn)的加載性能,我們決定采用緩存優(yōu)先策略。即用戶(hù)每次訪(fǎng)問(wèn)頁(yè)面時(shí)所請求的主接口數據寫(xiě)入本地緩存,同時(shí)用戶(hù)每次訪(fǎng)問(wèn)都優(yōu)先加載緩存數據,形成一套規范的數據讀取機制。通過(guò)優(yōu)先讀取本地緩存數據,可讓頁(yè)面內容在極短時(shí)間內完成渲染;另外,本地緩存數據亦可作為頁(yè)面兜底數據,在用戶(hù)網(wǎng)絡(luò )超時(shí)或故障時(shí)使用,可避免頁(yè)面空窗的情景出現。
緩存優(yōu)先策略高性能瀑布流長(cháng)列表
首頁(yè)緊接著(zhù)首屏區域的是一個(gè)支持下滑加載的瀑布流長(cháng)列表,每次滑到底部都會(huì )異步拉取 20 條數據,總計會(huì )拉取將近 500 條數據,這在 iOS 下交互體驗還比較正常。但是在配置較低的安卓機型下,當滑動(dòng)到 2 到 3 屏之后就開(kāi)始出現嚴重卡頓,甚至會(huì )閃退。
針對這種場(chǎng)景也嘗試過(guò)用 FlatList 和 SectionList 組件來(lái)優(yōu)化,但是它們都要求規則等高的列表條目,于是不得不自己來(lái)實(shí)現不規則的瀑布流無(wú)限滾動(dòng)加載。其核心思路是通過(guò)判斷列表的條目是否在視窗內來(lái)決定圖片是否渲染,要優(yōu)化得更徹底些的話(huà),甚至可以移除條目?jì)人袃热葜槐A羧萜?,以達到減少內容節點(diǎn)以及內存占用,不過(guò)在快速進(jìn)行滑動(dòng)時(shí)比較容易出現一片白框,算是為了性能損失一些體驗,整體上來(lái)說(shuō)是可以接受的。
由于 RN 下在獲取元素坐標偏移等數據相對 H5 和小程序要麻煩得到,具體的實(shí)現細節可以查看抽離出來(lái)的簡(jiǎn)單實(shí)現Taro 高性能瀑布流組件(for RN)[7]。
寫(xiě)在最后
三端達到像素級別的還原
這篇文章從技術(shù)選型、開(kāi)發(fā)實(shí)錄再到性能優(yōu)化三個(gè)維度對京喜首頁(yè)改版做了簡(jiǎn)單總結。整個(gè)項目實(shí)踐下來(lái),再一次證實(shí) Taro 開(kāi)發(fā)框架已完全具備投入大型商業(yè)項目的條件。雖在多端開(kāi)發(fā)適配上耗費了一些時(shí)間,但仍比各端獨立開(kāi)發(fā)維護工作量要少;在前端資源匱乏的今天,選擇成熟的開(kāi)發(fā)工具來(lái)控制成本、提升效率,已是各團隊的首要工作目標。同時(shí),京喜作為京東戰略級業(yè)務(wù),擁有千萬(wàn)級別的流量入口,我們對頁(yè)面的體驗優(yōu)化和性能改進(jìn)遠不止于此,希望每一次微小的改動(dòng)能為用戶(hù)帶來(lái)愉悅的感受,始終為用戶(hù)提供優(yōu)質(zhì)的產(chǎn)品體驗。
參考資料