日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Rax,完美融合編譯時(shí)與運(yùn)行時(shí)的雙引擎小程序框架

 西北望msm66g9f 2020-05-06

作者:阿里巴巴淘系前端工程師 弗申 逆葵

Rax Github Repo——https://github.com/alibaba/rax[1]

Rax 小程序官網(wǎng)——https://rax./miniapp[2]

經(jīng)過持續(xù)的迭代,Rax 小程序迎來了一個(gè)大的升級(jí),支持全新的運(yùn)行時(shí)方案。站在 2020 年初這個(gè)時(shí)間點(diǎn),我們想從 Rax 小程序的特點(diǎn)出發(fā),進(jìn)行一次全面的梳理與總結(jié),并且在文末附上了 Rax 與當(dāng)前主流的小程序開發(fā)框架的對(duì)比。本文將從 API 設(shè)計(jì)與性能、雙引擎架構(gòu)、優(yōu)秀的多端組件協(xié)議設(shè)計(jì)基于 webpack 的工程架構(gòu)四個(gè)方向展開。

一、API 設(shè)計(jì)與性能

當(dāng)決定一個(gè)產(chǎn)品的技術(shù)選型的時(shí)候,我們往往會(huì)從幾個(gè)方面考慮,1)可用生態(tài),即周邊相關(guān)的工具是否滿足產(chǎn)品開發(fā)的條件;(2)風(fēng)險(xiǎn)率,即出現(xiàn)問題是否能夠快速定位解決,所使用的技術(shù)是否會(huì)持續(xù)維護(hù);(3)上手成本,即需不需要很大代價(jià)才能達(dá)到能夠使用的階段;(4)性能,即能夠滿足產(chǎn)品既定的性能標(biāo)準(zhǔn)以及用戶體驗(yàn)。

本節(jié)主要會(huì)介紹 Rax 小程序在后面兩點(diǎn)上的優(yōu)勢。

API 設(shè)計(jì)

框架整體的上手成本是比較小的,Rax 小程序鏈路從框架上是繼承自 Rax(構(gòu)建多端應(yīng)用的漸進(jìn)式類 React 框架)。所以只要你會(huì) Rax Web/Weex 開發(fā)或者 React,那么你就會(huì)用 Rax 開發(fā)小程序,并且可以同時(shí)投放到 Rax 所支持的其它端。

但是由于小程序端的特殊性,總會(huì)存在無法抹平以及需要單獨(dú)處理的地方。得益于 Rax 已經(jīng)做了比較久的多端方案,我們認(rèn)為,每個(gè)端獨(dú)立的屬性不應(yīng)該入侵基礎(chǔ)框架本身,保證基礎(chǔ)框架的純凈有利于做更多的擴(kuò)展。

以下面的代碼為例:

Taro:

import Taro, { Component } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'

export default class Index extends Component {
config = {
navigationBarTitleText: '首頁'
}

componentWillMount () { }

componentDidMount () { }

componentWillUnmount () { }

componentDidShow () { }

componentDidHide () { }

render () {
return (
<View>
<Text>1</Text>
</View>

)
}
}

Rax

import { createElement, Component } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import { isMiniApp } from 'universal-api';
import { registerNativeListeners, addNativeEventListener, removeNativeEventListener } from 'rax-app';

function handlePageShow() {}

class Index extends Component {
componentWillMount () { }

componentDidMount () {
if (isMiniApp) {
addNativeEventListener('onShow', handlePageShow);
}
}

componentWillUnmount () {
if (isMiniApp) {
removeNativeEventListener('onShow', handlePageShow);
}
}

render () {
return (
<View>
<Text>1</Text>
</View>

)
}
}

if (isMiniApp) {
registerNativeListeners(Index, ['onShow']);
}

export default Index;

