blog

テンプレート・エンジンの仕組み

出力は公式のものと同じです。次のif文のように、どのようなJS文でもこの方法で表示することができます:...

Sep 21, 2020 · 3 min. read
シェア

原理は正規置換+文字列スプライシングで、ejsを例にとると、具体的な手順は以下のようになります:

  1. テンプレート・ファイルを読み込んで元の文字列を取得
  2. 正規置換<% %> <%= %>
  3. コード形式にスプライスされた文字列
  4. new 関数で文字列を関数に変換
  5. 関数は

プレビュー

index.htmlに以下のような内容を書くのも悪くないでしょう:

<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="UTF-8" />
 <title>EJS</title>
 </head>
 <body>
 <h2><%=title %></h2>
 <p><%=date%></p>
 <ul>
 <%arr.forEach(item=>{%><li><%=item%></li><%})%>
 </ul>
 <div>
  <%=obj.name%>age:<%=obj.age%>
 </div>
 </body>
</html>

まずはネイティブejsで出力をテストしてみましょう:

const fs = require('fs')
const ejs = require('ejs')
const data = {
 title: 'EJS ',
 date: new Date(''),
 obj: { name: ' ', age: 10 },
 arr: [1, 2, 3, 4, 5],
}
const tpl = fs.readFileSync('index.html', 'utf-8')
const html = ejs.render(tpl, data)
console.log(html)

と出力されます:

<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="UTF-8" />
 <title>EJS</title>
 </head>
 <body>
 <h2>EJS </h2>
 <p>Sun Feb :00:00 GMT+0800 (GMT+08:00)</p>
 <ul>
 <li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
 </ul>
 <div>
 名前:張三、年齢:10
 </div>
 </body>
</html>

実装方法

<%=xx %> <% xx %> テンプレートのレンダリング全体は、実際にはEJS構文(主にand構文)が散りばめられた1つの大きな文字列です:

処理<%=xx %>

のような構文の場合、dataの中の値を正規表現に置き換えるだけと考えるのは簡単です:

tpl = tpl.replace(/<%=(.+?)%>/g, '${$1}')

置換後の文字列は

<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="UTF-8" />
 <title>EJS</title>
 </head>
 <body>
 <h2>${title }</h2>
 <p>${date}</p>
 <ul>
 <%arr.forEach(item=>{%><li>${item}</li><%})%>
 </ul>
 <div>
  ${obj.name}age:${obj.age}
 </div>
 </body>
</html>

処理<% xx %>

のような構文では、JS文が含まれているため、実行させて結果を返さなければなりません:

const head = 'let str = ``
with(data){
str+=`'
const body = tpl.replace(/<%(.+?)%>/g, '`
$1
str+=`')
const tail = '`}
return str'
tpl = head + body + tail

得られたコードは以下の通り:

let str = ``
with(data){
str+=`<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="UTF-8" />
 <title>EJS</title>
 </head>
 <body>
 <h2>${title }</h2>
 <p>${date}</p>
 <ul>
 `
arr.forEach(item=>{
str+=`<li>${item}</li>`
})
str+=`
 </ul>
 <div>
  ${obj.name}age:${obj.age}
 </div>
 </body>
</html>
`}
return str

それを関数にまとめて実行するだけです:

const f = new Function('data', tpl)
f(data)

出力は公式には同じです。このコード文字列の綴り方は、以下のif文のように、どんなJS文でもレンダリングできます:

<% if (obj) { %>
 <h2><%= obj.name %></h2>
<% } %>
Read next

ジェットパック・コンペの原理分析

Jetpack Composeは、Googleが2019年のI/Oカンファレンスでオープンソースとして発表したアンバンドルツールキットです。Jetpack Composeは、AndroidのネイティブUIを構築するためのモダンなツールキットです。 少ないコード、強力なツール、直感的なKotlin APIを使用することで、Jetpack ComposeはAn...

Sep 21, 2020 · 20 min read