一(yī)、前言
提起微(wēi)信小(xiǎo)程序,相(xiàng↑₽≠α)信所有(yǒu)人(rén)都(dōu)不(bù)陌生(shēng),下(↑φxià)面這(zhè)個(gè)典型使用(yòng)場(chǎn∏♦g)景你(nǐ)一(yī)定經曆過:
餐館落座 —— 微(wēi)信掃桌角小(x↑λ€iǎo)程序碼 —— 使用(yòng)微∑ε>(wēi)信小(xiǎo)程序點餐🍔
微(wēi)信小(xiǎo)程序(下(xià)文(wén)簡稱:小(↓βxiǎo)程序)作(zuò)為(wèi)一(yī)種在微(wēi)信平©€÷台內(nèi)運行(xíng)的(de)應用(yòng)程序,用(y✔εα<òng)戶無需前往應用(yòng)商店(diàn)下(xià)載安裝包γε≈即可(kě)使用(yòng),可(kě)以在微(wēi)←★φ∑信內(nèi)被便捷地(dì)獲取和(hé₩')傳播,2017 年(nián)一(yī)經推出便迅速成為(wèi☆ δ)熱(rè)門(mén)技(jì)術(shù)關鍵詞,得(de)物(wù)也(¥∞yě)随即發布了(le)得(de)物(wù) App 小(xiǎo)程序,歡迎₽←↕掃碼體(tǐ)驗:
七年(nián)時(shí)間(jiān&↑>)過去(qù)了(le),小(xiǎo)程序的(de)周邊配套已經十分(fēn)成熟,微(wēi)信官方π×對(duì)小(xiǎo)程序生(shēng)λ☆₩态進行(xíng)了(le)很(hěn)多♣∑♣(duō)叠代 —— 微(wēi)信開(••πkāi)發者工(gōng)具從(cóng)難用(yòng)到(d$€ào)可(kě)用(yòng)、小(xiǎo)程∞×序 API 經曆了(le)多(duō)輪簡化(huà)和(hé)拓展、↑•數(shù)據分(fēn)析能(néng)力逐漸完善,同時(sh™♠$✘í)開(kāi)源社區(qū)也(yě)貢獻了(le)®≠ 非常多(duō)的(de)開(kāi)發框架、××實踐記錄等。
得(de)物(wù)內(nèi)部也(yě)形成了(le)自(zì)己的(de✔φ÷↕)小(xiǎo)程序開(kāi)發生(shēng)β∏态,本文(wén)主要(yào)介紹一('≈•yī)些(xiē)得(de)物(wù) App 小(x€$↕iǎo)程序版本叠代中形成的(de)開(kāi)發指南(nán)、實踐經¥驗等,給小(xiǎo)程序新手開(kāi)發者一(yī)些(xiē)實踐≈∞®經驗,如(rú)果你(nǐ)已經是(shì)&©個(gè)小(xiǎo)程序開(kāi)發高(gāo)手了(le),那ε§(nà)麽歡迎交流指正我們做(zuò)得(de)好(hǎo)的(de)♠↑φ / 不(bù)好(hǎo)的(de)部分(fēn)。
事(shì)實上(shàng),“小(xiǎo)程序” 這(zhè)種技(¥←$φjì)術(shù)架構并非微(wēi)信首創,但(dàn)無疑微(w™εφ✘ēi)信小(xiǎo)程序是(shì)目前生(shēng)态建設>© 最完整、用(yòng)戶量最大(dà)的(de)小(xiǎo)程序生∑∞(shēng)态。
二、小(xiǎo)程序運行(xíng)機(jī)制(zhì) ₩
先簡單介紹一(yī)下(xià)小(xiǎo)程↑₹"序的(de)運行(xíng)機(jī)制(zhì)和(hé)架構設計(jì)。↑₽">
小(xiǎo)程序的(de)架構設計(jì)初衷是(shì) “快(kuà₩i)”,同時(shí)又(yòu)需要(yào)€♣₽§對(duì)展示內(nèi)容做(zuò)嚴格的(de)安全管→δ★↓控,所以采用(yòng)了(le) Webview 結合 Nat✔ ive 的(de) Hybrid 技(j☆←'ì)術(shù),設計(jì)了(le)雙線程模βφ<♦型架構:
渲染層:小(xiǎo)程序界面由 Webview 渲染,一(yī)部分(fēn≠)較複雜(zá)組件(jiàn)用(yòng)客戶端原生(shēng)渲染,¥™以提供更好(hǎo)的(de)性能(néng)。ε ↓
邏輯層:一(yī)個(gè) JavaScript 沙箱環境 (利用(yòn↑§g)原生(shēng)客戶端系統的(de) JavaS÷≥cript 的(de)解釋引擎創建),隻執行(xíng)有(yǒu)關小(≠$↔$xiǎo)程序業(yè)務邏輯的(de)代碼,不(bù)能(néng)訪問(w←®èn)任何浏覽器(qì)相(xiàng)關接口,以避免₩ε惡意代碼運行(xíng):在運行(xíng)時(shí)訪問(±γ÷wèn) DOM 樹(shù)獲取敏感數(shù)據、跳(tiào)轉到♦α↑↔(dào)其他(tā)在線網頁等。
上(shàng)述渲染層和(hé)邏輯層隻是(®∏shì)上(shàng)層的(de)抽象概念,在不(bù)≥↑®"同運行(xíng)環境下(xià)有(yǒu)各自(zì)技(jì)術( Ωshù)實現(xiàn),如(rú)下(xià)表:
小(xiǎo)程序本質上(shàng)是(shì) Web 和(hé) Nat ₹©ive 的(de)結合 —— 成熟的(de) W× eb 渲染技(jì)術(shù)負責界面渲染、Native 提供客戶δ↑ε端原生(shēng) API 補充 Web 的(de)短(duǎn)闆;由Ω↓于 Web 基于單線程模型且開(kāi)放(fàng)靈活,因此微(λ<wēi)信隔離(lí)了(le)渲染層與∏→ε邏輯層,以此作(zuò)為(wèi)對(duì)內(nèi)容安全↑≈管控的(de)有(yǒu)效控制(zhì)手段。
目前小(xiǎo)程序在渲染層上(shàng)已經有(yǒ₩≠∏u)了(le)基于 "Skyline 渲染線程" 的(de)新型架構δ☆,減少(shǎo)了(le)雙線程架構之間(jiān)的(de)通(tōn"✘Ω g)信開(kāi)銷和(hé)內(nèi)存占用(yòng),理(lǐ≤≤α∑)論上(shàng)擁有(yǒu)更好(hǎo)的(de)性能(néng),需←λ≠要(yào)單獨開(kāi)啓,可(kě)自(zì)行(x☆∞±íng)查閱相(xiàng)關文(wén)檔•&。
三、開(kāi)發階段
從(cóng)小(xiǎo)程序的(de)運行(xíng)機(&™jī)制(zhì)可(kě)以得(de)¶γ知(zhī):小(xiǎo)程序在開(kāi)發、發布、運行★₽δ↔(xíng)等每個(gè)環節都(dōu)依賴于微(wēi)信自(zì☆✘πσ)身(shēn)的(de)生(shēng)态而非傳統 Web,所以有(yǒ© ∞u)很(hěn)多(duō)特有(yǒu)的(de)設計(jì)。先介紹±λ☆一(yī)些(xiē)基礎概念和(hé)知(zhī)識:
用(yòng)戶端運行(xíng)的(de)小(xiǎo)程序資源文(wé♥£×≤n)件(jiàn)需要(yào)先上(shàng)傳到(dào✔₽Ω)微(wēi)信側,然後才能(néng)推送到(∑"•✘dào)用(yòng)戶端,微(wēi)信限制(zhì)了(le) 資源體(tǐ)積大(dà)小(xiǎo):
主包:小(xiǎo)程序默認啓動頁面 / TabBa≠↓≠r 頁面的(de)構建産物(wù),以及一(yī)些(xiē)所有(yβ×↔™ǒu)分(fēn)包都(dōu)需用(yò÷γng)到(dào)公共資源 / JS 腳本;
分(fēn)包:為(wèi)了(le)提高(gāo)↕✘初始化(huà)加載速度,開(kāi)發者可(kě)以劃分(fē≤₽₽←n)以頁面為(wèi)維度的(de)分(fēn)包,分Ω☆ (fēn)包隻包含一(yī)些(xiē)子(zǐ✘→®©)級頁面的(de)代碼。
跨平台框架選型
如(rú)果你(nǐ)的(de)項目确實隻需要(yào)運行(xíng)在微(✘∞wēi)信小(xiǎo)程序平台,選用(yòng)微(α>φwēi)信小(xiǎo)程序原生(shēng)開(kāi)發方式或許&λγ是(shì)一(yī)個(gè)更好(hǎo∏§')的(de)選擇 —— 能(néng)随時(sh₽<✔≥í)接入微(wēi)信小(xiǎo)程序的(de)最新特 ¥Ω↑性和(hé) API,缺點就(jiù)是(shì)不(bù)夠靈活,如(r★β←δú)果日(rì)後還(hái)想要(yào)在别★α的(de)平台開(kāi)展相(xiàng)同的(de)業(★÷★yè)務,需要(yào)額外(wài)開(kāi)發工(gγ$>ōng)作(zuò)。
更普遍的(de)情況是(shì),大(d£∞à)多(duō)數(shù)開(kāi)發者都(d&♥ōu)選用(yòng)跨端框架去(qù)開(kāi)發小(xiǎ↕♦®o)程序,畢竟程序員(yuán)都(dōu)喜歡 Write✘& once, run anywhere,所以支持小(xiǎo£<¶∞)程序端的(de)跨平台框架在小(xiǎo)程序剛推™₽→♣出的(de)前幾年(nián)如(rú)雨(yǔ)後春筍>σ↔般層出不(bù)窮。
當然,截止到(dào) 2024 這(zhè)個(gè)時(•€δshí)間(jiān)節點,其中很(hěn)多( duō)框架都(dōu)已經停止維護(比如(rú) remax、mpvueπ♣β、wepy...),目前比較推薦的(de)跨平台框架有(yǒu ≠↔):uni-app、Taro,兩者異同比較:
一(yī)句話(huà)總結:喜歡寫 Vue 的(de)話(huà)用(y<↑§←òng) uni-app,喜歡寫 React 用(yò•"ng) Taro,這(zhè)兩者在小(xiǎo)程序平台上(sh±↓àng)的(de)表現(xiàn)來(lái)說(shuō)都(dσ 'ōu)沒有(yǒu)絕對(duì)的(de)優✔¥≠₩勢和(hé)劣勢,社區(qū)活躍度都(dōu)很(★£♠hěn)高(gāo),時(shí)至今日(rì)§γ♦都(dōu)在持續更新維護中。
目前在得(de)物(wù)內(nèi)部,uni-app 和 §π(hé) Taro 都(dōu)有(yǒu)™ 使用(yòng)。
包體(tǐ)積優化(huà)
主包 / 分(fēn)包配置
從(cóng)前文(wén)中可(kě)↓&以得(de)知(zhī),微(wēi)信限制(zhì)了"♦₩(le)單個(gè)分(fēn)包 / 主包大(dà)小(xσ§iǎo)不(bù)能(néng)超過 2M,因此需要(yà σ©o)規劃合理(lǐ)的(de)目錄,以 ↔☆σuni-app 的(de)開(kāi)發£γγ 目錄做(zuò)示例:
├── ... ├── bin // 構建§✔™命令 ├── loaders ├── src │↓↔ ├── assets // 靜(jìng)态資源 │ ├── compone♥$₹nts // 通(tōng)用(yòng≠✘)組件(jiàn) │ ├── pages // $↓主包目錄 │ ├── product // product分(f₽£ēn)包目錄 │ ├── order // order分(fēn)包目錄 │ ™€ ├── ... │ ├── sdk // 外(•Ωwài)部SDK │ ├── store≤♠∏ // 全局狀态 │ ├── style // 樣式文(wén)件(jiàn)>↔∑ │ ├── utils // 通(tōng)用(yòng)方法 │ └↑☆>── wxcomponents // 小(xiǎo)程序原生(shēng¶δ$≈)組件(jiàn) ├── ...
小(xiǎo)程序根目錄下(xià)的(de) app.json 文 ↓≤¥(wén)件(jiàn)用(yòng)來(lái)對(duì)微(wα™ēi)信小(xiǎo)程序進行(xíng)全局配置,決定頁面α♣文(wén)件(jiàn)的(de)路(lù)徑、窗(chuāng)口表現(x§♠→♥iàn)、設置網絡超時(shí)時(shí)間(jiān)、₩£∑設置多(duō) tab 等。(選用(yò₽ ng)不(bù)同的(de)跨平台框架會(h≥≈φuì)有(yǒu)不(bù)同的(de)配置方式和(hé)語法,但(dà¥$n)是(shì)殊途同歸,編譯到(dào)小(xiǎo)程序平台的(de☆₹§φ)配置文(wén)件(jiàn)都(dōu)¥✘ 會(huì)遵從(cóng)小(xiǎo↕≥ §)程序規範,下(xià)文(wén)将用(yòng)小(xi'±€ǎo)程序原生(shēng)語法做(zuò)說(shuō)明(míng)。)
需要(yào)額外(wài)注意的(de)是(shì),考慮到♦≈Ω§(dào)小(xiǎo)程序有(yǒu)主包和(hé)分(fēn)包的(de)φ©☆設計(jì),将關聯性較強的(de)頁面放₽∑(fàng)在同一(yī)目錄裡(lǐ)可(kěδε≤)以更合理(lǐ)地(dì)配置分(fēn)包,示例如(rú)下(xià):
// app.json { // 主包頁面φ♥← "pages": [ "pages/index/index", ÷ ₽"pages/xxxxx/index", ], // 分₽∞™(fēn)包配置頁面 "subPackage≠§☆s": [ { "root": "product", "pages": [γε "xxxxx/index", ] }, ], "windβ♣ow": { // 全局相(xiàng)關配置 }, "tabB↔≈σar": { // tabBar相(xiàng)關配置 } } 
即便是(shì)合理(lǐ)地(dì)配置了(le)分(fē§≥n)包且做(zuò)好(hǎo)了(le)目錄規劃≠✘←,也(yě)依然可(kě)能(néng)超過 2M 的(de)體(≠δ✔tǐ)積限制(zhì),這(zhè)個(gè)時(shí )候我們的(de)優化(huà)手段跟 Web 項目基本相(xi™☆Ωàng)同,這(zhè)裡(lǐ)不(bù≤♣≤)再贅述,主要(yào)手段:靜(jìng)态資源從(cóng) cdnγ☆ε± 加載、代碼壓縮、依賴優化(huà)分(f♥✔ēn)析等。
分(fēn)倉開(kāi)發
小(xiǎo)程序的(de)構建發布機(jī)制(zhì)∑"♦決定了(le)所有(yǒu)頁面都(dōu)要(yà≤≤•₩o)一(yī)起打包、上(shàng)傳,在開(kāi)發階段也(yě)是Ω∏(shì)如(rú)此。
我們曾經真實經曆的(de)開(kāi)發流δ≤程:
我們的(de)小(xiǎo)程序業(yè)務代碼已經非常龐大(dà),面對(β duì)這(zhè)樣複雜(zá)的(de)多(duō)線≥∑程開(kāi)發流程,開(kāi)發階段的(de)編譯構δ¶∏≤建給研發電(diàn)腦(nǎo)極大(dà)¥↕ ∞的(de)內(nèi)存壓力,卡頓屬實家(jiā)常便飯。
為(wèi)了(le)能(néng)更高(gāo)效地(dì)進行(x ∏↔íng)開(kāi)發工(gōng)作(zu§'ò),我們利用(yòng) Webpack 的(de)虛拟模塊能(néng)Ω♥§÷力,結合私有(yǒu) npm 包管理(lǐ),将業(yè)務代碼收斂進了↑(le)各業(yè)務域的(de)倉庫內(nèi)δ∑•→,做(zuò)到(dào)了(le):
将一(yī)個(gè)完整的(de)小(xiǎ$αo)程序項目,分(fēn)割成多(duō)個(gè)能 λ(néng)獨立進行(xíng)開(kāi)≥↓λ發、部署的(de)子(zǐ)應用(yòng)±€(基于獨立 git 倉庫),同時(shí)又(yòu)可(kě)以将所有(yǒ←£αu)子(zǐ)應用(yòng)作(zuò)為(wèi)一(yī)個(gè)₹←完整小(xiǎo)程序應用(yòng)打包發布。
時(shí)至今日(rì),分(fēn)倉開(kāi)發在得(de'&)物(wù)成為(wèi)了(le) “過去(qù)式”—— 由于後續的(de♥§)一(yī)波研發電(diàn)腦(nǎo)大(dà)升級(唯快(kuà∑π→i)不(bù)破 M2 Pro + 力大(dà<€)磚飛(fēi) 32GB RAM),同時(shí)得(de)≤&÷物(wù)在 QQ 平台 & 字節平台的(de)£$♠小(xiǎo)程序也(yě)停止了(le)叠代。隻運行(xíng) W÷∏♦eb 構建和(hé)小(xiǎo)程序構建,并不(bù)會(™®£≥huì)卡頓影(yǐng)響開(kāi)發效率,所以目前已經不(b§§←♣ù)再需要(yào)分(fēn)倉開(kāi)發模式。
限于本文(wén)主題和(hé)篇幅,這₽£↔≤(zhè)裡(lǐ)我們不(bù)再過多(duō)贅述分(f' ←ēn)倉開(kāi)發相(xiàng)關實現(xiàn),有↓••(yǒu)興趣的(de)話(huà)記得(de)關注我們,後續可(kλ∏ě)以整理(lǐ)一(yī)波技(jì)術(shù)文(wén)★↔檔以供方案參考~
提效工(gōng)具
在 Web 中切換 API 環境有(yǒu)天然的(de)域名隔離(líΩΩ×),可(kě)以直接訪問(wèn)不(bù)→≤×同域名下(xià)部署的(de)站(zhàn)點。而在小(xiǎo)"®×β程序中,像原生(shēng) App 一(yī)樣,頁面路(lù)徑在用(yΩ★<òng)戶端是(shì)無感且不(bù)能(néng)修改的₽ •φ(de),而且小(xiǎo)程序沒有(yǒu)安裝包的(de)概念,£×同一(yī)時(shí)間(jiān)隻存在一(yī)個(gè)體(tǐ)驗版↓>α₽。所以為(wèi)了(le)更方便去(qù)調試和(£hé)測試,可(kě)以做(zuò)一(γ<±yī)些(xiē)提效小(xiǎo)工(gōng)具。
API 環境切換功能(néng)
在 TabBar 頁面可(kě)以開(kāi)發一(yī)個(gè)環境™₩σ✘切換功能(néng),例如(rú):
<view v-if="!IS_PRODUCT×→ION" class="changeServiceE∏¶♦nv"> <view class="changeTitl₽'e">環境切換</view> <radio-←¥group @change="radioChange"&g♦Ω t; <radio v-for="item in×₹✘® ENV_Array" :key="item" •φ:value="item" :checked="item === SE♣α✔RVICE_ENV" class="rad÷≠γio-info" > {{ item }}₹© </radio> </radio-group>€> </view>
radioChange(e) { let { value "σ} = e.detail this.$store.commit('SETβ÷☆♠_SERVICE_ENV', value) uni.showT→₹×oast({ title: `當前環境是(shì)$÷±♠≥{this.SERVICE_ENV}` }) }
這(zhè)樣就(jiù)可(kě)以做(zuò)到(dà∏§o)在單一(yī)體(tǐ)驗版中自(zì)由切換 API 環境,驗證不(bù≈γ♦φ)同環境下(xià)的(de)數(shù)據展現(xiàn)和 ™★✘(hé)業(yè)務邏輯了(le)。
DEV 面闆
在測試場(chǎng)景下(xià),嘗試訪問(wèn)路(lù)徑較深的(∑πde)頁面會(huì)比較耗時(shí)繁瑣,和(hé)很(hěn)α&↓多(duō)原生(shēng) App 的(de)測試包做(zu✘€€ò)法一(yī)樣,可(kě)以開(kāi)♣ ↕☆發一(yī)個(gè)全局的(de) DEV 面闆。
但(dàn)是(shì)受限于小(xiǎo)程序的(de)架構設計(jì):小♠α(xiǎo)程序每跳(tiào)轉到(dào)一(yī)個(gè)頁面,§$±&實際上(shàng)都(dōu)是(shì)打開(kāi&≥)一(yī)個(gè)新的(de) Webview,在這(zhè)種設£γ±♦計(jì)架構下(xià),雖然可(kě)以®₽注冊全局組件(jiàn),但(dàn)是(shì)如(rú)果想要(yào)在←®每個(gè)頁面都(dōu)渲染出全局組件(jiàn),還↔₹ &(hái)是(shì)需要(yào)在每Ω<>個(gè)頁面都(dōu)寫一(yī)遍¥φ→¶全局組件(jiàn)的(de)代碼,這(zhè)樣并不(bù)π$ cool,我們探索出來(lái)的(de)方案:
在非生(shēng)産環境的(de) Webpack 配置中使 ♠π用(yòng)注入全局組件(jiàn)的(de) loader:
關鍵代碼:
// 全局loader主要(yào)代碼 functi £on modifyTemplateStrin✘λg(inputString, customTag) { // 查找 &©≠lt;template> 标簽內(n≥$èi)容 let templateStart if ™ (inputString.indexOf('<template&≠★¥gt;') > -1) { templ€≠ ateStart = inputString.indexOf('<te'✔σ←mplate>') + '<template>™;'.length } const templa≥™π↓teEnd = inputString.ind≈βexOf('</template>') c™∑"onst templateContent = inputString.s<♦πubstring(templateStart, templat∏ eEnd).trim() let modifiedTe £♠mplateContent = '' // 在 <templaγ©te> 第一(yī)個(gè)元素開(kāi)頭插入自(zì)定義标簽>£ modifiedTemplateCont♠γ'♥ent = templateContent.replace£♣$(/(^\s*<\w+(?:-\w+)*\b(?:\s+(?:" ™€[^"]*"|'[^']*'|[^>"])+)?\s*>♣✘×;)/, `$1\n${customTag}`) €ε∏// 替換原始字符串中的(de) <template> ×; 和(hé) <script&g ¥>t; 內(nèi)容 return inp€®↓utString .replace(templateContent, () =✘←¶> modifiedTemplateContent)÷ε } module.exports = func©÷↓±tion loader(source) { const relPath = pδ ✘ath.relative(path.join(__dirname, '../'βΩ, './src'), this.resourcePath) // ♦λ<devPanel>是(shì)已經 ©在全局中注冊過的(de)全局組件(jiàn) return modifyT×πemplateString(source,•∑ '<devPanel></&ε☆devPanel>') }
這(zhè)樣就(jiù)能(néng)自(zì)動在所有(y'∞γ™ǒu)頁面渲染出全局 DEV 按鈕組件(jiàn✘β>✔)了(le),可(kě)以更加方便地(dì)進行(xíng)各種快(ku ≈ài)捷操作(zuò),實現(xiàn)效果如(rú)下(xià):
自(zì)動化(huà)發布
小(xiǎo)程序開(kāi)發完成之後,微(w★✔∏ēi)信開(kāi)發者工(gōng)具提供了(le)上(shàng)傳入口σ∏,構建産物(wù)上(shàng)傳之後,需要(yào)到(dào)σ¥小(xiǎo)程序後台再設置為(wèi)體(tǐ)驗版,§β×♥如(rú)下(xià)圖所示:
每個(gè)開(kāi)發者都(dōu)這(zhè)樣操作(z'<εuò)會(huì)造成後台系統上(shàng)有(y€★&♣ǒu)很(hěn)多(duō)的(de)開(kδ₹•āi)發者版本,而且不(bù)同系統環境下(xià)的(de)構建 ✘産物(wù)可(kě)能(néng)不(bù)一(yī)樣,這(zhè)樣&♥的(de)工(gōng)作(zuò)流低'£©(dī)效且不(bù)穩定,所以通(tōng)過專門(mén)的(de→←↕)機(jī)器(qì)執行(xíng)構建,并将構建産物(wù)✔© 上(shàng)傳到(dào)微(wēi)★∑δ✔信服務器(qì)是(shì)更可(kě)靠的<←♥(de)選擇。
目前我們的(de)發布工(gōng)作(zuò)流γ↕ '如(rú)下(xià):
1. 開(kāi)發人(rén)員(yuán)将代碼合入指定分(fēγ♥σ n)支後,會(huì)觸發發布平台的(de)持續部署任©"γ務,打包機(jī)拉取代碼後執行(xíng)命令:
// 打包機(jī)執行(xíng)的(de)命令 ☆™★#!/usr/bin/env node const shell = requi ©☆✘re('shelljs') const s™δΩignale = require('signale') const { S₽≠σ₹ignale } = signale const ci&'¥ = require('miniprogram-ci'<≥) async function main() {↔×£↑ const interactive = new Signale({ i≈φ♣λnteractive: true }) interactive.pending α≠©(task) // 執行(xíng)構建命令 const resul'€t = shell.exec(`npm run ∑δbuild`) if (result.code !== 0) { // 如(₩Ωπ★rú)果構建失敗了(le) 退出 interacti✔×$☆ve.error(task) process.e★xit(1) } else { const project = n∏₹↔λew ci.Project({ type: 'mini∑λ÷Program', projectPath: '/dist/dev/mp-w• πeixin', ignores: ['node_modules/**/*'Ω©♥§], }) // 将構建産物(wù)上(shàng)傳至微(wēi)信服務★€ 器(qì) ci.upload({ proje≠ ct, }).then(res => { console.log(∑→→'上(shàng)傳成功') // 通(tōn®≈g)過IM通(tōng)知(zhī)相(xiàng)關測試/ ™✘研發驗證體(tǐ)驗版小(xiǎo)程序 }).catch(err =&'gt; { console.log('上(s©₽σhàng)傳失敗') interactive.error(taskαδε÷) process.exit(1) }) }©'∑↑ } main()
2. 打包并上(shàng)傳成功後,通(→↑λtōng)過 IM 通(tōng)知(zhī)相(xiàng)關測試 /∞₹★ 研發驗證體(tǐ)驗版小(xiǎo)程序:
miniprogram-ci 是(shì)從(cóng)微(wēi)®♥信開(kāi)發者工(gōng)具中抽離(l®™í)的(de)關于小(xiǎo)程序 / 小(xiǎo)✔★☆遊戲項目代碼的(de)編譯模塊。
使用(yòng)前需要(yào)使用(yòng)小(₹Ω≠xiǎo)程序管理(lǐ)員(yuán)身(s §hēn)份訪問(wèn) "微(wēi)信公衆平台 - 開(kāi)≠∏發 - 開(kāi)發設置" 後下(xià$π)載代碼上(shàng)傳密鑰,并配置 IP 白(bái)名單,才能(nén↕¥g)進行(xíng)上(shàng)傳、預覽<♣±操作(zuò)。
miniprogram-ci 從(cóng) 1.0.28 開(kāi)始支↓α持第三方平台開(kāi)發的(de)上(shàn¶♥αg)傳和(hé)預覽,調用(yòng)方式與普通(tōng)開(kāi)發 ≈λ♣模式無異。
采用(yòng)自(zì)動化(huà)發布的(de)優勢:
四、發布後的(de)數(shù)據分(fēn)析
想要(yào)對(duì)小(xiǎo)程序産生(shēng)的(de✔γ×±)數(shù)據進行(xíng)精确化(huà)分(fēn)≈₩析,除了(le)自(zì)建監控和(hé)埋點,還(hái)可(kě)以從(c★€óng)微(wēi)信官方提供的(de) “We 分(fε¶<ēn)析” 數(shù)據分(fēn)析平台入手γ✘£$,我們從(cóng)研發比較關心的(de∞™λ€)兩點做(zuò)介紹:穩定性監控、JS 錯(cuò)誤分(≠fēn)析。
穩定性監控
JS 錯(cuò)誤分(fēn)析
“JS 分(fēn)析” 面闆,這(zhè)裡(lǐ)可(k★≠ě)以通(tōng)過版本、時(shí)間(jiān)等多(duō)♠γ個(gè)維度篩選微(wēi)信記錄的(de) JS 錯(cuò)♥Ω♥誤,通(tōng)過錯(cuò)誤堆棧信息可(kě)以定位到 ♣(dào)代碼中的(de) bug 進行δ§↑(xíng)修複。
同樣可(kě)以配置微(wēi)信告警群,群裡(lǐ)會(huì)定§ ♠¥時(shí) push 錯(cuò)誤量的(de)趨勢,能(néng&)夠讓開(kāi)發者及時(shí)觀測到(dào)新發布版本的(de)代碼σ≠↕φ bug。
五、總結思考
在小(xiǎo)程序發布之初,很(hěn)多(duō)開(kāi)發者都↑πγ¥(dōu)不(bù)看(kàn)好(hǎo)小( ♣↓∏xiǎo)程序。從(cóng)技(jì)術(shù)視(shì)角來(₹δlái)看(kàn),小(xiǎo)程序确實帶著(zhe)非常多(du↕πō)的(de) debuff:閉源、充滿限制(zhì)σ∑♣←、原生(shēng) IDE 醜、bug 多(duō)。然而,如(ε•rú)今看(kàn)來(lái),不(bù)€δ ☆論開(kāi)發者是(shì)否接受這(zhè&"©δ)種與 Web 精神相(xiàng)悖的(de)技(jì)術≤↕×(shù)理(lǐ)念,也(yě)不(bù)妨礙它已經成為(wèi)↕δ ÷一(yī)種新的(de)技(jì)術(shù)标準 —— 目前市(shì)場(chǎng)上(shànγ∏≠÷g)很(hěn)多(duō) App 都(dōu)已建設了(le)×"©自(zì)己的(de)小(xiǎo)程序生(shēng)态,σ←如(rú)支付寶小(xiǎo)程序、飛(fēi)書(γ<shū)小(xiǎo)程序等,它們無一(yī)例外(wài)都(dōu)參考了(le)微(wēi)信的♣<₹≠(de)技(jì)術(shù)架構和(hé) API Ω↑₽設計(jì)。
盡管小(xiǎo)程序在技(jì)術(shù)上(shà±∏ng)存在諸多(duō)限制(zhì)和(hé)缺陷,但(dàn>)其所帶來(lái)的(de)便利和(hé)商業§$★(yè)機(jī)會(huì)無疑是(shì)巨大'≈ (dà)的(de)。未來(lái),随著(₩'↑zhe)技(jì)術(shù)的(de)不(bù)斷進步和(hé±$&)生(shēng)态的(de)逐漸完善,小 ✘β(xiǎo)程序有(yǒu)望成為(wèi)移動應用(yòng)開(kāi)發的(de)重要♣∏(yào)範式之一(yī),為(wèi)用(yòng)戶和(σ↓™'hé)開(kāi)發者創造更多(duō)價值♠↓。
同時(shí),小(xiǎo)程序的(de)成功也(yě)提醒我們開(kāi€±)發者,要(yào)不(bù)斷關注和(hé)學習(xí)新技(jì)術 δ(shù),不(bù)斷調整自(zì)己← 的(de)思維和(hé)方法,以适應技(jì)術(δ®©shù)和(hé)市(shì)場(chǎng)的(de)變化(huà)。∑§
引用(yòng):
https://developers.weixin.qq.coλ✔$ m/miniprogram/introduction/
https://segmentfault.com/a/11900000∑£π19131399
https://juejin.cn/post/7087041847700×®× 226062
https://developers.weixin.qq≠∑"£.com/ebook?action=get_post_info&doc≠→id=0000286f908988db00↓×ε866b85f5640a
https://developers.w✔≥eixin.qq.com/miniprogr♠→✘am/dev/framework/runtime/skyline/in £ troduction.html
https://uniapp.dcloud.net.cn/
https://docs.taro.zo↔≠ ne/docs/
https://www.npmjs.com/package/miniprogrΩam-ci