1. 程式人生 > >重構後端模板檔案的一種實踐

重構後端模板檔案的一種實踐

後端的動態模板

Java後端通常會使用ftl(freemarker template language)模板檔案來動態返回前端頁面。這個工作,通常還可以用jspphp檔案來實現。但這些動態模板的實現,通常是在已有的html檔案上對特定的、需要做動態處理的部分做改寫。這對小專案來講沒什麼不對。可如果你的頁面數量足夠多,維護它們將成為一件異常困難的事情。

Nodejs大前端技術

在目前的大前端技術棧下,Nodejs的各種框架讓前端開發變得規矩不少:傳統前端的html+css+js的技術棧的最大問題在於其模組化、組織能力像是一個教學語言,應有的語句控制和程式碼複用的技術,都顯得蒼白無力。

就html的編寫來講,幾乎不存在一種類似函式的複用方式,能夠簡化重複的UI component的生成。你只能不斷地去寫一些重複的、雜亂的程式碼。整體上來講,這不僅難以做後期的維護,也無法輕易地看懂其間的程式碼邏輯。

一句話來講,這些程式碼非常類似於機器程式碼或者彙編程式碼。沒有高階語言的精準控制和抽象層去對程式碼做巨集觀把控。

Pugjs是一個很好的html預處理專案。它的基本想法是:

不要去直接編寫“底層”的html程式碼,而是用自己定義的一套語法去編寫pug檔案。通過這個pug檔案去生成出html程式碼。

特別地,在它的語法中,你不必再寫一大堆的尖括號和與前後呼應的tag。如同Python,僅僅依靠程式碼的對齊方式,就可以自動識別相應的作用域範圍。例如

<div> 
    <ul>
        <li> First tip </li>
        <li> Second tip </li>
        <li> Third tip </li>
    </ul></div>

這樣語義簡單、語法繁瑣的一堆程式碼,在pug下可以簡化為

div
    ul
        li First tip
        li Second tip
        li Third tip

但這還不是最誘人的技術,因為這無非是加入了一些語法糖。最為誘人的是pug提供的函式,它能夠定義一個函式去生成某個元件。

例如,如果你需要定義一組table,每個table僅僅是表頭或者其中一部分的資料不一樣,你該如何處理?傳統的方式當然是複製貼上一堆模板程式碼,然後一個個地去修改裡面的資料。

pug的處理方式就要好太多,完全符合將資料和程式碼分離的思想。定義函式:

mixin leftbox-gen(dataObj)
        table.table
            thead
                tr
                    th(scope="col") #{dataObj.title}
            tbody
                each area in dataObj.areas
                    tr
                        td
                            .box-title #{area.name}
                            ul
                                each subarea in area.subareas
                                    li
                                        a(id=subarea.id, href=subarea.url) #{subarea.name}

這樣就可以根據通過定義json格式的dataObj去引用函式:

+leftbox-gen(cs_leftbox_data)

你通過不同的json資料,就能夠生成不同的table出來。這就實現了程式碼的模組化和以及資料和業務程式碼的分離。要做出新的table component,你只需要改變資料就可以了。

這樣的實現方式在別的高階語言中是很常見的,但是在傳統的前端程式碼中,這常常難以見到。原因就在於,html程式碼更像是沒有抽象層的機器程式碼,只是一大堆的實際操作,而缺少抽象層的高效管理。

前端預處理和後端動態模板的結合

pug這樣優秀的工具,如果能夠用來管理後端的ftl模板當然會相當合適。優秀的語法糖、程式碼模組化、資料和業務邏輯的分離,實在是相當誘人的選擇。

但這樣的理念真要實施在生產程式碼中,特別是用來重構已有的legacy code時,就不大容易了。

例如,pug只能生成html程式碼,且生成出來的位置通常是在一個統一的地方。可ftl程式碼卻分散在各個不同Java工程的不同目錄之下。這兩者很難統一到一起。

或許一個直接的想法是,不如直接把所有的ftl都放到一個地方,這樣就不用把模板語言分散到各個不同專案的不同資料夾裡,而難以維護。

但這種方案帶來的一個麻煩是,如果真的把後端的ftl檔案挪動了位置,那麼後端程式碼的介面部分就不得不做修改。而這樣的介面部分其數量並不少。既要做出大量的修改,還要保證它們的正確性,並不是一件輕鬆的事情。

經過大量的思考和嘗試得出的一個解決方案是:

使用Pugjs生成出統一的ftl檔案,放在同一個公共資原始檔夾下。讓每一個具體專案下的ftl檔案中,直接include這個公共資原始檔夾中ftl內容。

這種做法的一個精妙之處是:它將ftl檔案當作函式介面來使用。後端Java程式碼呼叫ftl檔案可以看作是函式呼叫。而函式實現並不需要直接放在這個ftl檔案裡,而是可以放在別的地方做引用。這就把實現和呼叫部分,通過一個單獨的檔案分離開了。

這裡雖然處理的是後端模板檔案和前端的一個結合,但其思想可以利用在別的地方。如果一個模板檔案具備了include功能,便可以把模板檔案本身當作介面,從而將實現與定義分離。

近期回顧

如果你喜歡我的文章或分享,請長按下面的二維碼關注我的微信公眾號,謝謝!

更多資訊交流和觀點分享,可加入知識星球: