首頁  >  文章  >  web前端  >  關於前端模板引擎的問題詳解

關於前端模板引擎的問題詳解

PHP中文网
PHP中文网原創
2017-06-22 11:03:041748瀏覽

 前端模板引擎需要有開發時的透明性

#透明性即指我在搭建好開發環境後,隨手寫程式碼隨手刷新瀏覽器就能看到最新的效果,而不需要額外執行任何指令或有任何的等待過程。

所以一切都依賴編譯過程的模板引擎並不適合前端使用,編譯只能是模板引擎的特性,而不能是使用的前提

更嚴格地說,使用FileWatch等手段進行文件變更檢測並自動編譯也不在我的考慮範圍之內,因為這會造成額外的等待,

由此可以推出,前端的模板引擎應該是具備可在純前端環境中解析使用的能力的。

前端模板引擎要有良好的運行時調試能力

由於用戶行為的不確定性、執行環境的不確定性、各種第三方腳本的影響等,前端很難做到完全的錯誤處理和跟踪,這也導致前端必然存在需要直接在線上排查問題的情況

而當問題出現在模板引擎這一層時,就需要模板引擎提供良​​好的調試能力

一般來說,編譯後產生的函數的調試能力是弱於原先手動編寫的模板片段的,因為自動生成的函數基本上不具備可讀性和可斷點追蹤性

因此在這一點上,一個供前端使用的模板引擎應該具備在特定情況下從“執行編譯後函數獲取HTML”換回“解析原模板再執行函數獲取HTML”的模式,即應該支援在兩種模式間切換

或更好地,一個強大的前端模板引擎編譯生成的函數,可以使用Source Map或其它自定義的手段直接映射回原始模板片段,不過現在沒有什麼模板引擎實現了這一功能

前端模板引擎要對文件合併友好

在HTTP/2普及之前,文件合併依舊是前端性能優化中的一個重要手段,模板作為文件的一部分,依舊是需要合併的

在提供編譯功能的模板引擎中,我們可以使用編譯的手段將模板變為JavaScript源碼,再在JavaScript的基礎上做文件合併

但是如果我們出於上文所說的調試能力等原因希望保留原始模板片段,那就需要模板引擎本身支持模板片段合併為一個文件了

#大部分僅支援將一段輸入的字串作為模板解析的引擎並不具備這一能力,他們天生並不能將一整個字符串切分為多個模板片段,因而無法支持模板片段層面上的文件合併

需要實現對檔案合併的支持,最好的方法就是讓範本的語法是基於「片段」的

前端範本引擎要擔負XSS的防範

從安全性上來說,前端對XSS的控制是有嚴格要求的

前端對XSS的防範比較合適的方法是使用「預設轉義」的白名單式策略

基於此,一個合理的模板引擎是必須支援預設轉義的,即所有資料的輸出都預設經過escape的邏輯處理,將關鍵符號轉為對應的HTML實體符號,以從根源杜絕XSS的入侵路徑

當然並不是所有的內容都必須經過轉義的,在系統中免不了有對用戶輸入富文本的需求,因此需要支持特定的語法來產生無轉義的輸出,但時時注意無轉義輸出才是特例,預設值必須是轉義輸出的

前端模板引擎要支援片段的複用

#這並不是前端模板引擎的需求,事實上任何模板引擎都應該支援片段的複用,後端如Velocity、Smarty等無不擁有此功能
所謂片段復用,應該有以下幾個層次的應用:

  1. 一個片段可以被引入到另一處,相當於一個變數到處用的效果

  2. 一個片段被引入時,可以向其傳遞不同的數據,相當於一個函數到處用的效果

  3. #一個片段可以被外部替換,但外部不提供此片段的話保持一個預設的內容,類似設計模式中的策略模式

滿足第1和第2點的模板引擎並不少,而滿足第3點的前端模板引擎卻不多見,而後端的Razor、Smarty等都具備此功能

前端範本引擎要支援資料輸出時的處理

所謂資料輸出時處理,指一個資料要在輸出時做額外的轉換,最常見的如字串的trim操作,比較技術性的如markdown的轉換等

誠然資料的轉換完全可以在將資料交給模板引擎前就透過JavaScript的邏輯處理完,但這會導致不少有些醜陋又有些冗餘的程式碼,對邏輯本身的複用性也會造成負面的影響

通常模板引擎對資料做額外處理會使用filter的形式實現,類似bash中的管道的邏輯。 filter的實作與註冊也會有不同的設計,如mustache其實註冊的是fitler工廠,而有些模板引擎則會直接註冊filter本身,不同設計有不同的考量點,我們很難說誰好誰壞 

