關於模板引擎一

来源:http://www.cnblogs.com/moneyss/archive/2017/06/21/7060641.html
-Advertisement-
Play Games

前端模板引擎需要有開發時的透明性 透明性即指我在搭建好開發環境後,隨手寫代碼隨手刷新瀏覽器就能看到最新的效果,而不需要額外地執行任何命令或有任何的等待過程。 所以一切依賴編譯過程的模板引擎並不適合前端使用,編譯只能是模板引擎的一個特性,而不能是使用的前提 更嚴格地說,使用FileWatch等手段進行 ...


 

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

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

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

更嚴格地說,使用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的語法結構來的

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

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

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

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

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近使用vue2.0重構項目, 需要實現一個分頁的表格, 沒有找到合適的分頁組件, 就自己寫了一個, 效果如下: 該項目是使用 vue-cli搭建的, 如果你的項目中沒有使用webpack,請根據代碼自己調整: 首先新建pagination.vue文件, 所有組件的代碼都寫在這裡, 寫這樣的組件並沒 ...
  • 1.javascript的typeof返回哪些數據類型 alert(typeof [1, 2]); //object alert(typeof 'leipeng'); //string var i = true; alert(typeof i); //boolean alert(typeof 1); ...
  • 在js中,字元串轉為數字類型是比較常見的,平時用的比較多的是parseFloat和parseInt這兩個方法。當然,除了這個方法之外還有一個Number;都是轉為數字類型,有什麼差別? 可以簡單的說Number的局限性更大。也就是說Number比parseFloat和parseInt對字元串的要求更 ...
  • 上一章節我們說到,線性路徑的繪製,主要利用movoTo(),lineTo()等方法,當然 Canvas 2D API 也提供了虛線的繪製方法,CanvasRenderingContext2D.setLineDash(); 下麵我們就來看看虛線的繪製方法 語法 參數 segments: 一個Array ...
  • 關於px、pt和em的區別,自己有時候也會糾結到底該用什麼單位,今天特意查了一些文章,下麵這篇雖然很久遠了,但解釋的比較全面,轉載收藏之。點擊查看原文(原網址已失效,這是其他站點) 這裡引用的是Jorux的“95%的中國網站需要重寫CSS”的文章,題目有點嚇人,但是確實是現在國內網頁製作方面的一些缺 ...
  • 網頁中有很多個標簽,使用jQuery可以快速找到指定id或者class的標簽;jQuery的篩選功能很強大,還可以找父親、兄弟、上一個、下一個等等。 ...
  • 學習vue和nodejs的過程當中,涉及到了axios,今天為了測試,寫了get和post兩個方法來跟node服務端交互,結果因為header和參數弄了好久,在此記錄一下,同時分享; 由於剛接觸axios,在測試方法中,寫的都是很簡單的東西,不過能夠實現基礎功能,大神看到的話..非常歡迎指導.. / ...
  • 一、HyperText Markup Language 內容,html是弱代碼語言,代碼編寫不嚴謹 1、超鏈接 <a href="#">超級鏈接(anchor)</a> 寫超鏈接的href地址的時,要註意是否有寫相應的解析協議,沒有設置協議時,按照預設的本地文件的文本協議 https,http,郵件 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...