本文轉載於:猿2048網站⇒關於模板引擎一php
前端模板引擎須要有開發時的透明性
透明性即指我在搭建好開發環境後,隨手寫代碼隨手刷新瀏覽器就能看到最新的效果,而不須要額外地執行任何命令或有任何的等待過程。前端
因此一切依賴編譯過程的模板引擎並不適合前端使用,編譯只能是模板引擎的一個特性,而不能是使用的前提後端
更嚴格地說,使用FileWatch等手段進行文件變動檢測並自動編譯也不在個人考慮範圍以內,由於這會形成額外的等待,設計模式
由此能夠推出,前端的模板引擎應該是具有可在純前端環境中解析使用的能力的。瀏覽器
前端模板引擎要有良好的運行時調試能力
因爲用戶行爲的不肯定性、執行環境的不肯定性、各類第三方腳本的影響等,前端很難作到徹底的錯誤處理和跟蹤,這也致使前端必然存在須要直接在線上排查問題的狀況安全
而當問題出如今模板引擎這一層時,就須要模板引擎提供良好的調試能力性能優化
通常來講,編譯後生成的函數的調試能力是弱於原先手動編寫的模板片段的,由於自動生成的函數基本不具有可讀性和可斷點跟蹤性bash
所以在這一點上,一個供前端使用的模板引擎應該具有在特定狀況下從「執行編譯後函數獲取HTML」換回「解析原模板再執行函數獲取HTML」的模式,即應該支持在兩種模式間切換markdown
或者更好地,一個強大的前端模板引擎編譯生成的函數,可使用Source Map或其它自定義的手段直接映射回原模板片斷,不過如今並無什麼模板引擎實現了這一功能框架
前端模板引擎要對文件合併友好在HTTP/2普及以前,文件合併依舊是前端性能優化中的一個重要手段,模板做爲文件的一部分,依舊是須要合併的
在提供編譯功能的模板引擎中,咱們可使用編譯的手段將模板變爲JavaScript源碼,再在JavaScript的基礎上作文件合併
可是若是咱們出於上文所說的調試能力等緣由但願保留原模板片斷,那就須要模板引擎自己支持模板片斷合併爲一個文件了
大部分僅支持將一段輸入的字符串做爲模板解析的引擎並不具有這一能力,他們天生並不能將一整個字符串切分爲多個模板片斷,於是沒法支持模板片斷層面上的文件合併
須要實現對文件合併的支持,最好的辦法就是讓模板的語法是基於「片斷」的
前端模板引擎要擔負XSS的防範
從安全性上來講,前端對XSS的控制是有嚴格要求的
前端對XSS的防範比較合適的方法是使用「默認轉義」的白名單式策略
基於此,一個合理的模板引擎是必須支持默認轉義的,即全部數據的輸出都默認通過escape的邏輯處理,將關鍵符號轉爲對應的HTML實體符號,以從根源上杜絕XSS的入侵路徑
固然並非全部的內容都必須通過轉義的,在系統中免不了有對用戶輸入富文本的需求,所以須要支持特定的語法來產生無轉義的輸出,但時刻注意無轉義輸出纔是特例,默認狀況下必須是轉義輸出的
前端模板引擎要支持片斷的複用這並非前端模板引擎的需求,事實上任何模板引擎都應該支持片斷的複用,後端如Velocity、Smarty等無不擁有此功能
知足第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),使用標準的屬性獲取邏輯
前端模板引擎要與異步流程嚴密結合
至今我尚未徹底明確模板與異步結合的方式和接口,這個話題也沒辦法繼續深刻探討了
前端模板引擎要支持不一樣的開發模式前端發展至今,有不少不一樣的開發模式,好比:
而通用模板引擎不多提供這兩個特性,因此沒辦法對不一樣的前端開發模式進行全面到位的支持
從模板引擎自己的實現上來講,一種方法是直接將模板解析後的相似AST的結構暴露出去,供其餘框架合理地處理,同時提供對模板局部的刷新功能(也可與前面所說的模板片斷一塊兒考慮),可是大部分模板引擎爲了性能等考慮,是不會解析出相似AST的語法結構來的
前端模板引擎要有實例間的隔離
在大型的前端項目,特別是單頁式的項目中,會有徹底未知個數的模板片斷同時存在,若是這些片斷是帶有名稱(出於複用的考慮)的,就很容易形成名稱上的衝突
對於同一層級的邏輯(如你們都是業務層代碼,或者你們都是控件層代碼),名稱衝突是能夠經過一些開發時的約定來解決的。但不一樣層之間,因爲封裝性的要求,外部不該該知道一些僅內部使用的片斷的名稱,此時若是不幸有名稱與其它層有衝突,會讓狀況變得比較麻煩,這類問題甚至都不容易跟蹤,每每會致使大量的精力和時間的浪費
所以,一個好的模板引擎應該是多實例的,且不一樣實例間應該相互具有隔離性,不會出現這種不可預期的衝突
將這個話題再往深地研究,就會發現單純的隔離是不夠的,不一樣層間除了不衝突的需求,一樣還有片斷複用的需求,咱們還會須要不一樣模板實例間能夠開放一些固定的片斷共享,所以模板引擎各個實例的關係是一種組合依賴但又具有基本的封裝和隔離的狀態說了這麼多。