滬江網校前端架構漫談

做者: 將來
本文轉自互聯網技術聯盟(ITA1024)技術分享實錄css

正文以下

沒有統一架構的時候是怎樣的一種狀況?

起初前端是沒有架構的,你們只是在完成一個一個的頁面。咱們來看看會發生什麼。前端

  • A同事是一個很是有意思的人,他喜歡把跟這個頁面相關的全部的JS都寫在同一個文件裏面。嗯,傳說中2000行代碼的JS文件就是這麼出來的。react

  • B同事是一個對技術比較有追求的人。他以爲模塊化不錯,因此他在本身作的頁面裏選用了requireJS。看上去不錯哦,巧的是C同事也是一個對技術有追求的人,可是他不喜歡AMD的規範,因此他支持國貨seaJS,哦,他還在裏面使用了他喜歡的模版引擎Jade。webpack

嗯,同一個網站,每一個頁面的技術選擇徹底不同的。別忘了,網站是須要維護的,修Bug阿,改需求啊。有一天B同事跑去負責C同事作的那個頁面的需求改動,當他看到那些他不熟悉的技術時,心裏是極度崩潰的。程序員

  • D同事玩的就比較高級了,他喜歡寫es6,也用sass。這就要求不管在開發的時候仍是發佈的時候代碼都要先編譯,並且顯然你是不可能每次都是手動去作這個事情的。這就是他對工程化有需求了。es6

這個時候他極可能選擇放棄,或者妥協(只使用少部分構建工具很好支持的功能),畢竟要實現一套完整的工程化是很花時間的事情(即便只是支持他本身的頁面),而程序員的時間每每會被業務需求所淹沒。畢竟以單我的和單個頁面的單位來看,工程化這個東西是得不償失的,若是以團隊和整個系統去看那就不同了。web

其實到這裏就能夠看出來,我的所使用的技術的天花板每每會被整個團隊的現狀所制約。npm

架構是否是必須的?

上面描述的是沒有架構的時候發生的狀況,這些狀況看上去固然都不太好,可是若是跳出前端這個角色,咱們怎麼去描述說這些問題會形成的影響,反過來的意思就是,若是有一個統一架構可以帶來的好處。redux

回答出這個問題,能夠解決兩方面的困擾。瀏覽器

第一是說服大團隊裏的其它角色前端架構這件事情的重要性(在如今的大環境下,這個其實很重要);

第二是本身要時刻記住架構的目的,可以不忘初心,不沉迷於形式和概念。

如今回過頭來看看,

架構的目的是什麼?

答案是提高質量和效率。

沒有架構的狀況下,新技術沒法獲得引入,技術沒法統一,使得團隊的總體技術能力沒法獲得提高,也沒法提供技術上的通用解決方案,從團隊的角度來考量的話,效率是很是低下的。

同時,由於技術過於陳舊,再加上代碼沒有統一規範,致使碰到頁面業務邏輯比較複雜,或者對老頁面進行維護的時候,產生Bug的機率很是高,產品質量堪憂。

架構應該怎麼玩?

上面講到,架構的目的是提高質量和效率。那咱們看看架構應該作到哪些方面才能實現這個目的。

  • 架構是一個抽象的過程,它是架構師根據本身的經驗對大量具體的業務項目進行分析,發現其中的規律,抽象出具體的規範,最終又應用於具體的業務項目中去。好比常說的MVVM就是一種規範。

  • 要把跟業務無關的問題都在架構層面處理掉。好比代碼壓縮,打包這種工程化的問題都要在架構層面統一解決的。要作到業務的歸業務,架構的歸架構。

  • 架構要考慮到能夠方便團隊成員提供和使用通用技術解決方案。好比分頁組件這種。

  • 架構設計的時候要綜合考慮當前的主流技術跟本身業務系統的實際狀況。由於前端正處在高速發展,各類新技術,工具,插件,框架層出不窮,這個時候要特別謹慎,有時候一個坑跳下去,就呵呵了。

滬江網校如今的架構是怎麼樣的?

基於以上原則,在搭建架構的時候,通過討論和嘗試,咱們最終肯定出4個方向,模塊化,組件化,工程化,規範化。(你也看出來了,大方向是跟主流走的,太陽底下沒有新鮮事啊。)

