0x1 讀完后希望你會(huì)
- 了解Weex中,we腳本的各個(gè)標(biāo)簽<template><script><style>解析實(shí)現(xiàn)方式玉转,如何生成可以運(yùn)行的js腳本文件。
- 基于標(biāo)簽tag,自己實(shí)現(xiàn)一套你喜歡的類(lèi)似we或者微信小程序的腳本語(yǔ)言熄阻。
- 可以包含表達(dá)式計(jì)算
- 流程控制
0x2 背景
目前線上App接入的weex版本為0.8.X,距目前最新的0.10.X系列跨度相差較大倔约,但是在保證目前業(yè)務(wù)穩(wěn)定的前提下秃殉,不能直接升級(jí)Weex SDK到最新版。
在升級(jí)前期浸剩,不得不面對(duì)的幾個(gè)問(wèn)題:
- 目前已開(kāi)發(fā)的大量.we頁(yè)面是否可以在新版Weex運(yùn)行钾军。
- 繼續(xù)使用已被廢棄的we腳本開(kāi)發(fā)新需求(Weex已經(jīng)推薦用vue來(lái)寫(xiě)頁(yè)面)
- Vue與Weex兩大生態(tài)的聯(lián)手,Weex官方也在推進(jìn)vue來(lái)編寫(xiě)界面.
- we腳本將來(lái)很有可能面臨不再被擴(kuò)展維護(hù)乒省,也就是weex很多的新特性在we中不一定會(huì)被支持,除非we與vue的feature更新節(jié)奏保持一致畦木。
- 據(jù)說(shuō)手淘與貓客已不再使用we編寫(xiě)weex袖扛,而是全部采用vue(求證)。
- Vue自身生態(tài)龐大十籍,對(duì)vue更好的支持蛆封,反而更利于weex的推廣。
所以在升級(jí)之前勾栗,以weex的transform流程原理為開(kāi)端惨篱,展開(kāi)一些前期的調(diào)研工作,順便學(xué)習(xí)一下weex的toolkit實(shí)現(xiàn)原理围俘。
據(jù)weex的同學(xué)說(shuō)新版的weex是可以跑老we的砸讳,不過(guò)要保證we腳本代碼的嚴(yán)謹(jǐn)性,因?yàn)樾掳娴膉sf runtime校驗(yàn)機(jī)制界牡,更加嚴(yán)格簿寂,某些頁(yè)面可能白屏(What?K尥觥3K臁)。
老話常談挽荠,“Talk is cheap,Show me the code”克胳。
0x3 驗(yàn)證思路
一個(gè)we頁(yè)面被渲染執(zhí)行平绩,可以大致拆分為兩部分。
【.we腳本的打包與編譯】(weex/vue loader漠另,生成標(biāo)準(zhǔn)的js腳本)
[.we] -> [build] -> output [*.js]
【W(wǎng)eex JS 運(yùn)行時(shí)環(huán)境(JSF)】(負(fù)責(zé)解析運(yùn)行編譯好的js腳本)
[*.js] -> [weex runtime] -> render [view:page]
從圖中可以看出 Weex 整體的工作流程捏雌。
首先開(kāi)發(fā)者編寫(xiě) .we 文件。
通過(guò) weex-toolkit 提供的工具將 .we 文件轉(zhuǎn)為js酗钞。
JS Framework 接收并執(zhí)行 js 的代碼腹忽,執(zhí)行數(shù)據(jù)綁定、模板編譯等操作砚作,然后輸出 json 格式的 Virtual DOM 傳遞給移動(dòng)端窘奏。
這篇文章主要分析第一層的transformer的實(shí)現(xiàn)原理。
0x4 we/vue 腳本是如何被解析的
不可不說(shuō)的parse5:
weex-loader中葫录,對(duì)we文件的解析主要依賴第三方開(kāi)源npm組件着裹,html標(biāo)簽解析的parse5,對(duì)輸入的html標(biāo)簽類(lèi)文本,解析后輸出json對(duì)象米同。
關(guān)于輸出的json格式骇扇,可以參考官方的在線playground,http://astexplorer.net/#/1CHlCXc4n4
weex-loader首先通過(guò)parse5 得到we文本的json 結(jié)構(gòu)的樹(shù)結(jié)構(gòu)面粮,
然后Weex-loader的處理流程中少孝,針對(duì)不同標(biāo)簽(<template/> <script/><style/>),分別有對(duì)應(yīng)的解析處理模塊,
大致流程如上圖,從左向右依次為:
1.輸入為原始we腳本文件熬苍。
2.通過(guò)parse5組件解析出對(duì)應(yīng)的jsonobject
3.根據(jù)json object中描述的各部分tag交給對(duì)應(yīng)的處理模塊稍走。
例如一個(gè)template標(biāo)簽的json對(duì)象,在loader中是這樣被處理的柴底,
源碼地址: weex-loader/lib/loader.js
不同的標(biāo)簽類(lèi)型文本會(huì)分配給專(zhuān)門(mén)的parse組件.
源碼地址:weex-loader/lib/parser.js
標(biāo)簽對(duì)應(yīng)的處理模塊如下:
<script> 標(biāo)簽 ————> weex-templater
<style > 標(biāo)簽 ————> weex-styler
<script> 標(biāo)簽 ————> weex-scripter
0x5 weex-styler 簡(jiǎn)介以及CSS預(yù)備知識(shí)
weex-styler負(fù)責(zé)處理weex所支持的css樣式婿脸,以及驗(yàn)證開(kāi)發(fā)者所寫(xiě)的css樣式是否正確。
其中實(shí)現(xiàn)原理是使用開(kāi)源css https://www.npmjs.com/package/css 組件柄驻,根據(jù)css代碼的文本段狐树,生成json object類(lèi)型的 ast節(jié)點(diǎn)信息。要了解weex-styler的處理流程鸿脓,勢(shì)必要了解一下ast以及css的基本概念抑钟。
一張圖看懂CSS構(gòu)成.
A CSS rule-set consists of a selector and a declaration block:
rule-set:包含一個(gè)selector 以及多個(gè)declaration。
selector:樣式選擇器野哭,主要用來(lái)定位元素
declaration:定義樣式屬性以及值味赃。
了解這三個(gè)基本概念之后,看scripter也是輕車(chē)熟路了虐拓,快上車(chē)心俗。
scripter當(dāng)中,通過(guò)css parser得到AST json object,讀取ast.stylesheet.rules獲得到當(dāng)前樣式的rule-set,然后遍歷所有的declaration城榛,校驗(yàn)樣式是否被weex所支持的(因?yàn)閣eex中支持css的樣式有限)揪利,以及簡(jiǎn)單的value字段合法性校驗(yàn)。
![Uploading Paste_Image_374004.png . . .]
源碼:/weex-styler/index.js
weex-styler新老版之差異狠持。
對(duì)Pseudo class樣式進(jìn)行了支持疟位。
新版weex中,支持shorthand writing寫(xiě)法的transition樣式喘垂。
// shorthand writing
div {
transition: width 2s linear 1s;
}
div {
transition-property: width;
transition-duration: 2s;
transition-timing-function: linear;
transition-delay: 1s;
}
0x6 weex-templater 簡(jiǎn)介
解析we腳本中的<template/>標(biāo)簽內(nèi)容甜刻,其核心節(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)也是基于parse5解析出的json object,同時(shí)也會(huì)做數(shù)據(jù)綁定正勒,標(biāo)簽驗(yàn)證得院,自動(dòng)修復(fù)common錯(cuò)誤的處理。
<template>
<div if={{x}}>
<text onclick="toggle">Toggle: {{result}}</text>
</div>
</template>
- 數(shù)據(jù)綁定:
<text>標(biāo)簽內(nèi)的value,”Toggle: {{result}}”,
<div>標(biāo)簽內(nèi)的attribute if 中的 “{{x}}”,
也就這種用戶可以編輯的文本段章贞,需要對(duì)包含的表達(dá)式以及變量進(jìn)行處理,這里的實(shí)現(xiàn)就在var exp = require('./exp’)這個(gè)模塊當(dāng)中祥绞,
該exp函數(shù)有2個(gè)參數(shù),需要轉(zhuǎn)換的字符串文本,以及是否需要轉(zhuǎn)換成function對(duì)象鸭限。
![Uploading Paste_Image_402398.png . . .]
/weex-templater/lib/exp.js
將雙引號(hào)“替換為單引號(hào)’蜕径,去除所有\(zhòng)n換行控制字符。
判斷文本中是否包含表達(dá)式败京,如果不包含兜喻,直接返回原始文本。
根據(jù)生成的token列表赡麦,
文本會(huì)在兩端加入單引號(hào)’
表達(dá)式在兩端(),顯式的加入運(yùn)算優(yōu)先級(jí)朴皆。
比如Toggle: {{result}} => [‘\’Toggle:\’’,’(result)’]
這樣在最后,只需要把結(jié)果列表中的所有元素做一次’+’.join操作隧甚,就可以構(gòu)成了一個(gè)合法的js語(yǔ)句车荔。
- 事件綁定:
text中的onclick屬性的值渡冻,templater會(huì)自動(dòng)生成可以調(diào)用toggle函數(shù)的js代碼戚扳。當(dāng)標(biāo)簽的屬性名包含on前綴時(shí),將進(jìn)行事件綁定族吻。
weex-templater/index.js
在checkEvent方法中帽借,通過(guò)把封裝好的function描述字符串eval對(duì)象賦值給value,達(dá)到事件發(fā)生時(shí)觸發(fā)函數(shù)的機(jī)制超歌。

- 對(duì)template的內(nèi)容砍艾,對(duì)元素標(biāo)簽(如<div/><a/><img/等>),控制語(yǔ)句(if,else,repeat等)做validation,針對(duì)不同標(biāo)簽巍举,會(huì)有額外特殊的驗(yàn)證操作脆荷。
下面舉幾個(gè)典型例子,
- 【If】 validation: <if={{x == 1}}> 驗(yàn)證if中包含的value,以及value是否是一個(gè)合法的表達(dá)式蜓谋。
- 【else】 validation:當(dāng)遍歷到一個(gè)節(jié)點(diǎn)中包含else時(shí)梦皮,就會(huì)驗(yàn)證前一個(gè)節(jié)點(diǎn)中是否包含了if。
- Tag(標(biāo)簽)validation:
Tag的驗(yàn)證相對(duì)多一點(diǎn)桃焕,因?yàn)椴煌膖ag會(huì)有其特殊的規(guī)則剑肯,
例如最外層的<template/>只能包含一個(gè)root子節(jié)點(diǎn)。
container類(lèi)型的標(biāo)簽可以嵌套標(biāo)簽观堂,非container則不可让网。
<cell>標(biāo)簽可以自動(dòng)補(bǔ)全tree屬性。 - <text>標(biāo)簽比較特殊师痕,因?yàn)閠ext里面可以包含任意的字符串溃睹,變量,表達(dá)式,
例如下面的腳本七兜。
- 修復(fù)一些簡(jiǎn)單的common問(wèn)題丸凭。
舉個(gè)例子,比如圖像內(nèi)容腕铸,既可以寫(xiě)成<img>也可以寫(xiě)成<Image>,在templater中是有處理的惜犀。
源碼地址:weex-templater/lib/validator.js