什么是模板引擎
模板引擎是一种用于生成 HTML 页面的工具,它可以将数据插入到 HTML 页面中,从而生成完整的 HTML 页面。
实现一个 mini-ejs
前置准备
- 如何执行一段字符串中的 JavaScript 代码?
方案一: 使用 eval()
const str = console.log('hello world')
eval(str)
方案二: 使用 new Function()
const str = 'console.log("hello world")'
const fn = new Function(str)
fn()
如何传递参数?
const str = 'console.log("hello world", a, b)'
const fun = new Function("a", "b", str)
fun(1, 2)
优化: 封装成对象传递
const str = 'console.log("hello world", obj.a, obj.b)'
const fun = new Function("obj", str)
fun({ a: 1, b: 2 })
再优化: 使用 with 语句
const str = 'with(obj) {console.log("hello world", a, b)}'
const fun = new Function("obj", str)
fun({ a: 1, b: 2 })
开始实现
这个是 ejs 中的内容
{% if (isShow) { %}
<div>{%= name %}</div>
{% } else { %}
<div>age: {%= age %}</div>
{% } %}
- 解析变量
// 将 {%= 解析为 ${,将 %} 解析为 }
// `<div>{%= name %}</div>` => `<div>${name}</div>`
let temp =
"with(obj) { return `" +
content.replace(/\{\%\=([^\}]+)\%\}/g, ($0, $1) => `\$\{${$1.trim()}\}`) +
"`}"
- 剥离其中的 js 语句
// 将 %{ 变为 `,将 %} 变为 str += `
with(obj) { return `{% if (isShow) { %}
<div>${name}</div>
{% } else { %}
<div>age: ${age}</div>
{% } %}
`}
// 就可以转化为下面的结构
let str = ''
with(obj) { return str += ``
if (isShow) {
str += `<div>${name}</div>`
} else {
str += `<div>age: ${age}</div>`
}
str += ``
}
return str
let temp =
"let str = ''; with(obj) { str += `" +
content.replace(/\{\%\=([^\}]+)\%\}/g, ($0, $1) => `\$\{${$1.trim()}\}`) +
"`} return str"
temp = temp.replace(/\{\%([^\%]+)\%\}/g, ($0, $1) => `\`\n${$1}str+=\``)
- 构建函数并执行
const build = (template, data) => {
const fn = new Function("obj", template)
return fn(data)
}
const res = build(temp, {
name: "whx111",
age: "100",
isShow: true
})
安全性
EJS 实际上是一个 JavaScript 运行时。它的全部工作是执行 JavaScript。如果您运行 EJS 渲染方法而不检查你自己投入,你对结果负责。
简而言之,请勿提交包含以下代码片段的“漏洞”:
app.get('/', (req, res) => {
res.render('index', req.query);
});