說了這麼多虛的^_^,下面來點乾貨。

第一點-工程化:

構建工具用的是webpack,發佈系統用的是jekins。

構建這裏是分開發環境和生產環境。開發環境須要提供jsmap, css map,livereload等開發時候須要的功能,而生產環境須要壓縮,打包,靜態資源文件名添加hash等功能的。這裏插一句,若是要啓動開發環境,只須要 npm start。

第二點-模塊化:

如今都是commonJS當道了,因此選擇es6+ babel。這裏順便提下咱們使用的框架,PC端knockout(爲了支持IE7), 觸屏端和hybrid端redux+react。

第三點-組件化:

這一塊咱們是作的挺完全的,也思考了不少。

  • 咱們的頁面是由一顆組件樹組成的。看下圖,invitationActivity表明了一個頁面,components下面的每個文件夾都表明一個組件。每一個組件包含本身須要的js,css,image等資源。

clipboard.png

  • 保證組件的封閉性。由於JS方面是模塊化的,在css方面咱們也引入了cssmodule來作到這點。

  • 組件的功能界限問題。也就是什麼是應該在組件內部實現,什麼是應該由組件的調用者來實現的。看下圖,下面這個界面會封裝成一個業務組件,由於不少頁面上都會有這個組件,因此在咱們的系統裏面,它是被看成一個公用組件的。順便提下,這個組件自己是由多個子組件組成的。

clipboard.png

如今有兩個問題須要考慮下:

  1. 爲了顯示熱門詞彙有哪些熱詞,須要調接口從後臺獲取。那在哪裏去調用接口呢,是組件自己去調用,仍是由使用者傳進來。

  2. 如今點擊搜索按鈕,須要跳轉到搜索結果頁(還有可能要打點)。那完成這些操做的代碼寫在哪裏呢?是直接寫在組件裏面仍是由調用者傳入,由組件在相應的時機調用傳入的函數。

這就是組件的功能界限問題。咱們的作法是組件只負責跟UI顯示相關的部分,全部業務邏輯都不屬於組件自己的功能。

根據這個原則,咱們來回答上面的問題。

  1. 組件只負責顯示熱詞,至於具體有哪些熱詞,由它的調用者傳入。

  2. 組件只知道搜索按鈕被點擊了,至於按鈕被點擊具體要作些什麼,它是不知道的,它能作的就是調用傳給它的回調函數。

備註:關於組件的功能界限問題咱們也思考了很長時間,而且作過不一樣的嘗試。好比把 點擊搜索按鈕要作的事情放在組件裏面本身作怎麼樣呢,後來發現不一樣的頁面上點擊搜索按鈕須要打點的關鍵字是不同的,這時候你若是把組件寫死了就無法重用 這個組件了。其中關於接口調用是否是要寫在組件內部的問題更是一度相持不下,彷佛兩邊都有點道理。後來碰到一個真實的事情就是由於接口調用都寫在組件裏 面,致使同一個接口在某個頁面上被調用了兩次。當這件事情發生以後,天平彷佛往另一邊傾斜了點。

  1. 通常組件化開發以後,咱們會碰到兩個方面的問題。

第一個問題是咱們去看別人的代碼的時候,沒辦法方便的知道這個頁面的組件樹是怎麼組成的,以及每一個組件須要哪些數據。

第二個問題是當組件樹的層次很深的時候,父子組件間參數的傳遞會很是繁瑣。並且一旦須要增長或刪減掉某個參數的時候,整個父組件到根組件路徑上全部組件參數的傳遞都要修改。

關於第二個問題,也就是父子組件之間參數傳遞的問題,我舉個例子來詳細說明。假設如今組件樹的結構是這樣的。

A組件全部子組件加起來須要的參數是9個,那麼調用A組件的寫法是

<Aa1= 「1」 a2=「2」 … a9=「9 />

而後在A組件內部,A組件自己只須要參數a1,其它的八個參數是被它的子組件B1,B2消費的。那麼A組件內部的寫法大概是這樣的。

<B1a2=「2」 a3=「3」 a4=「4」 a5=「5」 />,<b2 a5=「5」 a6=「6」 a7=「7」 a8=「8」 a9=「9」 />

B1組件自己不須要參數,四個參數都是被子組件C1,C2消費。那麼B1組件內部的寫法大概是這樣的。