在和 Taro 的對(duì)比中,可以看出主要是兩點(diǎn)差異:(1)Rax 沒有 componentDidShow componentDidHide 的概念,新增了和 W3C 標(biāo)準(zhǔn)類似的 addNativeEventLisenter removeEventListener 等 API;(2)組件實(shí)例上沒有一個(gè)叫做 config 的靜態(tài)屬性用來設(shè)置頁面的 title 等配置。

這就是前文所說的不入侵基礎(chǔ)框架本身,React 本身其實(shí)是沒有 componentDidShow 這些概念,因?yàn)檫@和組件本身的生命周期其實(shí)是無關(guān)的。我們更期望引導(dǎo)用戶用標(biāo)準(zhǔn)的 API 來寫業(yè)務(wù)代碼。同時(shí),這種寫法的設(shè)計(jì)帶來的還有性能相關(guān)的提升,后文會(huì)具體說明。

當(dāng)然這種設(shè)計(jì)本身會(huì)導(dǎo)致代碼量一定的膨脹,但是通過工程上的手段,是可以保證最后產(chǎn)物代碼的體積幾乎毫無差異。

性能

小程序的性能問題是在業(yè)務(wù)開發(fā)中經(jīng)常會(huì)遇到的,為此 Rax 小程序現(xiàn)有的編譯時(shí)方案也做了很多的努力。通過阿里小程序真機(jī)云測的功能,我們對(duì)一個(gè)無限下拉的列表做了測試。

頁面結(jié)構(gòu)如下:

根據(jù)真機(jī)測試報(bào)告,原生小程序三次平均是 2008 ms,Taro 是 2003ms,Rax 是 1924ms,當(dāng)然其實(shí)相差并不多,但是實(shí)際的業(yè)務(wù)場景其實(shí)遠(yuǎn)比上面的頁面結(jié)構(gòu)更加復(fù)雜。

與 Taro 類似的,Rax 小程序側(cè)的基礎(chǔ)框架沒有在邏輯層弄一個(gè) VDOM,而是通過數(shù)據(jù)合并、傳統(tǒng)的數(shù)據(jù) diff,來避免用戶更新冗余的數(shù)據(jù)。更多的是,阿里小程序原生提供了私有方法 $spliceData來進(jìn)行性能優(yōu)化,Rax 底層會(huì)去識(shí)別用戶需要更新的值是否是數(shù)組,然后自動(dòng)根據(jù)場景使用 $spliceData 來優(yōu)化渲染。

另外需要提到的是,前面說的原生事件監(jiān)聽,小程序本身需要預(yù)先注冊(cè)才能監(jiān)聽事件(這也是為了保障性能),即需要:

Page({
onShow() {}
});

而不能動(dòng)態(tài)注冊(cè):

const config = {}
Page(config);
setTimeout(() => {
config.onShow = () => {};
}, 1000);

所以加入 componentDidShow 這類概念真的不是好的做法,這會(huì)導(dǎo)致頁面由于不知道是否需要注冊(cè) onShow 屬性而將所有的原生事件全部注冊(cè)監(jiān)聽,這不僅會(huì)造成開發(fā)者不能靈活擴(kuò)展,更會(huì)導(dǎo)致內(nèi)存泄漏的風(fēng)險(xiǎn)。

于是 Rax 小程序引入了 registerNativeListeners ,只給開發(fā)者一種新的認(rèn)知,就是需要先在頁面上注冊(cè)事件才能進(jìn)行監(jiān)聽。這樣不僅解決了擴(kuò)展性的問題,還解決了潛在的性能問題。

當(dāng)然,Rax 小程序能做的性能優(yōu)化到此為止了么?在可計(jì)劃的未來,Rax 小程序編譯時(shí)方案已經(jīng)有一些明確的 action,比如進(jìn)一步減輕框架對(duì) props 更新的管理,更多的利用小程序原生的能力來實(shí)現(xiàn)組件更新,從而避免和小程序基礎(chǔ)框架做重復(fù)的事情導(dǎo)致性能損耗。

