构建自己的静态网站生成脚本(二)
此篇来讲模版引擎的实现,筛选之后,比较喜欢的模版引擎有如下几个:
edge
@if(happy && hungry)
I am happy _and_ hungry; both are true.
@endif
{{ foo ? "true" : "false" }}
- adonisjs 全栈框架的模版引擎,可以作为独立的包来使用,语法非常优雅,没有丑陋的百分号,需要学习新概念,后续会尝试支持
- npm 地址:https://github.com/edge-js/edge
- 文档地址:https://docs.adonisjs.com/guides/views/introduction
lit-html
js
import { html } from "lit-html";
const helloTemplate = (name) => html`<div>Hello ${name}!</div>`;
- 谷歌出品的 lit.js 前端框架的工具包
- 有配套的官方 VSCode 插件来提供代码高亮
- 代码高亮需要识别 lit-html 的 html 标签函数调用
- npm 地址:https://www.npmjs.com/package/lit-html
通用 html VSCode 代码支持解决方法
打开:设置 => 文本编辑器 => 文件 => Associations => 添加项
- edge
- 添加项:*.edge
- 添加值:html
- temp.js
- 添加项:*.temp.js
- 添加值:html
这样可以基本解决 html 的高亮、补全、提示、格式化,但是这样同时也失去了 js 的相关支持
js 最简模版引擎实现
关于 js 想要实现尽量原生的模版引擎,必然要使用模版字符串,模版需要被构造成函数随处调用,但是 js 是没有提供模版字符串的构造函数的,初步有两种思路:
- 直接将模版封装成 js 函数,返回将参数处理之后的模版字符串;
- 将模版写入文本文件,如 html 文件,脚本运行时读入模版内容,通过 Function 函数动态创建模版函数
js
const render = (t) => new Function("$", `return \`${t}\``);
temp.js
js
// template.js
export const template = (name) => `<p>${name}<p>`;
- 使用 js 的模版字符串来写函数式模版,使用 ESModule 高灵活度组件化
- 写在 js 文件中,没有 html 的语法高亮、自动补全提示和代码格式化
Function 动态创建模版函数
html
<!-- tempalte.html -->
<p>${$.title}</p>
- 在 html 文件中模版字符串的语法,使用编辑器默认提供的相关代码支持,同时失去编辑器对模版中逻辑代码的支持
- 组件化需要预先读入所有模版,随模版上下文对象一起注入,稍显麻烦
尝试编写 temp.js demo,函数式模版确实灵活,但没有编辑器的相关支持代码非常混乱,难以阅读,于是先转头实现了 Function 动态创建模版函数的模版引擎,以及从上下文注入所有模版函数的组件化。
js
// 把模板文件解析为函数
const x = (x) => new Function("$", `return \`${readFileSync(x, "utf-8")}\``);
// 读入所有模板
function readTemplate(dir = "./template") {
const tems = {};
readdirSync(dir).forEach((v) => {
try {
// 在模版文件中使用反引号时需要转义,否则会创建模版函数失败
tems[v.replace(/\.html$/, "")] = x(resolve(dir, v));
} catch {
// 对创建失败抛出错误,提示报错文件
throw new Error(
`Error reading "${v}" template file, please check the part related to backquotes or escape symbols in the file.`
);
}
});
return tems;
}