在進(jìn)行React重構(gòu)優(yōu)化的過程中,構(gòu)建對(duì)項(xiàng)目的優(yōu)化作用必不可少,F(xiàn)在2016年8月,web前端技術(shù)這幾年變化太快,因此一些信息的時(shí)效性非常重要,還是把時(shí)間寫上比較好。
百度新聞的 webapp 有兩個(gè)途徑可以訪問。第一個(gè)是用手機(jī)瀏覽器訪問 m.baidu.com 點(diǎn)擊搜索框下面的“新聞”鏈接,第二個(gè)是下載手機(jī)百度app,搜索框下面有個(gè)“新聞”鏈接。每天平均的PV,大概接近1億。
為何要重構(gòu)?
重構(gòu)一個(gè)項(xiàng)目需要很多條件的支持,但是最終的目的,是為了:第一減少維護(hù)和二次開發(fā)的成本、第二提高產(chǎn)品的用戶體驗(yàn)或完善功能,兩者至少要符合一個(gè),否則沒必要重構(gòu)。不是為了重構(gòu)而重構(gòu),為了技術(shù)而重構(gòu)。
要重構(gòu)一個(gè)項(xiàng)目,特別是一個(gè)比較復(fù)雜的項(xiàng)目,是需要一些條件的,否則一般都會(huì)維護(hù)現(xiàn)有版本的產(chǎn)品。比如好多公司的app、網(wǎng)站做的很炫很漂亮,而公司內(nèi)部的erp、oa、cms等系統(tǒng)都用著10多年前的代碼。新聞webapp雖然看似就是一個(gè)很簡(jiǎn)單的新聞列表、新聞分類、新聞內(nèi)容頁(yè),但是詳細(xì)分析起來還是蠻復(fù)雜的?偨Y(jié)起來,重構(gòu)新聞webapp的條件有這么幾個(gè):
目前代碼比較混亂、代碼之間耦合太多,從2011年做完這一版開始,經(jīng)歷了好幾個(gè)人維護(hù);
框架比較老(backbone + zepto),已經(jīng)落伍,使得維護(hù)人員很沒有認(rèn)同感;
那段時(shí)間產(chǎn)品經(jīng)理的需求不是很多,開發(fā)人員正好有大量的時(shí)間;
以上原因中,第三個(gè)是最重要的,否則大家都每天加班很晚,誰(shuí)會(huì)再去考慮重構(gòu)這事兒?既然有時(shí)間,那就做吧!我就主動(dòng)跟我們組長(zhǎng)提出了這個(gè)事兒,得到他的贊同之后,我們就就開始了下面的內(nèi)容。
選擇靠譜的技術(shù)框架
重構(gòu)的第一步就是選擇一個(gè)比較靠譜的前端框架,F(xiàn)階段你如果要做一個(gè)webapp,再說什么框架都不用,就用zepto.js,那就out了。這并不是為了炫耀技術(shù)或者為了用而用,選用一個(gè)靠譜的框架,真的會(huì)從設(shè)計(jì)、開發(fā)、維護(hù)這幾個(gè)方面都會(huì)增加效率降低成本。
現(xiàn)階段前端框架可選的有以下幾個(gè):
angular
vue
react
angular我們一開始就直接放棄了。第一,因?yàn)樗约禾^于強(qiáng)大,什么事兒都自個(gè)干了,不利于配置和擴(kuò)展;第二,它的學(xué)習(xí)成本相對(duì)于其他兩個(gè)算最高的了,代碼畢竟不是自己一個(gè)人寫,而且寫完了也不一定后期誰(shuí)維護(hù)呢,學(xué)習(xí)成本盡量越低越好;第三,它都快升級(jí)2.0版本了,當(dāng)時(shí)2.0沒有正式發(fā)布,不是已經(jīng)有beta版本,而且使用了typescript,學(xué)習(xí)成本就更高了。
下面,就到了vue和react的選擇了。這兩者我當(dāng)時(shí)都是了解各大概,做過一些demo,但是都沒有在項(xiàng)目中實(shí)際用過。于是我花了大概一周多的時(shí)間做了一個(gè)調(diào)研,即分別用vue和React做了一個(gè)很粗糙的、簡(jiǎn)化版的新聞webapp的demo,然后兩者做了一下對(duì)比。后來沒有發(fā)現(xiàn)兩者有太多的懸殊,可能有些細(xì)節(jié)的習(xí)慣上仁者見仁,無(wú)論是使用React還是Vue都能很高效、清晰的完成既定功能,學(xué)習(xí)成本也都不高。
關(guān)于React和Vue的入門教程,介紹兩個(gè)很不錯(cuò)的視頻教程《 vuejs入門基礎(chǔ)》、《React入門》《React實(shí)戰(zhàn)–打造畫廊應(yīng)用》
但是,最后還是選擇了React,理由就是React生態(tài)更大。確切的說,應(yīng)該是選擇了React + React-router + Redux的技術(shù)框架,與之對(duì)應(yīng)的是Vue + Vue-router + Vuex
做技術(shù),框架的生態(tài)很重要。選擇對(duì)了,以后的升級(jí)就順風(fēng)順?biāo),選擇錯(cuò)了,就會(huì)很糾結(jié)很難受。果不其然,沒過多久,手機(jī)百度的app團(tuán)隊(duì)就成了研究React Native的技術(shù)小組,由于我當(dāng)時(shí)早早的熟悉了React,還給他們當(dāng)了幾次老師[偷笑]。
驗(yàn)證技術(shù)框架的性能問題
選擇完技術(shù)框架之后,還有兩個(gè)重要的問題有待于驗(yàn)證。
低版本android是否流暢
拿我們之前用React做的那個(gè)demo,在未經(jīng)過優(yōu)化的情況下,使用一些低版本的手機(jī)進(jìn)行驗(yàn)證,結(jié)果發(fā)現(xiàn)瀏覽器運(yùn)行的效果還算是流暢,最后優(yōu)化之后的流暢度會(huì)好一些。但是中途遇到兩個(gè)其他問題,就此記錄一下。
flex兼容性問題:本來利用flex布局,結(jié)果如果要使用flex-wrap做換行的話,有些瀏覽器就不支持了,最典型的就是android的UC瀏覽器;
fetch 的兼容性問題:高級(jí)瀏覽器默認(rèn)支持fetch了,但是低版本(如 ios6)還不支持,需要借助npm install es6-promise這個(gè)庫(kù)來做兼容。
React比Vue重,如何讓首屏更“輕”
用React開發(fā)webapp肯定是SPA應(yīng)用,網(wǎng)頁(yè)一加載肯定會(huì)把系統(tǒng)中用到的所有的js、css都加載下來,但是這樣會(huì)不會(huì)導(dǎo)致首屏?xí)r間會(huì)很慢?帶著這個(gè)疑問,我們做了一個(gè)使用fis3做異步加載的demo。demo很簡(jiǎn)單,就一個(gè)home頁(yè)(列表頁(yè))、detail頁(yè)、about也,很簡(jiǎn)單的一個(gè)demo,最關(guān)鍵的是下面的fis-conf.js的配置。
下面這個(gè)配置的意思是:根據(jù)不同的頁(yè)面,打包成不同的文件。例如,針對(duì) home頁(yè)打包成一個(gè)home-third.js和home-app.js,針對(duì)about頁(yè)打包成about-third.js和about-app.js……這樣,訪問哪個(gè)頁(yè)面就動(dòng)態(tài)加載相應(yīng)的js,暫時(shí)訪問的不到的頁(yè)面,其js就先不加載。這樣來提高性能。
(以下代碼如果看不懂,可以先看下一節(jié)介紹fis3配置的內(nèi)容,那里會(huì)有這塊的解釋)
后來直到上線,這個(gè)分頁(yè)面加載資源也沒用上。原因如下:
配置有點(diǎn)復(fù)雜,針對(duì)不同router都得配置
經(jīng)過壓縮之后,third.js才80kb,app.js不到50kb,而且third.js一般是強(qiáng)緩存的,文件已經(jīng)很小了,沒必要做分屏加載
選擇靠譜的構(gòu)建工具
在公司內(nèi)部做項(xiàng)目,當(dāng)然盡量選用公司自己的框架,而百度的 fis3 那會(huì)兒已經(jīng)基本成熟了,有了400+的插件,支持我們當(dāng)時(shí)的React重構(gòu)是問題不大了。而且,當(dāng)時(shí)已經(jīng)有人拿fis3做過構(gòu)建React的重構(gòu),還分享了經(jīng)驗(yàn)——如何用 fis3 來開發(fā) React?
fis3 是一個(gè)很不錯(cuò)的構(gòu)建工具,至少我們?cè)谑褂眠^程中還比較滿意。除了基本功能,它的動(dòng)態(tài)假數(shù)據(jù)模擬、發(fā)布到測(cè)試機(jī)這些功能非常實(shí)用,詳情請(qǐng)看官網(wǎng)文檔。但是它最大的問題是生態(tài)、圈子上還沒有webpack、gulp大,因此用的人少,用的人越少了生態(tài)就越小。
為項(xiàng)目選擇打包工具,除了基本功能(打包、壓縮、合并、編譯less等語(yǔ)法糖、生成md5后綴等等),以下幾點(diǎn)是最必須考慮的內(nèi)容。
編譯 React 的 .jsx格式和 ES6 語(yǔ)法
支持 npm 生態(tài),支持js的模塊管理
動(dòng)態(tài)引用css和圖片(因?yàn)橐媒M件化開發(fā),組件需要的css要在組件中引用)
按需打包js
模擬假數(shù)據(jù),運(yùn)行代碼
支持多種編譯模式,例如dev模式下不壓縮代碼、方便調(diào)試,而publish模式下壓縮代碼、壓縮資源
下面挨著說明一下,以上幾點(diǎn)使用fis3時(shí)如何配置的,也權(quán)當(dāng)幫助公司宣傳一下國(guó)產(chǎn)前端編譯神器——fis3
注意:以下所提到的fis3的配置,都要寫在./fis-conf.js代碼中,這是fis3的規(guī)則,可以去查閱官網(wǎng)的文檔。另外,以下代碼注釋中提示要npm install ... --save-dev安裝的插件,你都可以在 github.com 上找到。
編譯 React 的 .jsx格式和 ES6 語(yǔ)法
一般情況下,編譯ES6都用babel,編譯jsx也有相應(yīng)的工具,但是沒成想這兩個(gè)只需要用typescript這一插件就搞定了。速度還要快,不過編譯打包,速度慢一點(diǎn)也沒關(guān)系,不考慮這個(gè)因素。但是使用typescript確實(shí)很方便。
支持 npm 生態(tài),支持js的模塊管理
以下配置即可是的fis3支持npm生態(tài),并且選擇使用commonjs的模塊化方案。這樣我們使用 npm install react --save 之后,在js代碼中,就直接可以使用import * as React from 'react'了,符合目前js的主流寫法。
動(dòng)態(tài)引用css和圖片
前端現(xiàn)在都是組件化開發(fā)的思路,一個(gè)項(xiàng)目中可能需要很多css代碼,但是一個(gè)組件中,就只引用它自己需要的代碼,然后構(gòu)建工具再將所有組件引用的css文件合并起來,一起給最終的頁(yè)面——這是組件化中使用css的思路。
使用以下配置,我們可以在js文件中直接引用css和圖片文件,跟webpack中使用相似。如果使用ES6語(yǔ)法,引用css時(shí)寫import './style.css',引用圖片時(shí)寫 import * as url from '../img/abc.png'
按需打包js
因?yàn)槭墙M件化開發(fā),因此項(xiàng)目中所有的圖片都是零散的放在各個(gè)組件里面的,因此最終打包之后,要將所有的圖片都打包到一個(gè)統(tǒng)一的目錄下,方便管理
最終打包完成的時(shí)候,我們要將項(xiàng)目中用到的所有代碼都打包成以下幾個(gè)文件:
app.js 程序員手寫出來的業(yè)務(wù)代碼,后期的二次開發(fā)或者維護(hù)調(diào)整比較頻繁,單獨(dú)打包成一個(gè)文件;
third.js 第三方插件的代碼,例如 React Redux 等,后期幾乎不調(diào)整,單獨(dú)打包成一個(gè)文件,可直接使用http強(qiáng)緩存,提高性能;
aio.css 所有的css文件
lib.js 直接以<script>方式寫在html頁(yè)面上的幾個(gè)js文件,都打包成 lib.js ,減少http請(qǐng)求
具體配置查看如下代碼,注釋中寫的也非常清楚了
模擬假數(shù)據(jù),運(yùn)行代碼
大部分情況下,開發(fā)的代碼要查看效果都是啟用 fis3 server start 然后在本地瀏覽器打開 127.0.0.1:8080 來自測(cè)的,而此時(shí)本地是沒有服務(wù)器端的接口的,例如本地頁(yè)面中有一個(gè)/news?tn=gethotnews這個(gè)ajax請(qǐng)求(舉例用,實(shí)際上根本沒有 gethotnews 這個(gè)接口名稱),默認(rèn)會(huì)請(qǐng)求127.0.0.1/news?tn=gethotnews,是會(huì)返回404的。那這時(shí)候怎么辦呢?
提前你要查閱fis3關(guān)于假數(shù)據(jù)模擬的 文檔說明
選擇一,你可以為/news?tn=gethotnews這個(gè)接口準(zhǔn)備一個(gè)靜態(tài)的json文件,文檔中說過了。但是新聞webapp的接口實(shí)在是太多了,為每個(gè)接口都準(zhǔn)備一下,耗費(fèi)很多工作量,而且萬(wàn)一接下來接口返回的數(shù)據(jù)結(jié)構(gòu)有變化,還得跟著改,麻煩。因此我們選擇第二種。
選擇二,如果在本地訪問有/news?tn=gethotnews,通過借助fis3的一些功能,能直接返回線上m.news.baidu.com/news?tn=gethotnews的數(shù)據(jù),這樣是不是就一步搞定了!下面說說該如何操作。
首先,新建一個(gè)./config/server.conf的文件,內(nèi)容如下。意思是,只要發(fā)出去的網(wǎng)絡(luò)請(qǐng)求的url符合^\/news.*$這個(gè)正則規(guī)則,就交給/test/data.js來處理,具體如何處理,往下看。
其次,新建一個(gè)./test/data.js的文件,內(nèi)容我就不能直接粘貼了,意思就是通過nodejs來抓取線上的結(jié)果。這樣就完成了動(dòng)態(tài)獲取線上數(shù)據(jù)的功能。
此外,fis-conf.js中還需如下配置,意思是./test和./config兩個(gè)文件夾下的內(nèi)容,打包時(shí)候要按照既定的路徑打包。即 ./test/data.js這個(gè)路徑,打包之后還是./test/data.js這個(gè)路徑。
支持多種編譯模式
這個(gè)需求也是我們開發(fā)中必須的。例如,我們要為上線打包文件時(shí),需要讓js有md5后綴(為了方便緩存),文件要壓縮到最。欢覀円詼y(cè)打包的時(shí)候,就無(wú)需md5后綴(否則一天下來產(chǎn)生很多冗余文件),文件不要壓縮(否則無(wú)法在瀏覽器調(diào)試)。
fis3的文檔中有介紹,我們可以使用fis.media來滿足我們的需求。如下配置,使用fis.media('publish').match配置了js和css的壓縮功能,而解析less的時(shí)候沒有用fis.media
當(dāng)運(yùn)行fis3 release的時(shí)候,fis3只會(huì)匹配沒有配置fis.media的配置項(xiàng),例如解析less功能。當(dāng)運(yùn)行fis3 release publish的時(shí)候,fis3既會(huì)匹配fis.media('publish').match又會(huì)匹配fis.match,即less也解析了、js和css也都?jí)嚎s了。
當(dāng)然,你還可以自己定義很多media,例如fis.media('test')。但是不要用fis.media('dev'),因?yàn)閒is3默認(rèn)的media就是dev,算是個(gè)保留字。
是否使用 npm 生態(tài)
其實(shí)這里不應(yīng)該是一個(gè)問題,不過當(dāng)時(shí)有一個(gè)小小的糾結(jié),就順便在這里記錄一下吧。
解決的問題
我們現(xiàn)在主流的開發(fā)方式,引用 React 一般都是 npm install react --save,然后在代碼中直接 import * as React from 'react'來引用。這就是所謂的“npm 生態(tài)”,即使用 npm 來管理依賴。
但是當(dāng)時(shí)就這個(gè)用法,出現(xiàn)過一個(gè)糾結(jié),即這樣依賴,我們打包的third.js文件中,會(huì)有很多define語(yǔ)句,都是和React相關(guān)的。因?yàn)橛?npm 安裝的 React 也是有好多零散的文件組成的,并不是就一個(gè) React.js。然后,就開始擔(dān)心這么多“冗余代碼”會(huì)不會(huì)導(dǎo)致代碼文件大很多,就開始想其他解決方法(其實(shí)最后根本不是問題)
解決方案
最后想出來的解決方法很有意思,就是要下載一個(gè)react.min.js然后放在如./lib的一個(gè)文件夾中,然后在代碼中使用import * as React from '../../lib/react.min.js'這樣用。
這樣是能解決很多個(gè)define的問題了,因?yàn)闆]必要define了,只有一個(gè)react.min.js文件,還define個(gè)什么勁?
后來
后來,這個(gè)解決方案還是被我否決了,當(dāng)時(shí)也沒想出什么壓倒式的理由,但是有一個(gè)原因——沒人這么用!大家都在基于npm生態(tài),社區(qū)中的寫法基本已經(jīng)固定了,現(xiàn)在卻不這么寫,自己獨(dú)創(chuàng)一個(gè)寫法,那樣會(huì)越走越窄。哪怕會(huì)有那么一點(diǎn)的不完善,我也要按照大家通用的格式來,不要獨(dú)創(chuàng)。
其實(shí)后來想了一下,按照解決方案那種使用react.min.js的方式,也是有很多問題的。例如,開發(fā)模式下也用.min.js那樣就沒有React自帶的提示、警告功能了,萬(wàn)一忽略了什么性能問題,沒有提示和警告,可就麻煩打了。再例如,這樣一來就沒有版本管理了,前端框架更新很快,版本管理很重要。
最后,我們發(fā)下經(jīng)過各種壓縮,最后的third.js都不到100kb,完全滿足我們的要求————這個(gè)年代,真的用不著自己去創(chuàng)新。
系統(tǒng)設(shè)計(jì)(邏輯)
要降低系統(tǒng)設(shè)計(jì)的復(fù)雜度,前端目前最好的方式就是組件化。將系統(tǒng)劃分成若干個(gè)頁(yè)面,然后將每個(gè)頁(yè)面都劃分成若干個(gè)組件,還要抽象出多個(gè)頁(yè)面中都會(huì)用到的通用組件,這是第一步。接下來要看組件和組件之間如何傳遞數(shù)據(jù),即數(shù)據(jù)管理和狀態(tài)管理該如何做。下面我們就從這兩個(gè)方面來分先一下新聞webapp該如何設(shè)計(jì)。
從 router 到 page 再到 component
下圖是一個(gè)最基本的設(shè)計(jì)理念,實(shí)際項(xiàng)目中也是按照這個(gè)來細(xì)化、擴(kuò)展最后落地執(zhí)行的。即,先給頁(yè)面劃分組件,然后組件構(gòu)成頁(yè)面,最后頁(yè)面匹配路由。如下圖:
將這個(gè)落實(shí)到頁(yè)面上,就是這個(gè)效果
但是最后在開發(fā)過程中忽略了一個(gè)問題,就是一些復(fù)雜頁(yè)面(例如新聞NBA頻道頁(yè),用瀏覽器模擬手機(jī)查看效果),光這種“頁(yè)面 - 組件”的形式是不夠的,應(yīng)該在加一個(gè)subpage層,這樣就擴(kuò)展性更好一些了。如下圖:
總結(jié):一個(gè)項(xiàng)目總會(huì)遇到個(gè)別的比較復(fù)雜的頁(yè)面,因此這種page - subpage - component會(huì)更加合理一些,其中的subpage在不需要的時(shí)候省略掉就是了。
智能組件 VS 木偶組件
在 React + Redux 結(jié)合作為前端框架的時(shí)候,提出了一個(gè)將組件分為“智能”和“木偶”兩種
智能組件:它是數(shù)據(jù)的所有者,它擁有數(shù)據(jù)、且擁有操作數(shù)據(jù)的action,但是它不實(shí)現(xiàn)任何具體功能。它會(huì)將數(shù)據(jù)和操作action傳遞給子組件,讓子組件來完成UI或者功能。這就是智能組件,也就是項(xiàng)目中的各個(gè)頁(yè)面。
木偶組件:它就是一個(gè)工具,不擁有任何數(shù)據(jù)、及操作數(shù)據(jù)的action,給它什么數(shù)據(jù)它就顯示什么數(shù)據(jù),給它什么方法,它就調(diào)用什么方法,比較傻。這就是木偶組件,即項(xiàng)目中的各個(gè)組件。
因此,數(shù)據(jù)在page層獲取、數(shù)據(jù)的操作和處理在page層定義,組件就是傻傻的知道執(zhí)行和顯示就行了,各操各的心。這種設(shè)計(jì)也整好符合目前無(wú)論是Vue、augular還是React提倡的基于數(shù)據(jù)驅(qū)動(dòng)的設(shè)計(jì)理念——程序定義好Model和View的關(guān)系,剩下的業(yè)余處理只需要關(guān)心數(shù)據(jù)變化,View的變化由框架自動(dòng)執(zhí)行,無(wú)需像jquery時(shí)代再去手動(dòng)操作DOM。
數(shù)據(jù)管理
下面看一下數(shù)據(jù)在系統(tǒng)中是如何傳遞的。這里的數(shù)據(jù)分為兩種:
第一種可以稱之為“系統(tǒng)數(shù)據(jù)”,和業(yè)務(wù)無(wú)關(guān)的,一般任何系統(tǒng)中都會(huì)有。例如用戶id、用戶頭像、配置信息等,這個(gè)的特點(diǎn)就是符合單例模式,全局共用一套
第二種可以稱之為“業(yè)務(wù)數(shù)據(jù)”,每個(gè)頁(yè)面都可能不一樣。如在娛樂頻道需要的是娛樂新聞列表,而到了軍事頻道就需要軍事新聞的列表了,再到新聞詳情頁(yè)就需要新聞的內(nèi)容了
針對(duì)這兩種不同的數(shù)據(jù),當(dāng)然要分開處理。針對(duì)第一種“系統(tǒng)數(shù)據(jù)”,系統(tǒng)一初始化就立即獲取,然后交給Redux做管理,這也符合Redux的特點(diǎn)。而針對(duì)第二種“業(yè)務(wù)數(shù)據(jù)”,那就什么時(shí)候用,就什么時(shí)候獲取。
代碼架構(gòu)(物理)
使用React + Redux設(shè)計(jì)代碼結(jié)構(gòu),目前方式都比較統(tǒng)一,基本都是按照以下方式來設(shè)計(jì),這些在github等社區(qū)都能找到相似的結(jié)構(gòu)。
以上目錄中,app/components和app/container是開發(fā)中修改最多的目錄。app/container里面定義的都是頁(yè)面,即智能組件,只關(guān)心數(shù)據(jù),功能比較單一,因此結(jié)構(gòu)也比較簡(jiǎn)單
但是針對(duì)組件app/components來說,要顯示樣式,當(dāng)然就需要css和圖片,文件類型比較多。因此,要按照如下方式定義組件
即,用一個(gè)文件夾來表示單個(gè)組件,里面的index.jsx是業(yè)務(wù)和模板代碼,style.less是樣式,img/文件夾放圖片文件。這樣的話,可以把每個(gè)組件都作為一個(gè)整體來管理,而且引用的時(shí)候也比較方便,例如import LoadMore from '../../app/components/LoadMore'就可以了——目錄名即組件的名字。
雖然我沒法將源碼的目錄結(jié)構(gòu)截圖出來分享給大家,但是我們實(shí)際開發(fā)中的目錄結(jié)構(gòu)基本是按照這個(gè)方式來做的,可能就是細(xì)節(jié)上因此會(huì)因?yàn)闃I(yè)務(wù)的問題做了特殊處理,但是設(shè)計(jì)理念上是一樣的。
開發(fā) - 如何多人協(xié)作開發(fā)
上文已經(jīng)描述了一些基本配置和系統(tǒng)設(shè)計(jì)的解決方案,接下來即可進(jìn)入開發(fā)。由于不是一個(gè)人做,因此必須考慮如何高效率的多人協(xié)作開發(fā)。其實(shí)這不是一個(gè)技術(shù)問題,這里就簡(jiǎn)單寫一下這方面的心得體會(huì)吧。
定義階段
提前定義好代碼結(jié)構(gòu),統(tǒng)一各個(gè)文件夾的作用
提前設(shè)計(jì)Router規(guī)則,以及和頁(yè)面的對(duì)應(yīng)關(guān)系
提前抽象出可能在多個(gè)頁(yè)面中通用的組件,創(chuàng)建文件夾(占位置)
討論確定每個(gè)頁(yè)面都如何拆分組件,統(tǒng)一設(shè)計(jì)思路
開發(fā)階段
每人開發(fā)不同的頁(yè)面,遇到頁(yè)面單獨(dú)用的組件,即自行開發(fā);
遇到多頁(yè)面公用的組件,先同步組內(nèi)開發(fā)進(jìn)度,有則直接用,沒有則自己開發(fā);
每裝配好一個(gè)組件,都提交一次代碼,隨時(shí)開發(fā)、隨時(shí)提交、隨時(shí)合并;
心得:如果你要參與一個(gè)重構(gòu)項(xiàng)目,你只需要按部就班發(fā)揮自己的技術(shù)能力即可,按照規(guī)則編碼、測(cè)試、提交代碼等。但是如果你要自己組織、規(guī)劃一次系統(tǒng)重構(gòu),考慮的事情那就太多了。除了頂住外在的壓力之外,還得考慮如何讓這件事兒更快、更穩(wěn)定的運(yùn)行起來。
開發(fā) - 自測(cè)
使用fis3作為構(gòu)建工具,其實(shí)使用fis3 server start即可啟動(dòng)本機(jī)的服務(wù),然后進(jìn)行測(cè)試。但是像新聞這種產(chǎn)品,它的任何頁(yè)面都需要獲取數(shù)據(jù)再展示,因此測(cè)試的時(shí)候需要一些模擬的或者真實(shí)的數(shù)據(jù),這個(gè)fis3也支持,在上文介紹fis3配置的時(shí)候已經(jīng)說明了。
但是這種本機(jī)運(yùn)行、并用fis3動(dòng)態(tài)假數(shù)據(jù)模擬的情況有一個(gè)問題:它沒法模擬登錄的情況,http請(qǐng)求中也沒有登錄狀態(tài)下的那些cookies信息,這就會(huì)影響很多功能的測(cè)試。因?yàn)樾侣劦脑S多功能是需要登錄才能運(yùn)行的,例如個(gè)人收藏、訂閱頻道、評(píng)論、點(diǎn)贊等。
最終想到的一個(gè)辦法是將代碼放在公司內(nèi)部的一臺(tái)測(cè)試機(jī)上,然后通過測(cè)試機(jī)訪問,這樣就可以獲取登錄信息。因此這里介紹一下如何使用fis3將代碼發(fā)布到測(cè)試機(jī)上。fis-conf.js中做如下配置:
配置完了之后,執(zhí)行fis3 release remote,它就會(huì)執(zhí)行編譯,并且將編譯后的文件傳上去。然后再在測(cè)試機(jī)上配置一個(gè)服務(wù),支持頁(yè)面的訪問即可。
開發(fā) - 代碼檢查
代碼檢查是開發(fā)環(huán)境中非常重要的一步,其實(shí)這塊的配置很簡(jiǎn)單,之所以單獨(dú)列出來,就是為了體現(xiàn)它在開發(fā)過程中(特別是多人協(xié)作)的重要性。
項(xiàng)目中使用eslint做檢查,其主要配置文件有兩個(gè)。.eslintignore定義了忽略哪些文件的檢查,例如我們要忽略一個(gè)第三方插件的代碼檢查
還有一個(gè).eslintrc.json定義了代碼的檢查規(guī)則,本項(xiàng)目的檢查規(guī)則相對(duì)比較寬松,配置如下。其配置項(xiàng)的意義,在網(wǎng)絡(luò)上可以輕松查詢到。
最后,我們將檢查代碼的命令封裝進(jìn)package.json中,如下代碼。這樣,在檢查的時(shí)候,只需要運(yùn)行npm run lint這個(gè)簡(jiǎn)單命令即可
目前只是軟性的規(guī)定,在git commit之前必須做檢查,如果開發(fā)人員忽略了,也能將代碼提交上。接下來將考慮將代碼檢查強(qiáng)制做到git-hook里面,即git commit之前必須要檢查通過,否則無(wú)法提交。
打包 & 提測(cè)
上文說過,自測(cè)的時(shí)候,發(fā)布的代碼是未經(jīng)過壓縮、也未加md5后綴的,而且直接將代碼發(fā)布到服務(wù)器的目錄即可,無(wú)需存到指定目錄。但是要打包出一個(gè)目錄,然后將文件提交給測(cè)試人員,就和自測(cè)不一樣了。
首先,打包的文件要壓縮、要加md5后綴(上文講述fis3的配置的時(shí)候已經(jīng)說過);其次,要講文件打包到指定目錄,這里定義將文件打包到./release目錄下;第三,fis3的默認(rèn)release功能還會(huì)將開發(fā)環(huán)境的源文件一起打包了,這些是不需要的(僅僅需要合并出來的代碼即可,合并的代碼在./release/static目錄下)。將以上這些需求一整合,寫一個(gè)復(fù)雜的命令一起放在package.json中
這樣,執(zhí)行npm run publish即可生成一個(gè)./release文件夾,里面包含了最終的模板文件、編譯之后的js和css、以及處理之后的圖片文件。目錄結(jié)構(gòu)如下。最終,將這個(gè)文件夾提交給測(cè)試人員部署即可。每個(gè)公司都有自己的提測(cè)流程,百度內(nèi)部流程這里就不說了。
測(cè)試過程中,qa可能會(huì)有反饋bug,至于如何修復(fù)bug,以及如何進(jìn)行二次開發(fā)和維護(hù),我都寫了一個(gè)說明文檔(僅供百度內(nèi)網(wǎng)訪問),規(guī)定了每個(gè)步驟該如何執(zhí)行。
上線
測(cè)試完了之后要上線,每個(gè)公司的上線步驟也都不盡相同,有的高級(jí)一些,有的low一些,這里就不管了。
上線之后注意如何及時(shí)快速的回滾,這一點(diǎn)很重要。
總結(jié)
洋洋灑灑寫了好多,最后做一個(gè)簡(jiǎn)單的總結(jié)。
系統(tǒng)重構(gòu)的目的永遠(yuǎn)都是為了后面減少開發(fā)成本、提高系統(tǒng)性能和穩(wěn)定性,這是公司或部門需要的結(jié)果。對(duì)于實(shí)際執(zhí)行的個(gè)人來說,參與或發(fā)起重構(gòu)項(xiàng)目,是對(duì)自己如何掌控一個(gè)產(chǎn)品前端設(shè)計(jì)和架構(gòu)的一次很好的機(jī)會(huì),會(huì)對(duì)自己有很大的能力提升。重構(gòu)過程中會(huì)遇到一些預(yù)想不到的問題,思考在過程中解決這些問題,對(duì)自己又是另一方面的能力提升。因此,好的東西,都是雙贏的。
待優(yōu)化
繼續(xù)壓榨性能:無(wú)論是通過資源的懶加載,還是使用Immutable.js做不可變數(shù)據(jù),都要讓性能達(dá)到最優(yōu)
完善一些設(shè)計(jì)不足的地方:例如目前的page - components 改為到 page - subpage - components的方式
接下來
選擇React框架肯定要再試圖往兩個(gè)方向來攻:
服務(wù)器端渲染
React Native
最后
現(xiàn)在一言不合就秀配置打包代碼~