二、雙引擎架構(gòu)

Rax (可能)是業(yè)界首個(gè)同時(shí)支持編譯時(shí)和運(yùn)行時(shí)方案的小程序解決方案。兩種方案之間的切換無比簡單,我們將高性能 or 完整語法的選擇權(quán)真正地交給了用戶。雙引擎驅(qū)動(dòng)的 Rax 小程序架構(gòu)如下:下面我們將分別介紹兩種編譯方案。

編譯時(shí)方案

Rax 小程序編譯時(shí)方案是基于 AST 轉(zhuǎn)譯的前提下,將 Rax 代碼通過詞法、語法分析轉(zhuǎn)譯成小程序原生代碼的過程。由于 JavaScript 的動(dòng)態(tài)能力以及 JSX 本身不是一個(gè)傳統(tǒng)模板類型語法,所以在這個(gè)方案中引入一個(gè)較為輕量的運(yùn)行時(shí)墊片。

Rax 小程序編譯時(shí)架構(gòu)的核心主要分為兩個(gè)部分,AST 轉(zhuǎn)譯運(yùn)行時(shí)墊片。下文會(huì)針對(duì)這兩個(gè)部分做簡要的介紹。

AST 轉(zhuǎn)譯

AST 轉(zhuǎn)譯部分的架構(gòu)相比同類產(chǎn)品 Taro 來說,更加清晰以及可維護(hù)性更強(qiáng)。這里不得不提到,它的分語法場景轉(zhuǎn)譯以及洋蔥模型。我們可以粗略的看一下,分語法場景轉(zhuǎn)譯部分的代碼結(jié)構(gòu):

可以比較清晰的看到,針對(duì)需要轉(zhuǎn)譯的每一個(gè)語法場景都有一個(gè)模塊專門負(fù)責(zé)轉(zhuǎn)譯,這就讓整個(gè)轉(zhuǎn)譯的過程輕松了起來,只要每一部分的轉(zhuǎn)譯結(jié)果符合預(yù)期,那么轉(zhuǎn)譯結(jié)果就是符合預(yù)期的。這樣的設(shè)計(jì)可以讓我們能夠充分利用單元測試來對(duì)轉(zhuǎn)譯前后的代碼進(jìn)行比較。

而洋蔥模型的設(shè)計(jì)則是AST 轉(zhuǎn)譯的另一個(gè)主要設(shè)計(jì),整個(gè)轉(zhuǎn)譯過程實(shí)際上分為 4 個(gè)步驟:

洋蔥模型主要進(jìn)行的是后面三步,在 parser 層將原有的 AST 樹修改為符合預(yù)期的新 AST 樹,然后在 generate 層將新的 AST 樹轉(zhuǎn)譯成小程序代碼。

運(yùn)行時(shí)墊片

由于 JSX 的動(dòng)態(tài)能力以及 Rax 原本提供的一些例如 hooks 之類的特性。所以,Rax 小程序編譯時(shí)方案提供了一個(gè)運(yùn)行時(shí)墊片,用來對(duì)齊模擬 Rax core API 。

既然引入了運(yùn)行時(shí),自然可以基于這套機(jī)制對(duì)數(shù)據(jù)流做更多的管理,以及提供 Rax 工程在其他端上的 API,比如路由相關(guān)的 history location 等。

運(yùn)行時(shí)方案

