uni-app授帕、Vue3 + ucharts 圖表 H5 無(wú)法渲染

當(dāng)學(xué)習(xí)成為了習(xí)慣同木,知識(shí)也就變成了常識(shí)。感謝各位的 點(diǎn)贊豪墅、收藏評(píng)論泉手。

新視頻和文章會(huì)第一時(shí)間在微信公眾號(hào)發(fā)送黔寇,歡迎關(guān)注:李永寧lyn

文章已收錄到 github偶器,歡迎 Watch 和 Star。

封面

logo (14)

簡(jiǎn)介

從問(wèn)題定位開(kāi)始缝裤,到給框架(uni-app)提 issue屏轰、出解決方案(PR),再到最后的思考憋飞,詳細(xì)記錄了整個(gè)過(guò)程霎苗。

前序

當(dāng)你在業(yè)務(wù)中不幸踩了開(kāi)源框架的某些坑,這是你的不幸榛做,但這同時(shí)也是你的幸運(yùn)唁盏,因?yàn)檫@是你給自己簡(jiǎn)歷中增加亮點(diǎn)的絕佳機(jī)會(huì)。

而給開(kāi)源社區(qū)貢獻(xiàn) PR 是你證明自己技術(shù)側(cè)擁有 P7 實(shí)力的絕佳方式检眯,P7 的評(píng)判標(biāo)準(zhǔn)無(wú)非是業(yè)務(wù)和技術(shù)厘擂,業(yè)務(wù)上有收益,技術(shù)上有深度和廣度(別人有的你能做的更好锰瘸,別人沒(méi)有的你能有)刽严。

這次整個(gè)過(guò)程歷時(shí) 3-4 天,在此之前我也沒(méi)讀過(guò) uni-app 和 ucharts 的源碼避凝,所以這里把整個(gè)過(guò)程分享出來(lái)也是給大家一個(gè)解決問(wèn)題的思路舞萄。

環(huán)境

  • uni-app cli 版本 3.0.0-alpha-3030820220114011
  • hbuilder 版本 3.3.8.20220114-alpha
  • ucharts 版本 uni-modules 2.3.7-20220122

現(xiàn)象

uni-app、vue3 + ucharts 繪制圖表管削,開(kāi)發(fā)環(huán)境正常倒脓,但是打包上線(xiàn)后,H5 無(wú)法繪制圖表含思,也不報(bào)任何錯(cuò)誤崎弃。

開(kāi)發(fā) 線(xiàn)上
APP 正常 正常
H5 正常 無(wú)法繪制

問(wèn)題定位

給 ucharts 的社區(qū)提 issue,經(jīng)過(guò)交流茸俭,維護(hù)者 “懷疑“ 是 uni-app 的 vue3 的 renderjs 有問(wèn)題吊履,但是他也給不了一個(gè)肯定的答復(fù),讓去 uni-app 的社區(qū)提 issue 而且示例中不能用 ucharts调鬓。個(gè)人對(duì)于該回答持懷疑態(tài)度艇炎,于是決定自己去定位問(wèn)題。

懷疑是 ucharts 的 bug

  • ucharts 視圖部分的關(guān)鍵代碼
<view ...其它屬性 :prop="uchartsOpts" :change:prop="rdcharts.ucinit">
  <canvas ...屬性 />
</view>

這里有一個(gè)知識(shí)點(diǎn)需要補(bǔ)充:當(dāng) prop 發(fā)生改變腾窝,change:prop 的回調(diào)會(huì)被調(diào)用缀踪,這是 uni-app 框架提供的能力居砖,但官方文檔沒(méi)有提及,從源碼中可以看到驴娃。

  • 看了 ucharts 的源碼奏候,繪制圖表時(shí)的代碼執(zhí)行過(guò)程如下:
image

可是打包后的 H5 線(xiàn)上環(huán)境,當(dāng)執(zhí)行 this.uchartsOpts = newConfig 之后卻沒(méi)有觸發(fā) change:prop 事件唇敞,所以這看起來(lái)似乎是 uni-app 的 view 組件有問(wèn)題

