0x1 讀完后希望你會
- 了解Weex中,we腳本的各個標簽<template><script><style>解析實現方式,如何生成可以運行的js腳本文件。
- 基于標簽tag,自己實現一套你喜歡的類似we或者微信小程序的腳本語言。
- 可以包含表達式計算
- 流程控制
0x2 背景
目前線上App接入的weex版本為0.8.X,距目前最新的0.10.X系列跨度相差較大,但是在保證目前業務穩定的前提下,不能直接升級Weex SDK到最新版。
在升級前期,不得不面對的幾個問題:
- 目前已開發的大量.we頁面是否可以在新版Weex運行。
- 繼續使用已被廢棄的we腳本開發新需求(Weex已經推薦用vue來寫頁面)
- Vue與Weex兩大生態的聯手,Weex官方也在推進vue來編寫界面.
- we腳本將來很有可能面臨不再被擴展維護,也就是weex很多的新特性在we中不一定會被支持,除非we與vue的feature更新節奏保持一致。
- 據說手淘與貓客已不再使用we編寫weex,而是全部采用vue(求證)。
- Vue自身生態龐大,對vue更好的支持,反而更利于weex的推廣。
所以在升級之前,以weex的transform流程原理為開端,展開一些前期的調研工作,順便學習一下weex的toolkit實現原理。
據weex的同學說新版的weex是可以跑老we的,不過要保證we腳本代碼的嚴謹性,因為新版的jsf runtime校驗機制,更加嚴格,某些頁面可能白屏(What??。。?。
老話常談,“Talk is cheap,Show me the code”。
0x3 驗證思路
一個we頁面被渲染執行,可以大致拆分為兩部分。
【.we腳本的打包與編譯】(weex/vue loader,生成標準的js腳本)
[.we] -> [build] -> output [*.js]
【Weex JS 運行時環境(JSF)】(負責解析運行編譯好的js腳本)
[*.js] -> [weex runtime] -> render [view:page]
從圖中可以看出 Weex 整體的工作流程。
首先開發者編寫 .we 文件。
通過 weex-toolkit 提供的工具將 .we 文件轉為js。
JS Framework 接收并執行 js 的代碼,執行數據綁定、模板編譯等操作,然后輸出 json 格式的 Virtual DOM 傳遞給移動端。
這篇文章主要分析第一層的transformer的實現原理。
0x4 we/vue 腳本是如何被解析的
不可不說的parse5:
weex-loader中,對we文件的解析主要依賴第三方開源npm組件,html標簽解析的parse5,對輸入的html標簽類文本,解析后輸出json對象。
關于輸出的json格式,可以參考官方的在線playground,http://astexplorer.net/#/1CHlCXc4n4
weex-loader首先通過parse5 得到we文本的json 結構的樹結構,
然后Weex-loader的處理流程中,針對不同標簽(<template/> <script/><style/>),分別有對應的解析處理模塊,
大致流程如上圖,從左向右依次為:
1.輸入為原始we腳本文件。
2.通過parse5組件解析出對應的jsonobject
3.根據json object中描述的各部分tag交給對應的處理模塊。
例如一個template標簽的json對象,在loader中是這樣被處理的,
源碼地址: weex-loader/lib/loader.js
不同的標簽類型文本會分配給專門的parse組件.
源碼地址:weex-loader/lib/parser.js
標簽對應的處理模塊如下:
<script> 標簽 ————> weex-templater
<style > 標簽 ————> weex-styler
<script> 標簽 ————> weex-scripter
0x5 weex-styler 簡介以及CSS預備知識
weex-styler負責處理weex所支持的css樣式,以及驗證開發者所寫的css樣式是否正確。
其中實現原理是使用開源css https://www.npmjs.com/package/css 組件,根據css代碼的文本段,生成json object類型的 ast節點信息。要了解weex-styler的處理流程,勢必要了解一下ast以及css的基本概念。
一張圖看懂CSS構成.
A CSS rule-set consists of a selector and a declaration block:
rule-set:包含一個selector 以及多個declaration。
selector:樣式選擇器,主要用來定位元素
declaration:定義樣式屬性以及值。
了解這三個基本概念之后,看scripter也是輕車熟路了,快上車。
scripter當中,通過css parser得到AST json object,讀取ast.stylesheet.rules獲得到當前樣式的rule-set,然后遍歷所有的declaration,校驗樣式是否被weex所支持的(因為weex中支持css的樣式有限),以及簡單的value字段合法性校驗。
![Uploading Paste_Image_374004.png . . .]
源碼:/weex-styler/index.js
weex-styler新老版之差異。
對Pseudo class樣式進行了支持。
新版weex中,支持shorthand writing寫法的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 簡介
解析we腳本中的<template/>標簽內容,其核心節點數據結構也是基于parse5解析出的json object,同時也會做數據綁定,標簽驗證,自動修復common錯誤的處理。
<template>
<div if={{x}}>
<text onclick="toggle">Toggle: {{result}}</text>
</div>
</template>
- 數據綁定:
<text>標簽內的value,”Toggle: {{result}}”,
<div>標簽內的attribute if 中的 “{{x}}”,
也就這種用戶可以編輯的文本段,需要對包含的表達式以及變量進行處理,這里的實現就在var exp = require('./exp’)這個模塊當中,
該exp函數有2個參數,需要轉換的字符串文本,以及是否需要轉換成function對象。
![Uploading Paste_Image_402398.png . . .]
/weex-templater/lib/exp.js
將雙引號“替換為單引號’,去除所有\n換行控制字符。
判斷文本中是否包含表達式,如果不包含,直接返回原始文本。
根據生成的token列表,
文本會在兩端加入單引號’
表達式在兩端(),顯式的加入運算優先級。
比如Toggle: {{result}} => [‘\’Toggle:\’’,’(result)’]
這樣在最后,只需要把結果列表中的所有元素做一次’+’.join操作,就可以構成了一個合法的js語句。
- 事件綁定:
text中的onclick屬性的值,templater會自動生成可以調用toggle函數的js代碼。當標簽的屬性名包含on前綴時,將進行事件綁定。
weex-templater/index.js
在checkEvent方法中,通過把封裝好的function描述字符串eval對象賦值給value,達到事件發生時觸發函數的機制。

- 對template的內容,對元素標簽(如<div/><a/><img/等>),控制語句(if,else,repeat等)做validation,針對不同標簽,會有額外特殊的驗證操作。
下面舉幾個典型例子,
- 【If】 validation: <if={{x == 1}}> 驗證if中包含的value,以及value是否是一個合法的表達式。
- 【else】 validation:當遍歷到一個節點中包含else時,就會驗證前一個節點中是否包含了if。
- Tag(標簽)validation:
Tag的驗證相對多一點,因為不同的tag會有其特殊的規則,
例如最外層的<template/>只能包含一個root子節點。
container類型的標簽可以嵌套標簽,非container則不可。
<cell>標簽可以自動補全tree屬性。 - <text>標簽比較特殊,因為text里面可以包含任意的字符串,變量,表達式,
例如下面的腳本。
- 修復一些簡單的common問題。
舉個例子,比如圖像內容,既可以寫成<img>也可以寫成<Image>,在templater中是有處理的。
源碼地址:weex-templater/lib/validator.js