React是當(dāng)前前端應(yīng)用最廣泛的框架。三大SPA框架 Angular、React、Vue比較。
目前成都創(chuàng)新互聯(lián)已為數(shù)千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、鎮(zhèn)坪網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。目前來(lái)看React的生態(tài)系統(tǒng)要比Vue大的多,在github、stackoverflow等大的技術(shù)社區(qū)搜索兩者,React的搜索結(jié)果是Vue的十倍左右,另外據(jù)近期統(tǒng)計(jì)使用React的站點(diǎn)是Vue的幾百倍以上。更大的生態(tài)意味著更多可用的資源,以及遇到問(wèn)題可以得到更多的有效參考與幫助,這也是除了性能之外選擇React的核心原因。
選擇React之后,應(yīng)用會(huì)在以下幾個(gè)方面有提升。
三大框架在移動(dòng)端分別有自己的東西。Angular的ionic,React的React Native,Vue的Weex。其中ionic 是基于cordova技術(shù),依然是瀏覽器應(yīng)用。而后兩者已上升到操作原生控件的層面,做出來(lái)的是原生界面,其中React Native的成熟度遠(yuǎn)高于Weex,已經(jīng)被很多公司使用,而Weex使用者很少。
綜合來(lái)看選擇React 生態(tài)明顯最佳,由當(dāng)前的cordova過(guò)渡為cordova+Reactjs,然后可以平滑地過(guò)渡到React Native,媲美原生性能的最優(yōu)混合開(kāi)發(fā)方式。之所以說(shuō)平滑是因?yàn)镽eact Native中近90%的代碼(JS)可以在IOS和Android端使用,剩余的涉及原生的代碼也基本可以找到可用的資源,就像cordova 的插件一樣。畢竟如果需要同時(shí)掌握J(rèn)S, OC(或swift),java(或kotlin)才能開(kāi)發(fā)React Native的話,那這門技術(shù)不會(huì)有人用;當(dāng)然反過(guò)來(lái)如果有原生開(kāi)發(fā)知識(shí)的話會(huì)對(duì)開(kāi)發(fā)React Native有一定幫助。
直接轉(zhuǎn)型為React native的話涉及了應(yīng)用底層架構(gòu)的變動(dòng),有比較大的跨度,而轉(zhuǎn)為cordova+Reactjs相對(duì)容易,而由cordova+Reactjs到React Native同樣容易不少,因?yàn)槠渲写蟛糠諶eactjs代碼可以重用。
首先開(kāi)發(fā)腳手架官方出了Create-react-app,集成了webpack-當(dāng)前最流行的打包工具,babel-提高js版本兼容性的轉(zhuǎn)碼器,以及ESLint-代碼檢測(cè)工具和其它一些常用工具,同時(shí)對(duì)這些工具進(jìn)行了比較優(yōu)的配置。值得一提的是該腳手架將這些工具的配置文件進(jìn)行了隱藏,本意是讓使用者專注于編碼即可,但實(shí)際使用時(shí)通常會(huì)有自己配置的需求,此時(shí)執(zhí)行npm run eject即可出現(xiàn)被隱藏配置文件。
React-router 是官方推薦的路由管理工具,由于是單頁(yè)應(yīng)用區(qū)別于原先的html界面間跳轉(zhuǎn),跳轉(zhuǎn)實(shí)質(zhì)是在組件間進(jìn)行,所以需要有路由管理工具來(lái)統(tǒng)一化管理。這里值得一提的是,React-router配合webpack可以實(shí)現(xiàn)代碼的按需加載。
一般來(lái)說(shuō),webpack打包后會(huì)在生成一個(gè)壓縮的js文件,在單頁(yè)應(yīng)用打開(kāi)會(huì)整體加載這個(gè)文件,由于該js文件包含之前所有的js代碼,雖然進(jìn)行了壓縮,一般仍至少有幾百kb,當(dāng)應(yīng)用稍微復(fù)雜點(diǎn),打包后文件會(huì)相應(yīng)變大。而加載的時(shí)候,不管那些代碼有沒(méi)有執(zhí)行到,都會(huì)下載下來(lái)并進(jìn)行加載,造成性能浪費(fèi),這一點(diǎn)在顯然在web端很重要,而在cordova中是將js代碼直接打包在本地,等于跳過(guò)了下載步驟但仍然會(huì)有加載過(guò)程。通過(guò)在router中寫require.ensure代碼并在webpack中相應(yīng)地修改配置即可將js分成多個(gè)文件,在需要時(shí)加載對(duì)應(yīng)的js文件,實(shí)現(xiàn)按需加載。
Redux 是應(yīng)用最廣泛的第三方狀態(tài)管理工具,其作用是當(dāng)應(yīng)用中多數(shù)據(jù)狀態(tài)交互時(shí),可以更有方便且代碼結(jié)構(gòu)清晰地統(tǒng)一管理狀態(tài),下圖給出了形象的闡釋。由于在實(shí)際開(kāi)發(fā)中一般是分人員/分功能模塊獨(dú)立開(kāi)發(fā),考慮引入redux的成本(redux本身略復(fù)雜),可以在沒(méi)有多數(shù)據(jù)交互的模塊不使用redux,而在類似涉及增刪改查的表單以及即時(shí)通訊websocket等契合redux的模塊使用。
為項(xiàng)目選取合適UI組件庫(kù),一定程度上簡(jiǎn)化UI樣式的開(kāi)發(fā)并且考慮使用其提供的過(guò)渡動(dòng)畫(huà)效果。這方面有比較多的選擇,Google Material Design 風(fēng)格的Material-UI在github上最受歡迎,但其設(shè)計(jì)語(yǔ)言與我們當(dāng)前APP截然不同,騰訊的weui和阿里的antd-mobile 較為相近,其中antd-mobile與create-react-app腳手架配合使用時(shí)配置項(xiàng)比較繁雜,因?yàn)榘⒗锉疽馐怯脕?lái)配合自己的腳手架dva(封裝了react-router和redux),因此暫時(shí)選擇weui,后期開(kāi)發(fā)有特定組件需求可結(jié)合其他ui庫(kù)使用。
至于頁(yè)面跳轉(zhuǎn)時(shí)的過(guò)渡動(dòng)畫(huà),有些UI庫(kù)給出了一些過(guò)渡樣式,比如touchstone。但該庫(kù)已不再維護(hù),文檔不佳,且與新版本的react-router配合使用有不兼容情況。后來(lái)瀏覽官方文檔發(fā)現(xiàn)官方有動(dòng)畫(huà)庫(kù)react-addons-css-transition-group,使用該庫(kù)結(jié)合css3的動(dòng)畫(huà)三件套animation,transition,transform即可實(shí)現(xiàn)各種動(dòng)畫(huà)效果包括基本的過(guò)渡效果,比如漸進(jìn)平移等。
另外關(guān)于css,因?yàn)槭菃雾?yè)應(yīng)用,所以如果不加處理,直接import css文件的話最終打包生成一個(gè)css文件會(huì)導(dǎo)致樣式應(yīng)用到全局,造成同類名樣式相互污染影響。解決這個(gè)問(wèn)題有很多種方案。Facebook積極探索css in js方式,但直接寫內(nèi)聯(lián)樣式代碼可讀性太差。目前解決方案中應(yīng)用最廣泛的是css-modules,即在webpack配置中開(kāi)啟module選項(xiàng),使用styles對(duì)象來(lái)寫樣式。
解決的原理是將css類名在打包后編譯成哈希字符串,保持其唯一性。但當(dāng)想要使用全局樣式時(shí)要再配置,稍顯繁雜,且它類名編寫的方式為對(duì)象的方式,需要整體修改,另外在使用它時(shí),發(fā)現(xiàn)不支持-橫線的類命名方式,支持下劃線方式,推薦駝峰式,而我們之前html中的樣式類名大多是橫線命名,這意味著原h(huán)tml和css中的類名都要對(duì)應(yīng)修改,考慮到樣式類名非常多,這一方式舍棄。
另外有基于css-modules使用高階組件的react-css-modules使用人數(shù)也比較多,允許橫線命名方式且全局本地樣式區(qū)分簡(jiǎn)單,但有benchmark測(cè)試表明其會(huì)較大程度拖累性能,所以也舍棄。解決這個(gè)問(wèn)題要大程度兼容原先css的寫法,即改動(dòng)最小,因?yàn)橹暗腸ss類樣式數(shù)量龐大。
Webpack css-loader 有個(gè)屬性 :local 加上之后類會(huì)變成局部作用域,即webpack會(huì)對(duì)該類型的類進(jìn)行自動(dòng)哈希轉(zhuǎn)碼處理,但顯然類名一個(gè)個(gè)加:local 是有些呆板的工作,于是想到可以利用scss的嵌套屬性將:local在一個(gè)css文件中統(tǒng)一加到類名前。這里涉及到在腳手架create-react-app 添加對(duì)scss的支持,在命令行執(zhí)行安裝,并在package.json的scripts中添加watch-css指令,將原css文件改為scss文件,然后在最外層添加:local,執(zhí)行watch-css命令,即可在scss文件旁自動(dòng)產(chǎn)生css文件,且類名前自動(dòng)添加:local 前綴,這種方法實(shí)踐中發(fā)現(xiàn)并非所有類的樣式都與:local 兼容良好,相應(yīng)的可以使用文件名代替:local,要做的就是保持文件名的唯一性,這一點(diǎn)原工程下的文件名已滿足。這樣原先文件中引入css的方式,全局css引入的方式都不需要變化,做到最小代價(jià)。
scss 是 sass 3 引入新的語(yǔ)法,其語(yǔ)法完全兼容 css3,并且繼承了 sass 的強(qiáng)大功能,sass和less是前端擴(kuò)充css常用的方式,添加了嵌套,變量,繼承等語(yǔ)法,但需要編譯成css來(lái)最終使用(穩(wěn)定性考慮)。
開(kāi)發(fā)Reactjs使用官方提供的腳手架Create-react-app,最終通過(guò)npm run build生成一個(gè)單頁(yè)網(wǎng)頁(yè)應(yīng)用,放入cordova的www目錄下即可。由于這兩部分開(kāi)發(fā)時(shí)獨(dú)立,而原先開(kāi)發(fā)是在含www目錄的cordova工程目錄下直接開(kāi)發(fā),這種不同會(huì)產(chǎn)生一些問(wèn)題。比如cordova中某些插件安裝后export函數(shù)或者變量供引入使用,因?yàn)橐婚_(kāi)始是分離的,在create-react-app中并找不到這些變量,就造成在build的時(shí)候產(chǎn)生變量undefined的錯(cuò)誤,盡管最終放到cordova工程中后可以找到變量并正常運(yùn)行,但在第一步react開(kāi)發(fā)時(shí)控制臺(tái)報(bào)一堆error會(huì)妨礙調(diào)試,影響開(kāi)發(fā)體驗(yàn)。
在github上有一些react cordova 庫(kù),但實(shí)質(zhì)上它們都需要通過(guò)npm run build來(lái)打包,所以并沒(méi)有解決引入插件變量的問(wèn)題,且會(huì)與create-react-app 有相斥的地方。所以要想辦法使插件提供的變量在React中不報(bào)錯(cuò),這里在不影響ESLint 檢錯(cuò)機(jī)制的情況下可以采取迂回的方式。Build時(shí)控制臺(tái)報(bào)錯(cuò)僅針對(duì)src文件夾下的代碼,而在public文件夾下還有個(gè)index.html這個(gè)文件會(huì)最終被打包放到www目錄下,因此可以在這個(gè)文件中deviceready時(shí)添加全局的插件變量(注意該類全局變量的唯一性,可以添加plugin前綴或使用命名空間等方式保證),并將值傳給src目錄下的代碼中,這樣即可繞過(guò)控制臺(tái)build以及調(diào)試時(shí)的報(bào)錯(cuò)。
另外一個(gè)小技巧可以將react工程直接放在cordova工程目錄下,指定最終build生成的文件放入www目錄下,省掉手動(dòng)轉(zhuǎn)移文件的過(guò)程。
還有需要注意的一點(diǎn)是由于React中默認(rèn)配置的公共路徑是絕對(duì)路徑,當(dāng)放在cordova中時(shí)需要使用file協(xié)議放本地,需要在webpack的production配置的public路徑前加".",或者在package.json 文件增加一行"homepage": "../www"或"homepage": "."改為相對(duì)路徑,否則會(huì)出現(xiàn)找不到文件的情況,這里推薦最后一種方式。
首先IDE選取webstorm,功能強(qiáng)大,之前項(xiàng)目組在用可以沿用下來(lái),但需要注意的一點(diǎn)是當(dāng)目錄中包含了安裝的依賴node_modules時(shí),由于該文件夾下文件數(shù)量非常多,webstorm在智能建立代碼關(guān)聯(lián)時(shí)會(huì)占用大量資源,在某些電腦上會(huì)偶爾會(huì)出現(xiàn)卡死現(xiàn)象,這一現(xiàn)象在我配置比較高(固態(tài)硬盤加8g運(yùn)存)的電腦上同樣出現(xiàn)了,解決辦法是在file-setting-File types中配置ignore node_modules 文件夾。
上圖是create-react-app 項(xiàng)目的目錄,主要代碼放在src目錄下。Components中包含所有組件。React嚴(yán)格地執(zhí)行組件技術(shù),組件化不僅方便重用,同樣可以將一個(gè)頁(yè)面清晰地分割為幾個(gè)部分最后放入一個(gè)父組件展示,因?yàn)閖sx技術(shù)將js和html放在了一起,分割后每個(gè)部分有自己的功能邏輯與頁(yè)面展示,這樣更加清晰易維護(hù)。事實(shí)上react提出了一切皆組件的思想,只是有的組件render了部分界面,而有的沒(méi)有render。
上圖中components下有common文件用來(lái)放項(xiàng)目成員自己寫的公用組件比如公共請(qǐng)求方法等,external放外部引入的組件,work_log里放的是我寫的工作日志模塊的組件,各個(gè)功能模塊都各自創(chuàng)建一個(gè)文件夾,命名規(guī)則統(tǒng)一使用下劃線方式,這也是之前使用的方式。具體功能模塊的劃分與層級(jí)關(guān)系可以參考之前的.
值得一提的,以前html的層級(jí)關(guān)系必須嚴(yán)格為兩層(涉及到跳轉(zhuǎn)路徑的邏輯),導(dǎo)致最后出現(xiàn)沒(méi)有把一個(gè)功能模塊放到一個(gè)文件夾里的情況,比如上面的工作日志之前所包含的各個(gè)文件直接和其它的一些功能模塊一起放到了setting文件夾內(nèi)。而現(xiàn)在只要在React-router統(tǒng)一配置好路由,實(shí)質(zhì)上是往某個(gè)組件跳轉(zhuǎn),不存在跳轉(zhuǎn)路徑的限制。
Constants文件夾下存放各種常量,比如各種接口路徑。Fonts存放字體圖標(biāo)文件,images存放圖片,redux文件夾下是redux的幾個(gè)組成部分,styles下放scss/css樣式文件。Index.js是入口也是最頂層的父組件,router.js則維護(hù)了整個(gè)應(yīng)用的路由關(guān)系。
上面就是本次調(diào)研的技術(shù)分析文檔,瀏覽大量技術(shù)文檔,開(kāi)源社區(qū)以及技術(shù)論壇并結(jié)合實(shí)踐摸索得出的選型思路和理由,可能依然會(huì)有一些點(diǎn)沒(méi)有添加進(jìn)去,以后會(huì)結(jié)合新知識(shí)和實(shí)踐繼續(xù)完善。
作者:梁鑫
來(lái)源:宜信技術(shù)學(xué)院