感謝 ucharts 官方蔗草,在定位問(wèn)題過(guò)程中,和社區(qū)進(jìn)行交流后疆柔,ucharts 免費(fèi)贈(zèng)送了一個(gè)永久超級(jí)會(huì)員咒精,感謝 ?? ?? !!

view 組件的 prop 和 change:prop

提供如下示例:

<template>
  <view>
    <view :prop="counter" :change:prop="changeProp"></view>
        <view>{{ msg }}</view>
  </view>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from "vue";

const counter = ref(1)
const msg = ref('hello')

function changeProp() {
    msg.value = 'hello' + counter.value
}

// @ts-ignore
let timer = null
onMounted(() => {
    timer = setInterval(() => {
        counter.value += 1
    }, 1000)
})

onBeforeUnmount(() => {
    // @ts-ignore
    clearInterval(timer)
})
</script>

<style>
</style>

H5 開(kāi)發(fā)環(huán)境 H5 打包后
vue2 正常 正常
vue3 正常 change:prop 未執(zhí)行

因?yàn)殚_(kāi)發(fā)環(huán)境沒(méi)有問(wèn)題,所以在開(kāi)發(fā)環(huán)境中通過(guò)在 change:prop 方法中打斷點(diǎn)旷档,查看調(diào)用棧模叙,找到觸發(fā) change:prop 回調(diào)的方法,再一步步往上看鞋屈,終于發(fā)現(xiàn)了 uni-app 重寫(xiě)渲染器(render 函數(shù))的地方范咨,在 @dcloudio/uni-h5-vue/dist/vue.runtime.esm.js 中。

通過(guò)閱讀 uni-app 的源碼厂庇,得到如下內(nèi)容:

響應(yīng)式數(shù)據(jù)發(fā)生變化渠啊,觸發(fā) vue 的響應(yīng)式更新。比如你的響應(yīng)式數(shù)據(jù)作為元素的 prop 屬性傳遞宋列,則在 patch 階段會(huì)觸發(fā) patchProps 方法昭抒, 觸發(fā)該方法后,方法內(nèi)判斷新老 props 是否發(fā)生改變炼杖,如果變了灭返,則遍歷新的 props 對(duì)象,將其中的每個(gè)屬性坤邪、值和老的對(duì)比熙含,如果不相等 或者 props 的 key 為 change:xx 則直接調(diào)用 patchProp 方法,如果 __UNI_FEATURE_WXS__為真并且 props 的 key 為 change: 開(kāi)頭艇纺,則調(diào)用 patchWxs怎静,patchWxs 方法最終會(huì)通過(guò) nextTick 調(diào)用 change:prop 的回調(diào)方法。

以下為上述執(zhí)行過(guò)程的流程圖:

image

最終定位到問(wèn)題就出在 __UNI_FEATURE_WXS__上,發(fā)現(xiàn)開(kāi)發(fā)環(huán)境中它是 true,但是打包后就變成了 false鉴嗤。

__UNI_FEATURE_WXS__

__UNI_FEATURE_WXS__是一個(gè)全局變量,所以肯定是通過(guò) vite 的 define 選項(xiàng)進(jìn)行設(shè)置的夜牡。

于是接下來(lái)的目的就是需要找到 __UNI_FEATURE_WXS__是在什么地方進(jìn)行設(shè)置的÷虑可以全局搜該變量塘装,然后找到在 @dcloudio/uni-cli-shared 包中找到一個(gè)叫 initFeatures 的方法急迂,該方法中聲明了一個(gè) features 對(duì)象:

const {
  wx,
  wxs,
  // ...其它變量
} = extend(
  initManifestFeature(options),
  // ... 其它方法
)

const features = {
  // vue
  __VUE_OPTIONS_API__: vueOptionsApi, // enable/disable Options API support, default: true
  __VUE_PROD_DEVTOOLS__: vueProdDevTools, // enable/disable devtools support in production, default: false
  // uni
  __UNI_FEATURE_WX__: wx, // 是否啟用小程序的組件實(shí)例 API,如:selectComponent 等(uni-core/src/service/plugin/appConfig)
  __UNI_FEATURE_WXS__: wxs, // 是否啟用 wxs 支持蹦肴,如:getComponentDescriptor 等(uni-core/src/view/plugin/appConfig)
  // ... 其它屬性
}