Rax 小程序的運(yùn)行時(shí)方案沒有自研,而是『站在了巨人的肩膀上』,復(fù)用了 kbone[3] 的架構(gòu)并對(duì)其作了一定程度的改造以接入 Rax 小程序的工程體系。關(guān)于運(yùn)行時(shí)方案的實(shí)現(xiàn)原理可以點(diǎn)擊這里[4]查看,此處不再詳細(xì)介紹。首先需要介紹的是 Rax 小程序同時(shí)也是 kbone 的優(yōu)點(diǎn):

  1. 支持更為完整的前端框架特性。相比較 Rax 編譯時(shí)方案,現(xiàn)在你可以使用完整的 Rax 語法,并且 Rax 所有的特性都已經(jīng)支持。忘記那些條條框框的語法約束吧;
  2. 可高度復(fù)用 Web 端邏輯。如果用戶已有 Web 端的 Rax 程序代碼,可能只需稍作修改,就能將整個(gè)應(yīng)用完整移植到小程序端,大大提升了開發(fā)效率;
  3. 小程序端運(yùn)行時(shí),仍然可以使用小程序本身的特性,比如小程序內(nèi)置組件等。

而在 kbone 的基礎(chǔ)上,Rax 小程序運(yùn)行時(shí)方案還新增了不少特性,概括起來有以下幾點(diǎn):

  1. 支持支付寶小程序。由于 kbone 的定位,其只支持微信小程序。Rax 基于 kbone,結(jié)合支付寶小程序的特點(diǎn),拓展了對(duì)支付寶小程序的支持?,F(xiàn)在,想在開發(fā)支付寶小程序時(shí)使用運(yùn)行時(shí)方案,不僅可以使用 Remax,你還有 Rax 可以選擇;
  2. 接入完整的 Rax 工程體系?,F(xiàn)在,你可以在使用運(yùn)行時(shí)方案時(shí)感受到 Rax 工程的所有特點(diǎn),比如 Rax 多端 API、多端組件、多端構(gòu)建器等,享受完整一致的體驗(yàn);

最后,我們也不能回避的是,Rax 小程序運(yùn)行時(shí)方案具有所有運(yùn)行時(shí)方案都存在的問題:性能損耗。事實(shí)上,運(yùn)行時(shí)方案就是以一定的性能損耗來換取更為全面的 Web 端特性支持。所以,如果你對(duì)小程序有一定的性能要求,建議使用編譯時(shí)方案;如果對(duì)性能要求不高,那么運(yùn)行時(shí)方案就是助你快速開發(fā)小程序的利器。雙引擎驅(qū)動(dòng)的 Rax 小程序,總有一處能夠擊中你的內(nèi)心。

三、優(yōu)秀的多端組件協(xié)議設(shè)計(jì)

Rax 小程序編譯時(shí)方案支持項(xiàng)目級(jí)開發(fā)和組件級(jí)開發(fā)。與 Taro 將組件統(tǒng)一在項(xiàng)目中進(jìn)行編譯產(chǎn)出為小程序代碼不同,Rax 在組件工程中即可構(gòu)建出小程序組件。結(jié)合一套優(yōu)秀的多端組件協(xié)議設(shè)計(jì),我們做到了在 Rax 小程序項(xiàng)目和原生小程序項(xiàng)目中都能正常使用 Rax 小程序組件,同時(shí)保持統(tǒng)一的多端開發(fā)體驗(yàn)。該協(xié)議定義在 package.json 中的 miniappConfig 字段中,其具體用法設(shè)計(jì)可以參見文檔 Rax 小程序——多端組件開發(fā)[5]。

支持漸進(jìn)式接入 Rax

對(duì)于那些已經(jīng)使用原生語法開發(fā)了完整的小程序的開發(fā)者來說,一個(gè)很合理的需求就是漸進(jìn)地切換到 Rax 開發(fā)鏈路上來,畢竟整個(gè)項(xiàng)目遷移可能成本高昂。而 Rax 依托多端組件協(xié)議,能夠幫助開發(fā)者平滑過渡。

按照設(shè)計(jì),Rax 小程序組件工程的構(gòu)建產(chǎn)物為符合小程序語法的組件,因此其理所當(dāng)然可以直接在原生小程序項(xiàng)目中使用。這意味著,如果你想漸進(jìn)式地使用 Rax 來開發(fā)小程序,可以以組件或者頁面為單位將之前使用原生語法開發(fā)的小程序逐漸地遷移到 Rax 上來。而這,也是 Taro 等其他框架不具備的能力。在 Rax 的使用方中,浙江省網(wǎng)上政務(wù)平臺(tái)『浙里辦』支付寶小程序即采用了漸進(jìn)式接入 Rax 的方式。

