Java後端一般會使用ftl
(freemarker template language)模板文件來動態返回前端頁面。這個工做,一般還能夠用jsp
、php
文件來實現。但這些動態模板的實現,一般是在已有的html文件上對特定的須要作動態處理的部分作改寫。這對小項目來說沒什麼不對。可若是你的頁面數量足夠多,維護它們將成爲一件異常困難的事情。php
在目前的大前端技術棧下,Nodejs的各類框架讓前端開發變得規矩很多。個人一個理解是,傳統前端的html+css+js的技術棧的最大問題在於其模塊化、組織能力像是一個教學語言,應有的語句控制和代碼複用的技術,都顯得蒼白無力。css
就html的編寫來說,幾乎不存在一種相似函數的複用方式,可以簡化重複的UI component的生成。你只能不斷地去寫一些重複的、雜亂的代碼。總體上來說,這不只難以作後期的維護,也沒法輕易地看懂其間的代碼邏輯。html
一句話來說,這些代碼很是相似於機器代碼或者彙編代碼。沒有高級語言的精準控制和抽象層去對代碼作宏觀把控。前端
Pugjs
是一個很好的html預處理項目。它的基本想法是:json
不要去直接編寫「底層」的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
提供的函數,它可以定義一個函數去生成某個組件。jsp
例如,若是你須要定義一組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
功能,即可以把模板文件自己看成接口,從而將實現與定義分離。