看了該對(duì)象的設(shè)置沒(méi)什么問(wèn)題僚碎,wxs在開(kāi)發(fā)和生產(chǎn)環(huán)境下都是 true。那接下來(lái)就需要找到誰(shuí)調(diào)用了 initFeatures 方法阴幌,而且可能調(diào)用完了以后通過(guò)判斷當(dāng)前命令勺阐,比如:執(zhí)行 build 時(shí),將 __UNI_FEATURE_WXS__設(shè)置為了 false裂七。

剛開(kāi)始想正向推導(dǎo)皆看。vite-plugin-uni 是 uni-app 提供給 vite 的一個(gè)插件框架,uni-app 中的 vite 配置都來(lái)自于這里背零。

插件當(dāng)中的 uni 插件提供了 config 選項(xiàng),config 選項(xiàng)的值是調(diào)用 createConfig 方法返回的函數(shù)无埃,該函數(shù)會(huì)返回一個(gè)對(duì)象徙瓶,該對(duì)象會(huì)和 vite 的配置做深度合并;該對(duì)象有 define 選項(xiàng)嫉称,該選項(xiàng)的值為 createDefine 函數(shù)的返回值侦镇,該返回值是一個(gè)對(duì)象,其中調(diào)用了 initDefine织阅,再往下看發(fā)現(xiàn)不對(duì)壳繁,然后路 走死了。

發(fā)現(xiàn)上面正向推導(dǎo)的方式走不通以后荔棉,于是開(kāi)始反向推導(dǎo)闹炉,即全局搜索,都有哪些地方調(diào)用了 initFeatures润樱,然后一步步的往下推渣触,得到如下正確的流程圖:

image

經(jīng)過(guò)最終的調(diào)試,發(fā)現(xiàn) 啟動(dòng)開(kāi)發(fā)環(huán)境和打包時(shí)最終的調(diào)用路徑是:uniH5Plugin -> createConfig -> configDefine -> initFeatures壹若。
而最終的問(wèn)題也就是出在了 initFeatures 方法調(diào)用的 initManifestFeature 方法中嗅钻。

答案

最終定位到出問(wèn)題的地方在 @dcloudio/uni-cli-shared/src/vite/features.ts 文件的 initManifestFeature 方法中。有如下對(duì)比:

  • github 倉(cāng)庫(kù)的最新代碼店展,版本號(hào):3.0.0-alpha-3030820220114011
if (command === 'build') {
    // TODO 需要預(yù)編譯一遍养篓?
    // features.wxs = false
    // features.longpress = false
  }
  • 已發(fā)版的代碼,最高版本號(hào):3.0.0-alpha-3031120220208001
if (command === 'build') {
    // TODO 需要預(yù)編譯一遍赂蕴?
    features.wxs = false;
    features.longpress = false;
}

已發(fā)版的版本居然高于倉(cāng)庫(kù)內(nèi)的最新版本號(hào)柳弄。查看 npm 上的發(fā)布版本信息:

image

發(fā)現(xiàn)版本號(hào)發(fā)生了回退。這幾次回退的版本號(hào)都是不符合規(guī)范的版本號(hào)睡腿,而且其中可能攜帶了 bug语御,比如上面提到的最高版本峻贮。

發(fā)版出現(xiàn)版本號(hào)不符合規(guī)范的情況是由于項(xiàng)目還沒(méi)有一個(gè)規(guī)范的發(fā)版流程導(dǎo)致的,但是已經(jīng)是 alpha 版本了应闯,這種低級(jí)錯(cuò)誤還是應(yīng)該避免的纤控。

