原理は正規置換+文字列スプライシングで、ejsを例にとると、具体的な手順は以下のようになります:
- テンプレート・ファイルを読み込んで元の文字列を取得
- 正規置換
<% %><%= %> - コード形式にスプライスされた文字列
- new 関数で文字列を関数に変換
- 関数は
プレビュー
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>
<% } %>