多端統(tǒng)一的組件使用體驗(yàn)

當(dāng)使用 Rax 組件工程發(fā)布的小程序組件在 Rax 項(xiàng)目中使用時(shí),構(gòu)建器會(huì)自動(dòng)通過 miniappConfig 規(guī)定的路徑去尋找該組件的小程序?qū)崿F(xiàn)從而實(shí)現(xiàn)替換。用戶在業(yè)務(wù)代碼編寫層面無需像傳統(tǒng)引入原生小程序組件的方式一樣寫具體路徑,而是與 Web/Weex 端保持一致即可,示例如下:

// Wrong
import CustomComponent from 'custom-component/miniapp/index'

// Correct
import CustomComponent from 'custom-component'

除此之外,多端組件協(xié)議還可以擴(kuò)展成多端組件庫協(xié)議,支持更靈活的類似 import { Button } from 'fusion-mobile' 的寫法。以 Rax 多端組件協(xié)議為基礎(chǔ),你可以快速為你的多端項(xiàng)目開發(fā)通用組件或者組件庫。比如,Rax 基礎(chǔ)組件[6]就都是以該方式開發(fā)的。

四、基于 webpack 的工程架構(gòu)

Rax 工程以阿里巴巴集團(tuán)前端統(tǒng)一的 CLI 工具 @alib/build-script[7] 為基礎(chǔ),其依賴 webpack,通過插件體系支持各個(gè)場景,同時(shí)基于 webpack-chain 提供了靈活的 webpack 配置能力,用戶可以通過組合各種插件實(shí)現(xiàn)工程需求。Rax 小程序的編譯時(shí)方案通過 webpack loader 來處理自身邏輯。以 app/page/component 等文件角色分類的 webpack loader 會(huì)調(diào)用 jsx-compiler 進(jìn)行代碼的 AST 分析及處理,再將處理完的代碼交由 loader 生成對(duì)應(yīng)的小程序文件;運(yùn)行時(shí)方案直接復(fù)用 Web 端的編譯配置,再通過額外的 webpack 插件生成具體的小程序代碼。

相比其他自研的工程體系,整套架構(gòu)具有如下優(yōu)點(diǎn):

  • 基于 webpack,靈活且可擴(kuò)展型強(qiáng)
  • 插件體系,可復(fù)用性強(qiáng)
  • 命令簡潔,體驗(yàn)統(tǒng)一

總結(jié)

最后,附上 Rax 和現(xiàn)有主流小程序框架的對(duì)比。以上是我們對(duì) Rax 小程序的核心競爭力的階段性總結(jié)與思考。小程序已經(jīng)不是初生牛犢,小程序的解決方案也早已汗牛充棟,但我們相信,Rax 的入局,會(huì)讓你的小程序開發(fā)有那么一些不一樣。

更多關(guān)于 Rax 小程序的內(nèi)容,歡迎訪問 https://rax./miniapp 了解!

參考資料

[1]

https://github.com/alibaba/rax: https://link.zhihu.com/?target=https%3A//github.com/alibaba/rax

[2]

https://rax./miniapp: https://link.zhihu.com/?target=https%3A//rax./miniapp

[3]

kbone: https://github.com/wechat-miniprogram/kbone

[4]

這里: https://wechat-miniprogram./kbone/docs/guide/principle.html

[5]

Rax 小程序——多端組件開發(fā): https://rax./docs/guide/multiple-ends-component-development

[6]

Rax 基礎(chǔ)組件: https://rax./docs/components/introduce

[7]

@alib/build-script: https://www./package/@alib/build-scripts

關(guān)注我們

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多