知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!
您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >
在 2020 年,談小程序框架該如何選擇
發(fā)表時間:2021-1-11
發(fā)布人:葵宇科技
瀏覽次數(shù):51
微信并不是第一個做小程序的 App,而是做小程序最有優(yōu)勢的 App,比如高流量、用戶較長的停留時間等等。站在微信的視角,小程序從業(yè)務(wù)形式上更像是公眾號開發(fā)的演變產(chǎn)物。在更早的時候,微信通過 sdk 的形式,增強(qiáng)了開發(fā)者開發(fā)公眾號網(wǎng)頁的能力。小程序的誕生是微信本身邁向平臺化超級 App 的 業(yè)務(wù) 行為,并且?guī)椭脩舾玫膶崿F(xiàn)了「輕量級 Web App」。
微信小程序誕生之初就自己定義了一套”標(biāo)準(zhǔn)“,與前端已有的生態(tài)格格不入,最開始的框架甚至沒有組件、沒有 npm,和 Web 生態(tài)嚴(yán)重脫節(jié)。由于特殊的雙線程模型與四不像的語法,開發(fā)者苦不堪言。小程序的 開放 只是對三方業(yè)務(wù)的開放而已。
蜂擁而至的效仿
其它廠商看到了小程序業(yè)務(wù)的開放性,試圖也能夠做成平臺型 App。支付寶小程序、百度小程序、淘寶小程序、360小程序、快應(yīng)用......它們中的大多數(shù)都不約而同的選擇了和微信類似的架構(gòu)、框架,而這更多的不是從技術(shù)角度去做的決定,而是想盡可能蹭微信小程序的福利,讓開發(fā)者可以更快的投放到自己的平臺。當(dāng)然,其中有兩個稍顯不同。一個是早期的淘寶小程序,它不僅支持 axml 的寫法,同時還支持 sfc -- 用 Vue 來開發(fā),這個架構(gòu)更大程度上讓開發(fā)者有了選擇的權(quán)利,并且能夠更好地連接已有的前端生態(tài)。另一個是快應(yīng)用,也是用類似 Vue 的語法來開發(fā),但是略顯畸形的是它自己又造了一套標(biāo)準(zhǔn),更像是對 Vue 進(jìn)行了魔改,開發(fā)者的開發(fā)成本并沒有得到有效的提升。
小程序框架選擇
小程序原生語法 and 增強(qiáng)型框架
小程序原生語法
是不是原生語法一定是被唾棄的。站在 2020 年這個時間節(jié)點上來說, 并不是這樣 。單純就微信小程序 or 支付寶小程序而言,目前的小程序生態(tài)是完完全全足夠開發(fā)者利用前端已有的部分生態(tài)來開發(fā)出符合預(yù)期的應(yīng)用的。
與早期 npm 能力的缺失、只能通過模板渲染實現(xiàn)組件化相比而言。現(xiàn)在的小程序已經(jīng)能夠做到前端工程化,并且植入前端生態(tài)中已有的一些理念,例如狀態(tài)管理、CLI 工程化等等。
也就是說,當(dāng)業(yè)務(wù)的需求只有投放到微信小程序或者支付寶小程序的時候,原生語法完完全全可以成為前端程序員們的一個選擇。你可以組件化你的項目,你可以手寫一個或者使用社區(qū)已有的狀態(tài)管理庫來顆粒化管理組件狀態(tài),你甚至還可以直接用 TypeScript 來編寫你的應(yīng)用??傊?,你幾乎可以把你所習(xí)慣的東西都帶到小程序這個域里。
漸進(jìn)增強(qiáng)型框架
所謂漸進(jìn)增強(qiáng)型框架,更多的還是在小程序引入 npm 之后,有了更加開放的能力所帶來的收益。這類框架一般依然是以小程序原生語法為主,只是在邏輯層引入了增強(qiáng)語法來優(yōu)化應(yīng)用性能或者提供更便捷的使用方法,
以騰訊開源的 omix 框架為例,先簡單看一下它的用法:
邏輯層
create.Page(store, {
// 聲明依賴
use: ['logs'],
computed: {
logsLength() {
return this.logs.length
}
},
onLoad: function () {
//響應(yīng)式,自動更新視圖
this.store.data.logs = (wx.getStorageSync('logs') || []).map(log => {
return util.formatTime(new Date(log))
})
setTimeout(() => {
//響應(yīng)式,自動更新視圖
this.store.data.logs[0] = 'Changed!'
}, 1000)
}
})
復(fù)制代碼
視圖層
<view class="container log-list">
<block wx:for="{{logs}}" wx:for-item="log">
<text class="log-item">{{index + 1}}. {{log}}</text>
</block>
</view>
復(fù)制代碼
先不談它的語法是否符合直覺或者好用。簡單來說,它整體 保留小程序已有的語法 。但是在此基礎(chǔ)之上,對它進(jìn)行了擴(kuò)充和增強(qiáng),比如引入了 Vue 中比較有代表性的 computed
,比如能夠直接通過 this.store.data.logs[0] = 'Changed'
修改狀態(tài)??梢哉f是在小程序原生半 Vue 半 React 的語法(此處 半 只是數(shù)量詞)背景下,徹底將其 Vue 化的一種方案。
使用增強(qiáng)型框架最大的好處是,你可以在只引入極少依賴,并且保留對小程序認(rèn)知的情況下,用更加 舒爽 的語法來寫代碼。這類框架對于目標(biāo)只投放到特定平臺小程序的開發(fā)者或者非專業(yè)前端而言是比較好的選擇之一。因為你只需要關(guān)注很少的新增文檔和小程序自身的文檔就足夠了。畢竟在推動某項技術(shù)的過程中,團(tuán)隊的學(xué)習(xí)成本也是需要考慮的。
轉(zhuǎn)換類框架
相比于漸進(jìn)增強(qiáng)型框架,轉(zhuǎn)換類框架的使命是完全不同的。轉(zhuǎn)換類框架的使命是讓開發(fā)者 幾乎不用感受 小程序原生語法,更大程度對接前端已有生態(tài),并且可以實現(xiàn)**「一碼多端」 的業(yè)務(wù)訴求,只是最后的 構(gòu)建產(chǎn)物**為小程序代碼。隨著這幾年的發(fā)展,轉(zhuǎn)換類框架大的方面分為兩種 -- 編譯時/運行時。下文會分別針對兩種方案進(jìn)行分析。
Rax 編譯時/Taro 2.0
顧名思義,編譯時方案的核心是通過編譯分析的方式,將開發(fā)者寫的代碼轉(zhuǎn)換成小程序原生語法。這里以 Rax 編譯時和 Taro 2.0 為例,面向開發(fā)者的語法是類 React 語法,開發(fā)者通過寫有一定語法限制的 React 代碼,最后轉(zhuǎn)換產(chǎn)物 1:1 轉(zhuǎn)換成對應(yīng)的小程序代碼。
以一段簡單的代碼為例:
Rax:
import { createElement, useEffect, useState } from 'rax';
import View from 'rax-view';
export default function Home() {
const [name, setName] = useState('world');
useEffect(() => {
console.log('Here is effect.');
}, [])
return <View>Hello {name}</View>;
}
復(fù)制代碼
轉(zhuǎn)換之后的小程序代碼:
邏輯層
import { __create_component__, useEffect, useState } from 'jsx2mp-runtime/dist/ali.esm.js'
function Home() {
const [name, setName] = useState('world');
useEffect(() => {
console.log('Here is effect.');
}, []);
this._updateData({
_d0: name
});
}
Component(__create_component__(Home));
復(fù)制代碼
視圖層
<block a:if="{{$ready}}">
<view class="__rax-view">{{_d0}}</view>
</block>
復(fù)制代碼
編譯時方案最大的特點就是,開發(fā)者雖然寫的是類 React 語法,但是轉(zhuǎn)換后的代碼和漸進(jìn)增強(qiáng)型框架非常類似。開發(fā)者可以比較清晰的看出編譯前后代碼的 對應(yīng)關(guān)系 。
簡單來說,編譯時方案會通過 AST 分析,將開發(fā)者寫的 JSX 中 return
的模板部分構(gòu)建到視圖層,剩余部分代碼保留,然后通過運行時墊片模擬 React 接口的表現(xiàn)。
以一個簡單的 return <View>Hello world</View>
為例,如果想要提取到 <View>Hello world</View>
,你可以寫這段解析代碼:
// 省略定義 babel parser 和包裝 traverse 的部分
const code = fs.readFileSync(FILE_PATH);
const ast = parser(code);
traverse(ast, {
ReturnStatement(path) {
const targetNodePath = path.get('argument');
if (targetNodePath.isJSXElement()) {
// 如果 return 的子元素是一個 JSX Element 就收集 or 處理一下
}
}
})
復(fù)制代碼
targetNodePath
就是 <View>Hello world</View>
的節(jié)點路徑,關(guān)于 AST 相關(guān)的文章可以自行搜索一下,babel 的 handle book 已經(jīng)比較詳細(xì)了,再加上這個 輔助網(wǎng)站 基本是沒有什么門檻的。
但是這個方案其實是存在明顯的優(yōu)勢和劣勢的。
優(yōu)勢
- 運行時性能損耗低
- 目標(biāo)代碼明確,開發(fā)者所寫即所得
- 運行時、編譯時優(yōu)化
在這個方案中,你可以輕易的做到和漸進(jìn)增強(qiáng)型框架一樣的效果,即給予開發(fā)者 更多的語法支持 以及 默認(rèn)的性能優(yōu)化處理 ,比如避免多次 setData
,亦或是長列表優(yōu)化等等。
劣勢
- 語法限制高
由于需要完全命中開發(fā)者在模板部分所用到的所有語法,這就對編譯時框架的實現(xiàn)者有相當(dāng)高的要求。因為大部分前端開發(fā)者們其實已經(jīng)對靈活的語法有一定的依賴性,比如會使用高階組件,比如在條件判斷的時候?qū)懞芏?nbsp;return
等等。進(jìn)一步的,由于是 1:1 編譯轉(zhuǎn)換,開發(fā)者在開發(fā)的時候還是不得不去遵循小程序的開發(fā)規(guī)范,比如一個文件中定義只能定義一個組件之類的。
目前在阿里巴巴集團(tuán)內(nèi)部,Rax 的這套編譯時方案 已經(jīng)落地了很多業(yè)務(wù) ,包括「電影演出」小程序等,從開發(fā)者的實踐來看,如果能夠掌握編譯時開發(fā)的技巧,即保證最終 return
的模板的簡潔性,語法限制其實還是在可以接受的范圍內(nèi)的。
Rax 運行時/Remax/Taro Next
運行時方案相比于上面的編譯時方案,最大的優(yōu)勢是可以 幾乎沒有任何語法約束 的去完成代碼編寫。這對于開發(fā)者而言,無疑是最大的吸引力,高階組件用起來! createProtal
用起來!但是在小程序領(lǐng)域上暫時還不可能存在這么好的事情,這也是小程序原生語法最后的 執(zhí)拗 。沒有語法限制帶來的更多的性能上的犧牲,這個與運行時方案的實現(xiàn)方式有很大的關(guān)系,接下來我詳細(xì)介紹一下。
從渲染的角度來看,這套方案更貼近于 富文本 渲染。邏輯層將一個和節(jié)點渲染信息相關(guān)的 組件樹 傳遞給視圖層,視圖層通過節(jié)點類型判斷然后進(jìn)行視圖渲染。下面這個圖簡要的描述了一下整個過程:
雖然只用了 維護(hù) 兩個字,但是邏輯層做的事情其實比較復(fù)雜。首先要做的是,去處理節(jié)點間的關(guān)系,去模擬 appendChild
/ removeChild
/ updateNode
等各個行為來操作 VDOM 樹。其次比較重要的是去模擬事件,在邏輯層每一個節(jié)點類會繼承自 EventTarget
基類,這個和 W3C 是一樣的,然后通過 nodeId
作為標(biāo)識去收集需要監(jiān)聽的事件,當(dāng)視圖層通過 action 觸發(fā)了某個節(jié)點的事件之后,再通過原生小程序事件中的 event.currentTarget.dataset.nodeId
獲取到目標(biāo)節(jié)點的 id,最終觸發(fā)目標(biāo)回調(diào)。
由于本文篇幅問題,不會更加詳細(xì)的介紹其中的各個部分更加具體的實現(xiàn),感興趣的同學(xué)可以通過 Rax 的源碼或者 npm init rax demo
起一個項目通過最終的產(chǎn)物來研究整個原理。
在目前這個階段,即使是運行時方案,也有不同的實現(xiàn)思路。以 Kbone (Rax 運行時方案是從 Kbone 改造而來) 和 Taro Next 都是通過模擬 Web 環(huán)境來徹底對接前端生態(tài),而 Remax 只是簡單的通過 react reconciler 連接 React 和小程序。
從業(yè)務(wù)訴求來看,筆者認(rèn)為,Rax 和 Taro Next 可能會比 Remax 更加開放。首先,需要考慮是三部分的訴求,(1)毫無語法限制,既然已經(jīng)沒有了語法限制,為什么不能用前端更加熟悉的方式來開發(fā),即擁有操作 DOM 的權(quán)利;(2)不和 DSL 耦合,盡管在阿里巴巴集團(tuán)內(nèi),對 React 的認(rèn)可度更高,但是從實現(xiàn)原理上來看,和某個框架進(jìn)行強(qiáng)綁定一定不是最優(yōu)解;(3)舊有的 Web 業(yè)務(wù)遷移,今天我們所面對的開發(fā)者,很多都是因為業(yè)務(wù)壓力或者其他情況需要將原有的 Web 頁面遷移到小程序上,那么用模擬 Web 環(huán)境這套方案是最好不過了,根據(jù)我們的測試,大部分業(yè)務(wù)幾乎可以無縫遷移過來。
害!說了這么多漂亮話,運行時方案 真的很香 ,但這 并不是救世主 ,我來說說它的劣勢。**劣勢 1:**數(shù)據(jù)傳輸量大,我們需要將完整的組件樹在邏輯層傳輸?shù)揭晥D層;**劣勢 2:**頁面上存在大量的監(jiān)聽器,每一個組件都需要無時無刻監(jiān)聽所有的事件,在事件不斷觸發(fā)的過程中,通過 nodeId
篩選出真正需要觸發(fā)的事件;**劣勢 3:**模板遞歸渲染,如果使用原生語法,原生框架可以在渲染前就知道頁面大概的結(jié)構(gòu),來對渲染進(jìn)行優(yōu)化,但是如果僅僅只是通過類似 <view a:if="{{node.tagName === 'view'}}"></view>
這樣的信息,是很難判斷頁面的真實結(jié)構(gòu)的。
組合
魚和熊掌雖然不能兼得,但是可以各要一半~再次強(qiáng)調(diào),本文 不是廣告文 。如果編譯時和運行時方案共存呢?基于淘系前端 高度現(xiàn)代的工程化 積累,開發(fā)者已經(jīng)習(xí)慣通過區(qū)塊來組建項目。更得益于,Rax 在編譯時和運行時方案都有所積累,我們希望能夠?qū)⑦\行時方案和編譯時方案組合使用。對于基礎(chǔ)復(fù)雜或者對于性能有要求的模塊通過編譯時實現(xiàn)。然后再通過 npm 包的形式,引入到運行時的項目中去,從而有效降低了運行時方案的性能損耗,并且能保證絕大部分的業(yè)務(wù)場景可以用 無限制 的語法完成,而開發(fā)者所面對的都是 Rax DSL。
用一個 Demo 來看下:
// 這是一個倒計時組件,通過編譯時實現(xiàn),然后發(fā)布為 rax-taobao-countdown
import { createElement } from 'rax';
import View from 'rax-view';
function CountDown(props) {
// 省略各種邏輯...
return <View>{day}:{hours}:{minutes}:{seconds}</View>
}
export default CountDown;
復(fù)制代碼
// 運行時項目
import { createElement } from 'rax';
import CountDown from 'rax-taobao-countdown';
function Home() {
return <CountDown now={Date.now()} />
}
復(fù)制代碼
假設(shè),我們這個倒計時組件結(jié)構(gòu)非常復(fù)雜,并且要求極高的交互性。那么,開發(fā)者可以通過編譯時方案開發(fā)一個高性能 CountDown
組件,然后在運行時項目中引入使用。此時,視圖層所得到的節(jié)點樹信息大致如下:
{
"tagName": "custom-component",
"type": "element",
"behavior": "CountDown",
"children": []
}
復(fù)制代碼
而不會有更多更深層結(jié)構(gòu)的節(jié)點信息,有效避免剛剛說的運行時方案中存在的劣勢。
Web 才是未來
小程序原生語法 絕對不是 小程序 or 下一代的渲染方案。通過微信小程序現(xiàn)有的語法規(guī)范來對開發(fā)者進(jìn)行 綁架 ,只會讓更多的人想突破圍城。微信小程序似乎已經(jīng)意識到了這一點,從目前的迭代來看,微信小程序引入了越來越多 Web 已有的東西,包括通過 wxs
在視圖層就可以一定程度上操作 DOM,甚至獲取到邏輯層組件實例等等,這個可以給現(xiàn)有的轉(zhuǎn)換類框架提供更多的可能性。但是,如果小程序如果一開始設(shè)計的不這么糟糕呢,我們可能會失業(yè)(開個玩笑)?
對于業(yè)務(wù)的開發(fā)者而言,「一碼多端」才是效率最大化的。今天的業(yè)務(wù)需求可能只是投放到小程序容器,明天的需求可能就是投放到 Web,未來甚至 是 Flutter。Web 是最貼近前端開發(fā)者的,有組織保障(W3C)的規(guī)范。所以,站在 2020 年這個時間點,無論是框架提供者,還是業(yè)務(wù)開發(fā)者都應(yīng)該更多的從標(biāo)準(zhǔn)的角度思考問題,這樣才能讓業(yè)務(wù)代碼有更多的可能性。
總結(jié)
距離小程序誕生已經(jīng)過去很多年,2020 年應(yīng)該如何選擇業(yè)務(wù)合適的小程序框架,這個需要開發(fā)者衡量利弊之后再做出選擇。因為每個業(yè)務(wù)的形式不同,應(yīng)用的存活時間也不相同,根據(jù)自己的需要選擇可能才是最好的,本文只是從一個全局的視角對所有類型的框架進(jìn)行分析,希望能夠讓正在看文章的你,不那么糾結(jié)~
相關(guān)案例查看更多
相關(guān)閱讀
- 云南網(wǎng)站建設(shè) 網(wǎng)絡(luò)服務(wù)
- 網(wǎng)站建設(shè)需要多少錢
- 二叉樹
- 云南小程序開發(fā)報價
- 云南小程序代建
- 企業(yè)網(wǎng)站
- 云南網(wǎng)站建設(shè)特性
- 網(wǎng)站建設(shè)高手
- 百度小程序開發(fā)公司
- 制作一個小程序
- 前端技術(shù)
- 云南網(wǎng)站建設(shè)電話
- 安家微信小程序
- 汽車報廢回收管理軟件
- 保山小程序開發(fā)
- 網(wǎng)站建設(shè)特性
- 云南手機(jī)網(wǎng)站建設(shè)
- web前端
- 怎么做網(wǎng)站
- web學(xué)習(xí)路線
- 小程序開發(fā)排名前十名
- 微信分銷
- 云南小程序開發(fā)首選品牌
- 網(wǎng)頁制作
- 網(wǎng)絡(luò)公司排名
- 汽車報廢軟件
- 云南網(wǎng)站建設(shè)費用
- Web開發(fā)框架
- web教程
- 百度人工排名