這篇文章是筆者近期關於Weex在iOS端的一些研究和實踐心得,和你們一塊兒分享分享,也算是對學習成果的總結。文章裏面提到的作法也許不是最佳實踐,也許裏面的方法稱不算是一份標準的指南手冊,因此標題就只好叫「僞最佳實踐指北」了。有更好的方法歡迎你們一塊兒留言討論,一塊兒學習。html
因爲筆者不太瞭解Android,因此如下的文章不會涉及到Android。前端
自從Weex出生的那一天起,就沒法擺脫和React Native相互比較的命運。React Native宣稱「Learn once, write anywhere」,而Weex宣稱「Write Once, Run Everywhere」。Weex從出生那天起,就被給予了一統三端的厚望。React Native能夠支持iOS、Android,而Weex能夠支持iOS、Android、HTML5。vue
在Native端,二者的最大的區別可能就是在對JSBundle是否分包。React Native官方只容許將React Native基礎JS庫和業務JS一塊兒打成一個JS bundle,沒有提供分包的功能,因此若是想節約流量就必須製做分包打包工具。而Weex默認打的JS bundle只包含業務JS代碼,體積小不少,基礎JS庫包含在Weex SDK中,這一點Weex與Facebook的React Native和微軟的Cordova相比,Weex更加輕量,體積小巧。react
在JS端,Weex又被人稱爲Vue Native,因此 React Native 和 Weex 的區別就在 React 和 Vue 二者上了。webpack
筆者沒有寫過React Native,因此也無法客觀的去比較二者。不過知乎上有一個關於Weex 和 React Native很好的對比文章《weex&React Native對比》,推薦你們閱讀。ios
前兩天@Allen 許帥也在Glow 技術團隊博客上面發佈了一篇《React Native 在 Glow 的實踐》這篇文章裏面也談了不少關於React Native實踐相關的點,也強烈推薦你們去閱讀。git
關於小白想入門Weex,固然最基礎的仍是要通讀文檔,文檔是官方最好的學習資料。官方的基礎文檔有兩份:github
在文檔手冊裏面包含了Weex全部目前有的組件,模塊,每一個組件和模塊的用法和屬性。遇到問題能夠先過來翻翻。頗有可能有些組件和模塊沒有那些屬性。npm
看完官方文檔之後,就能夠開始上手構建工程項目了。
我司在知乎上面寫了4篇關於《Weex入坑指南的》。這四篇文章仍是很值得看的。
Weex也和前端項目同樣,擁有它本身的腳手架全家桶。weex-toolkit + weexpack + playground + code snippets + weex-devtool。
weex-toolkit是用來初始化項目,編譯,運行,debug全部工具。
weexpack是用來打包JSBundle的,實際也是對Webpack的封裝。
playground是一個上架的App,這個能夠用來經過掃碼實時在手機上顯示出實際的頁面。
code snippets這個是一個在線的playground。
我相信你們應該都有Native的App,若是真的App都沒有,那就用weexpack命令初始化一個新的項目。若是已經有App項目了,那麼weex命令就只是用來運行和調試的。
已經有iOS項目的,能夠經過cocospod直接安裝Weex的SDK,初始化SDK之後,Native就可使用Weex了。加載的JS的地址改爲本身公司服務器的IP。
#define CURRENT_IP @"your computer device ip"
// ...
// 修改端口號到你的端口號
#define DEMO_URL(path) [NSString stringWithFormat:@"http://%@:8080/%s", DEMO_HOST, #path]
// 修改 JS 文件路徑
#define HOME_URL [NSString stringWithFormat:@"http://%@:8080/app.weex.js", DEMO_HOST]複製代碼
這樣整個項目就能夠跑起來了。
這裏還有一點須要說明的是,項目雖然跑起來了,可是每次運行都須要啓動npm,打開Weex的前端環境。這裏有兩個作法。
第一種作法是直接Hook Xcode的run命令,在Xcode配置裏面加入啓動npm的腳本。好比下面這樣:
第二種作法就是每次運行以前,本身手動npm run dev。我我的仍是喜歡這種方式,由於在Xcode運行完成以前,必定能夠在命令行上面打完這些命令。
再說說如何Debug,這塊使用的是weex-devtool。
這個工具和前端在Chrome裏面調試的體驗基本相同。
具體使用方法看這兩篇文章便可,這裏再也不贅述:
《Weex 入坑指南:Debug 調試是一門手藝活》
《Weex調試神器——Weex Devtools使用手冊》
在平常開發中,咱們能夠所有本身開發完全部的Weex界面,固然還能夠用一些已有的優秀的輪子。Weex的全部優秀的輪子都在Weex Market裏面。
在這個Market裏面有不少已經寫好的輪子,直接拿來用,能夠節約不少時間。
好比這裏很火的weex-chart。weex-chart圖表插件是經過g2-mobile依賴gcanvas插件實現的
若是你想使用Weex Market的Plugin插件,你可使用weex plugin 命令:
$ weex plugin add plugin_name複製代碼
你只須要輸入插件的名稱就能夠從遠程添加插件到你本地的項目,好比添加 weex-chart,咱們能夠輸入命令:
$ weex plugin add weex-chart複製代碼
咱們可使用plugin remove移除插件,好比移除安裝好的 weex-cahrt:
$ weex plugin remove weex-chart複製代碼
這個插件庫裏面我用過weex-router,還不錯,用它來作weex的路由管理。推薦使用。
weex官方提供了weexpack命令。我以爲這個命令是提供給不懂iOS的前端的人用的。若是是Native來打包,依舊使用的Xcode的Archive打包。
徹底不懂iOS的前端開發者可使用weexpack build ios 打包,中間會要求輸入證書,開發者帳號等信息。都輸入正確之後就能夠打出ipa文件了。全程傻瓜操做。
若是是iOS開發者,原來怎麼打包如今仍是怎麼打包。只很少JS這塊要單獨進行打包。建議是把Weex這塊單獨用一個git分支進行管理,專門針對這個分支進行weexpack或者Webpack進行打包。webpack的具體配置由每一個公司本身配置。
這裏額外說一點,這一點也是前端大神告訴個人。webpack打完包之後是能夠經過webpack官方網站查看這個包裏面究竟打入了哪些文件和依賴。雖然我打包都是一股腦的都打完,可是資深前端開發也許還會再去檢查一下是否有多的文件被打進去了。極限壓縮包的體積,1KB的文件也很少放進去。
再談談發佈的問題。因爲有了Weex之後,每次發佈都會把上個版本累計到這個版本的hotPatch都累計修復掉,並在新版裏面直接內置最新的JSBundle文件。內置JS的目的也是爲了首屏加載秒開。
關於熱更新的做用你們都明白,否則用Weex的意義就少了好多。不過這裏還有一點須要說明的是——熱更新的策略。
在平常開發過程當中,咱們在瀏覽器上面連着手機調試,也並非實時刷新的。(不過經過在手機上掃描二維碼,而且手機和電腦在同一個局域網以內,能夠作到實時更新)
因此在實際生產環境中,熱更新的策略應該是這樣:有新的HotPatch就下發到客戶端,而後客戶端在下次啓動的時候,先比對版本信息,若是是新版本,就去加載這個最新的HotPatch,而後渲染在屏幕上。
曾經我幻想着能實時在線更新,就是線上一發布,全部用戶在聯網的狀況下,下發HotPatch完畢之後直接加載,聯網的用戶能夠實現秒級別的熱更新。這種雖然能夠作到,可是意義不大。作法是專門維護一套Websocket,直連服務器,下發完畢之後能夠經過調用Native的通知,Native客戶端本身刷新頁面便可。(目前應該沒有多少公司是這樣作的吧?)
關於JSBundle的版本管理這塊是應該交給前端來管理。前端可能會用版本號來管理各個包的版本。部署也會牽扯到每一個公司前端部署的流程。他們會更加了解。部署通常也會放到CDN上加速。
若是說Weex一點坑都沒有,那是不可能的。
好比說在某些界面連續Push的時候,頁面邊緣會有一些線條從屏幕上掃過。還有捕捉JS錯誤或者異常的時候,Weex並不能可靠的捕捉到異常,這點須要靠Native來作,Native捕捉到異常之後再傳遞事件給JS Runtime去處理。
計算頁面寬高尺寸這點是最須要注意的。Weex進行界面適配的時候是用750爲標準的,因此須要根據750去換算。還有一點是Weex裏面有四捨五入的操做,是會丟失一點精度的。具體這塊請看《Weex 事件傳遞的那些事兒》這篇文章裏面的源碼分析。
Weex JS 引擎也不支持 HTML DOM APIs 和 HTML5 JS APIs,這包括 document, setTimeout 等。
Weex關於Web標準的實現如今尚未達到100%,因此用Vue來寫Weex的話,有些是不支持的。
好比說一些CSS樣式,最使人想不到的就是不支持< br>,還不支持< form>,< table>,< tr>,< td>,不支持CSS percentage 單位,不支持相似 em,rem,pt 這樣的 CSS 標準中的其餘長度單位。不支持 hsl(), hsla(), currentColor, 8個字符的十六進制顏色。
Weex對W3C上的FlexBox的規範也沒有支持徹底,暫不支持inline,也不支持Z軸上面的變化,不過移動端在Z軸上的需求真的沒有。Weex的Layout是用的Yoga以前的某個版本,解決問題的方式也比較直接,後期升級到最新版的Yoga,即可以支持更多的Flex的標準了。
具體還有不支持的就要多翻翻文檔,好比這裏的《Weex 目前不支持的Web 標準有哪些》。這些最好先看看,內心有個數,以避免開發時候遇到一些莫名的bug,卻不知最終是由於不支持致使的。
而後還有一些是組件暫時還不支持同步方法。這裏是Vue 2.0還不支持,官方預計是在 0.12 版本支持。
額外提醒一點,因爲蘋果前段時間對JSPatch的封殺,因此致使Weex官方對自定義模塊給出了一個警告:
Weex 全部暴露給 JS 的內置 module 或 component API 都是安全和可控的, 它們不會去訪問系統的私有 API ,也不會去作任何 runtime 上的 hack 更不會去改變應用原有的功能定位。
若是須要擴展自定義的 module 或者 component ,必定注意不要將 OC 的 runtime 暴露給 JS , 不要將一些諸如 dlopen(), dlsym(), respondsToSelector:,performSelector:,method_exchangeImplementations() 的動態和不可控的方法暴露給JS, 也不要將系統的私有API暴露給JS
上述警告特別強調了不要用dlopen(), dlsym(), respondsToSelector:,performSelector:,method_exchangeImplementations()這幾個函數。這也是爲何一樣是用Weex有些人沒有經過審覈,有些人卻能經過審覈的緣由。
據說安卓上有Refresh Control的一些bug,安卓在Weex上的表現我沒有怎麼了解過,不過這塊若是出如今iOS上,我以爲能夠直接用Native來替換掉這塊,有bug的地方都用原生來作。
總之Weex仍是多多少少有一些問題,可是目前使用來看,不影響使用,只要懂得靈活變通,遇到實在過不去的坎,或者是真的一時hold不住的bug,那麼多考慮用原生來替代。
接下來講一下稍微高級的玩法。如下這些即便沒有作,也不影響Weex正常上線。
Weex默認是支持頁面降級的。好比出現了錯誤,就會降級到H5。這裏建議最好作一個線上的開關。我司在處理頁面降級的問題上採起了兩種級別的開關:
除了降級之後,還對應採起了灰度的策略,這樣保證線上bug下降到最低。
好比在用戶量低峯期的時候開啓開關進行灰度。還有一級灰度就經過線上實時錯誤監控平臺來控制,若是由於突發事件致使Crash率陡升,那麼就當即關閉Weex的開關,當即進行降級處理。
在Weex給的官方Demo裏面有一個M的小圓點浮框,點開會看到以下的界面:
在這裏咱們點開性能的按鈕:
在這裏咱們能夠看到監控了CPU,幀率,內存,電量,流量等數據,這些數據也是咱們在Native APM中監控的常見數據。固然,這個M圓點並不沒有開源。因此這塊須要各個公司本身作一套本身的監控系統。這塊可能每一個公司的前端已經作好了,因此Weex須要接入到前端的性能監控裏。
若是咱們再點開工具的界面,就會看到以下的選項:
這裏就有埋點監控。在初期可能Weex埋點仍是由Native進行埋點,由於各家都有自家的Native完整的埋點系統了。後期埋點這塊也能夠交給前端在前端埋點。
暫時筆者尚未實踐過Weex的增量更新,因此這裏就不提增量更新了。全量更新就比較簡單,下發整個JSBundle,App在下次啓動的時候再加載便可。Weex的包比RN的包小不少,通常就100-200K左右。阿里的一次Weex分享裏面提到他們gzip壓縮之後能達到60-80K。
上圖是阿里在Weex Conf大會上提出的一個挑戰,網絡請求加上首屏渲染的時間加起來小於1秒。
這裏面涉及到3方面的因素,網絡下載耗時,JS和Native通訊耗時,還有渲染耗時。
網絡下載耗時能夠經過支持HTTP / 2,配置Spdy協議,域名收斂,支持http-cache,極致壓縮JSBundle的大小,JSBundle預加載。
JSBundle預加載的時候能夠在App啓動時候預先下載JS。遠程服務器推包的時候經過長連通道Push,這裏能夠是全量 / 增量,被動 / 強制更新相互結合。
阿里關於JS和Native通訊耗時,渲染耗時的相關優化見上圖。這兩方面筆者也沒有相關的實踐。
雖然Weex有屬於它本身的全家桶,可是在支持了Vue 2.0之後,它的全家桶徹底能夠換成Vue的全家桶。Vue,Vue-Router,Vuex,原來還有Vue-resource,不過尤大後來去掉了這個Vue-resource,更加推薦axios了。因此全家桶裏面就是Vue,Vue-Router,Vuex,axios。
若是所有都換成了Vue之後,那麼前端首屏渲染的速度就須要Vue來解決了。爲了提升首屏渲染速度,wns緩存+直出 是必不可少的。在Vue 1. x 時代,沒有 server-side-render 方案,直出須要專門給寫一份首屏非Vue語法的模板。Vue2.0 server-side-render(簡稱Vue SSR)的推出,成功地讓先後端渲染模板代碼同構。
若是隻用了Vue-Router之後,當打包構建應用時,JSBundle 包會變得很是大,影響頁面加載。若是咱們能把不一樣路由對應的組件分割成不一樣的代碼塊,而後當路由被訪問的時候才加載對應組件,這樣就更加高效了。
結合 Vue 的 異步組件 和 Webpack 的 code splitting feature, 輕鬆實現路由組件的懶加載。減小JSBundle的體積。
還有一點須要注意的是,Vue-Router 提供了三種運行模式:
hash : 使用 URL hash 值來做路由。默認模式。
history : 依賴 HTML5 History API 和服務器配置。
abstract: 支持全部 JavaScript 運行環境,如 Node.js 服務器端。
不過Weex 環境中只支持使用 abstract 模式!
就在7天前,Vue 發佈了v2.3.0版本,官方支持了SSR。因此在支持了SSR之後,能夠大幅提高SEO,也能夠作到首屏秒開。因此爲了性能,SSR必作!
最後的最後,還有一些「前瞻性」的玩法。
JS service 和 Weex 實例在 JS runtime 中並行運行。Weex 實例的生命週期可調用 JS Service 生命週期。目前提供建立、刷新、銷燬生命週期。
這塊我在官方的Demo裏面也沒有找到相關的例子。在官方的文檔裏面有相關的例子。在官方手冊裏面有這樣一句話:
重要提醒: JS Service 很是強大但也很危險,請當心使用!
可見,這塊很是強大,也許能夠作不少「神奇的」事情。
在官方手冊《拓展JS framework》這一章節裏面,提到了能夠橫向拓展JS framework。這個功能可能通常公司都不會去擴展。
Weex 但願可以尊重儘量多的開發者的使用習慣,因此除了 Weex 官方支持的 Vue 2.0 以外,開發者還能夠定製並橫向擴展本身的或本身喜歡的 JS Framework。
定製完本身的JS Framework之後,就可能出現下面的代碼:
import * as Vue from '...'
import * as React from '...'
import * as Angular from '...'
export default { Vue, React, Angular };複製代碼
這樣還能夠橫向擴展支持Vue,React,Angular。
若是在 JS Bundle 在文件開頭帶有以下格式的註釋:
// { "framework": "Vue" }
...複製代碼
這樣 Weex JS 引擎就會識別出這個 JS bundle 須要用 Vue 框架來解析。並分發給 Vue 框架處理。
因此,Weex 支持同時多種框架在一個移動應用中共存並各自解析基於不一樣框架的 JS bundle。
能夠支持多種框架並存這點很是強大,固然尚未完,one more thing……
若是正常使用API,看官方文檔,不開源碼,是不會發現Rax的身影的。官方文檔絲毫沒有說起到它。
Rax是什麼呢?
在《淘寶雙促中的 Rax》這篇文章裏面介紹了Rax:
Rax 是一個基於 React 方式的跨容器的 JS 框架。
Rax 通過 gzip 之後的大小 8k,與 Angular、React、Vue 相比更加輕量。相比React的43.7kb,小了太多。
Rax 在設計上抽象出 Driver 的概念,用來支持在不一樣容器中渲染,好比目前所支持的:Web, Weex, Node.js 都是基於 Driver 的概念,將來即便出現更多的容器(如 VR ,AR等),Rax 也能夠從容應對。Rax 在設計上儘可能抹平各個端的差別性,這也使得開發者在差別性和兼容性方面不再須要投入太多精力了。
若是說RN和Weex這些技術是用來跨端的技術,那Rax是用來跨容器的:Browser、Weex、Node.js等。
那麼Weex裏面加了Rax能幹些什麼事情呢?值得期待!