<C1a2=「2」 a3=「3」 />,<C2a4=「4」 a5=「5」 />

這個時候已經能夠看出來,若是C1須要增長或者刪減一個參數,從組件自己C1到根組件A之間的全部組件都須要改動。想象一下當組件樹的橫向和縱向的層次都變的很是深的時候,這個時候每一個組件的參數傳遞都會變的很是龐大並且混亂。

若是要把一個組件的位置換一下的話,要改變的地方之多,也是讓人很是頭疼的。咱們想了一個方案來同時解決這兩個問題,看下圖,

clipboard.png

咱們每一個頁面都有一個param.js文件,能夠看到從param.js裏面能夠清晰的看到當前這顆組件樹的結構,以及每一個組件本身須要的參數。而在組件內部,寫法也至關簡單,以A組件內部爲例,組件內部的寫法是這樣的,

<B1{…B1_param} />,<B2 {…B2_param} />

能夠看到,這樣的話,不管是增減參數仍是移動某個組件,都會變的很是簡單。

因爲咱們對組件功能界限的定義是隻負責UI相關的功能,全部的業務邏輯都是從調用者傳遞過的。也便是寫在param.js。因此param.js文件是很是重要的一個文件,裏面基本包涵了這個頁面全部業務處理邏輯。

很顯然,隨着頁面業務邏輯變的複雜,param.js將會變得愈來愈大。不要緊,把不一樣的組件參數分拆到不一樣的js文件裏面去實現,而後建個params文件夾把它們組織起來。

第四點-規範化:

  • JS語法檢查選用了eslint。

  • 項目目錄結構很是清晰。當進行開發的時候,哪些代碼應該放到哪裏都進行了明確的規定,而且每一個文件的功能都儘可能清晰而且單一。

頂層目錄結構以下圖:

clipboard.png

  1. src文件夾存放的是全部的的源代碼和其餘靜態資源(好比圖片,iconfont)。

  2. dist文件夾存放的是全部編譯後的代碼。

  3. build文件夾存放的是全部工程化所須要的代碼。

  4. document文件夾固然存放的文檔。

下面重點看下src目錄結構,以下圖:

clipboard.png

  1. app文件夾裏的每個子文件夾表明了一個頁面,每一個頁面所用到的全部靜態資源都存放在這個子文件下面(除了引用的公共資源之外),構建的時候,每一個子文件夾會生成本身的靜態資源供頁面引用。

  2. common文件夾裏面的全部代碼在構建的時候會單獨生成js文件和css文件供頁面引用。因此一個頁面會引用兩個js和兩個css.裏面存放的是每一個頁面都會用到的一些共用資源。好比觸屏端使用了react,那麼跟react相關的那些包就會放在common裏面。

  3. components文件夾裏面存放的是共用組件,每個子文件夾表明了一個組件。有多是通用的功能組件,好比分頁組件,Loading組件,ModalDialog組件。也有多是一個通用的業務組件,好比站點通用頭部,通用footer,通用分享組件。注意,在其餘地方引用這些組件時,是不須要寫相對路徑的,直接寫組件名字就能夠了,好比import pager from ‘pager’。這樣對使用者更方便。

  4. lib文件夾存放的是通用的js類庫。好比檢測瀏覽器用的browserDetect.js,處理日期用的dateUtil.js。一樣的,在其餘地方須要引入這些JS時,也不須要寫相對路徑,直接寫JS的名字就能夠了。好比import{isIE} from ‘browserDetect’。

  5. style文件夾裏面存放的一些公用的sass資源。好比function,mixing, variable。其餘的sass文件須要引入這些資源的時候,使用方式跟使用通用js同樣,直接@import 「base.scss"便可。

寫在最後

滬江網校的架構纔剛剛有個雛形,後面還有更多的功能會加進來,好比腳手架(等到架構更成熟的時候在出一套完整的),NodeJS中間層(在大方向上已經達成統一),前端監控系統等。

架構是個不斷完善的過程,而把架構尤爲是跟規範相關的部分落實到具體業務系統裏面更是個團隊不斷磨合的過程。它最終考驗的,同時也是最終磨合出來的是團隊的成熟度。

謝謝你們。

clipboard.png

clipboard.png

iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、噹噹開售。

相關文章
相關標籤/搜索