更致命的操作是,回退版本號(hào)碉纺。uni-app 目前每次升級(jí)都是升級(jí)的最小版本號(hào)后面的數(shù)值船万,而業(yè)務(wù)項(xiàng)目的 package.json 都是 "@dcloudio/uni-app": "^xxx" 的形式,這就意味著骨田,你每次重新裝包(比如自動(dòng)化部署時(shí))或者升級(jí)包時(shí)耿导,都會(huì)更新到這個(gè)存在 bug 的高版本,這就會(huì)導(dǎo)致線(xiàn)上系統(tǒng)報(bào) bug态贤。

解決方案

所以這里正確的處理方式是重新發(fā)一個(gè)更高版本的包舱呻,而不是回退版本。因?yàn)樵摬僮鲿?huì)導(dǎo)致用戶(hù)線(xiàn)上的系統(tǒng)出 bug悠汽,即以下代碼無(wú)法正常執(zhí)行:

<view :prop="msg" :change:prop="cb"></view>

當(dāng)正常情況下箱吕,當(dāng) msg 改變后,change:prop 的回調(diào)會(huì)執(zhí)行柿冲。但是這個(gè)攜帶 bug 的高版本包茬高,在打包時(shí)(npm run build)將 __UNI_FEATURE_WXS__設(shè)置為了 false,導(dǎo)致 change:prop 的回調(diào)不會(huì)被調(diào)用假抄。

總結(jié)

代碼可以回退怎栽,但是版本號(hào)不要回退,應(yīng)該基于當(dāng)前穩(wěn)定版本宿饱,重新發(fā)一版版本號(hào)更高的版本熏瞄。

于是就給官方提了 issue 和 解決方案

結(jié)果

官方已采納該解決方案刑棵,基于當(dāng)前穩(wěn)定版重新發(fā)布一版版本號(hào)更高的版本巴刻。

思考

針對(duì) uni-app 這種處于 alpha 版本的框架,項(xiàng)目?jī)?nèi)部也確實(shí)不應(yīng)該繼續(xù)使用 ^ 符號(hào)蛉签,還是應(yīng)該將版本號(hào)寫(xiě)死為最新的 tag 版本胡陪,因?yàn)榭偢S alpha 的最新版,確實(shí)可能會(huì)踩坑碍舍。

鏈接

感謝各位的:點(diǎn)贊柠座、收藏評(píng)論,我們下期見(jiàn)片橡。


當(dāng)學(xué)習(xí)成為了習(xí)慣妈经,知識(shí)也就變成了常識(shí)。感謝各位的 點(diǎn)贊收藏評(píng)論吹泡。

新視頻和文章會(huì)第一時(shí)間在微信公眾號(hào)發(fā)送骤星,歡迎關(guān)注:李永寧lyn

文章已收錄到 github,歡迎 Watch 和 Star爆哑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末洞难,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子揭朝,更是在濱河造成了極大的恐慌队贱,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潭袱,死亡現(xiàn)場(chǎng)離奇詭異柱嫌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)屯换,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)编丘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人趟径,你說(shuō)我怎么就攤上這事瘪吏。” “怎么了蜗巧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)蕾盯。 經(jīng)常有香客問(wèn)我幕屹,道長(zhǎng),這世上最難降的妖魔是什么级遭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任望拖,我火速辦了婚禮,結(jié)果婚禮上挫鸽,老公的妹妹穿的比我還像新娘说敏。我一直安慰自己,他們只是感情好丢郊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布盔沫。 她就那樣靜靜地躺著,像睡著了一般枫匾。 火紅的嫁衣襯著肌膚如雪架诞。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天干茉,我揣著相機(jī)與錄音谴忧,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沾谓,可吹牛的內(nèi)容都是我干的委造。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼均驶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼昏兆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辣恋,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亮垫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后伟骨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體饮潦,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年携狭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了继蜡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逛腿,死狀恐怖稀并,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情单默,我是刑警寧澤碘举,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站搁廓,受9級(jí)特大地震影響引颈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜境蜕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一蝙场、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粱年,春花似錦售滤、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至拉庶,卻和暖如春嗜憔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氏仗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工吉捶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夺鲜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓呐舔,卻偏偏與公主長(zhǎng)得像币励,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子珊拼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容