但是,模板引擎支援資料的輸出處理後,會另我們在編碼過程中產生一個新的糾結,即哪些資料處理應該交由模板引擎的filter實現,哪些應該在交給模板引擎前由自己的邏輯邏輯實作。這個主題展開來又是一篇長長的論述,於當前的話題無關就略過吧

前端模板引擎要支持動態數據

##在開發過程中,其實有不少資料並不是靜態的,如EmberJS就提供了Computed Property這樣的概念,Angular也有類似的東西,Backbone則可以透過重寫Model的get方法來變相實作

雖然ES5在語言層面上直接提供了getter的支持,但我們在前端開發的大部分場景下依舊不會使用這一語言特性,而會選擇將動態的資料封裝為某種物件的get等方法

而模板引擎在將資料轉換為HTML片段的過程中,同樣應該關注這一點,對這些動態計算的資料有良好的支援

說得更明白一些,模板引擎不應該僅僅接受純物件(Plain Object)作為輸入,而應該更開放地接受類似帶有get方法的動態的資料

#一個比較合理的邏輯是,如果一個物件有一個get方法(模板引擎決定這個接口),則資料透過此方法獲取,其它情況下視輸入的物件為純物件(Plain Object),使用標準的屬性取得邏輯

前端範本引擎要與非同步流程嚴密結合

一個很常見的例子是,我們有一個AMD模組存放了全域使用的常數,模板引擎需要使用這些常數。當然我們可以在使用模板引擎之前讓JavaScript去異步獲取這一模組,然後將常量作為數據傳遞​​給模板引擎,但這是一種業務與視圖相對耦合的玩法,出於強迫症我並不覺得這是一個漂亮的設計,所以我們希望


  • 模板的輸出本身變成異步的方法,而不再像現在一樣直接回傳字串

  • #分析範本對非同步操作的依賴,整個字串的拼接邏輯被打斷成多個非同步

  • 非同步是需要等待的,且等待是未知的,從效能上考慮,是否需要考慮Stream式的輸出,以便完成一段提供一段

  • 是提供內建的固定幾種非同步邏輯,還是基於Promise支援任何自訂的非同步邏輯,在複雜度和實用性上作出平衡

至今我還沒有完全明確模板與異步結合的方式和接口,這個話題也沒辦法繼續深入探討了

前端範本引擎要支援不同的開發模式

前端發展至今,有許多不同的開發模式,例如:


  • 最普通的HTML頁面,使用DOMContentLoaded等事件加入邏輯,特定互動下局部刷新頁面

  • 採用傳統的MVC模型進行單頁式開發

  • #使用MVVM方式以資料為核心,資料與視圖方向綁定進行開發

  • #基於Immutable Data進行資料比對Diff轉DOM更新的開發(其中可能有Virtual DOM的引入)

一個模板引擎要能支援這麼多不同的模式是一個非常大的挑戰,特別是對雙向綁定的支援特別突出。到目前為止幾乎所有的支援雙向綁定的開發框架都自帶了專用的模板引擎,這是因為雙向綁定對模板有兩大要求:


    ##能夠從範本中擷取「此範本對哪些資料有依賴」的元資訊
  • 能夠知道一個資料變更引擎的是範本的哪一塊,而不至於整個刷新
  • 而通用模板引擎很少提供這兩個特性,所以沒辦法對不同的前端開發模式進行全面到位的支援
從模板引擎本身的實現上來說,一種方法是直接將模板解析後的類似AST的結構暴露出去,供其他框架合理地處理,同時提供對模板局部的刷新功能(也可與前面所說的模板片段一起考慮),但是大部分模板引擎為了性能等考慮,是不會解析出類似AST的語法結構來的


前端模板引擎要有實例間的隔離

在大型的前端項目,特別是在單頁式的項目中,會有完全未知個數的模板片段同時存在,如果這些片段是帶有名稱(出於復用的考慮)的,就很容易造成名稱上的衝突

對於同一層級的邏輯(如大家都是業務層程式碼,或大家都是控制層程式碼),名稱衝突是可以透過一些開發時的約定來解決的。但不同層之間,由於封裝性的要求,外部不應該知道一些僅內部使用的片段的名稱,此時如果不幸有名稱與其它層有衝突,會讓情況變得比較麻煩,這類問題甚至都不容易跟踪,往往會導致大量的精力和時間的浪費

因此,一個好的模板引擎應該是多實例的,且不同實例間應該相互具備隔離性,不會出現這種不可預期的衝突

將這個主題再往深地研究,就會發現單純的隔離是不夠的,不同層間除了不衝突的需求,同樣還有片段復用的需求,我們還會需要不同模板實例間可以開放一些固定的片段共享,因此模板引擎各個實例的關係是一種組合依賴但又具備基本的封裝和隔離的狀態說了這麼多。

以上是關於前端模板引擎的問題詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn