本文同步更新在: https://github.com/whxaxes/blog/issues/4 ,在 github 看文章顯示效果會更好一些。
前言
不知不覺就很長時間沒造過什么輪子了,以前一直想自己實現一個模板引擎,只是沒付諸於行動,最近終於在業余時間里抽了點時間寫了一下。因為我們的項目大部分用的是 swig 或者 nunjucks ,於是就想實現一個類似的模板引擎。
至於為什么要做這么一個東西?基本上每一個做前端的人都會有自己的一個框架夢,而一個成熟的前端框架,模板編譯能力就是其中很重要的一環,雖然目前市面上的大部分框架 vue、angular 這些都是屬於 dom base 的,而 swig nunjucks ejs這些都是屬於 string base 的,但是其實實現起來都是差不多的。不外乎都是 Template
=parse=> Ast
=render=>String
。
再者,做一個模板引擎,個人感覺還是對自身的編碼能力的提升還是很有幫助的,在性能優化、正則、字符解析上尤為明顯。在日后的業務需求中,如果有一些需要解析字符串相關的需求,也會更得心應手。
功能分析
一個模板引擎,在我看來,就是由兩塊核心功能組成,一個是用來將模板語言解析為 ast(抽象語法樹)。還有一個就是將 ast 再編譯成 html。
先說明一下 ast 是什么,已知的可以忽略。
抽象語法樹(abstract syntax tree或者縮寫為AST),或者語法樹(syntax tree),是源代碼的抽象語法結構的樹狀表現形式,這里特指編程語言的源代碼。樹上的每個節點都表示源代碼中的一種結構。之所以說語法是“抽象”的,是因為這里的語法並不會表示出真實語法中出現的每個細節。比如,嵌套括號被隱含在樹的結構中,並沒有以節點的形式呈現;而類似於if-condition-then這樣的條件跳轉語句,可以使用帶有兩個分支的節點來表示。
在實現具體邏輯之前,先決定要實現哪幾種 tag 的功能,在我看來,for
,if else
,set
,raw
還有就是基本的變量輸出,有了這幾種,模板引擎基本上也就夠用了。除了 tag,還有就是 filter 功能也是必須的。
構建 AST
我們需要把模板語言解析成一個又一個的語法節點,比如下面這段模板語言:
<div>
{% if test > 1 %}
{{ test }}
{% endif %}
</div>
很明顯,div 將會被解析為一個文本節點,然后接着是一個塊級節點 if ,然后 if 節點下又有一個變量子節點,再之后有是一個