Handlebars 预编译与运行时:生产环境的高效用法
🎯 引言
学会这篇文章,你将了解 Handlebars 的 预编译 机制。在前端项目中,每次都把模板字符串传给浏览器再编译会很慢。预编译可以提前把模板编译好,浏览器只需要加载轻量的运行时,渲染速度更快,也更适合生产环境。
🧱 运行时与完整版的区别
Handlebars 有两种使用方式:
| 方式 | 特点 | 适用场景 |
|---|---|---|
| 完整版(handlebars) | 包含编译和渲染功能 | Node.js 后端、开发环境 |
| 运行时版(handlebars/runtime) | 只包含渲染功能,体积小 | 浏览器前端、生产环境 |
完整版可以在运行时把模板字符串编译成函数;运行时版只能执行已经编译好的模板函数。
✨ 为什么需要预编译
在浏览器里使用完整版 Handlebars,流程是:
- 加载完整版 JS(体积大)。
- 把模板字符串传给
Handlebars.compile()。 - 得到渲染函数,再传入数据得到 HTML。
每一步都在浏览器里执行,会增加页面加载和运行时间。
预编译的流程是:
- 在构建阶段用 Node.js 把模板编译成 JS 函数。
- 浏览器只加载运行时版(体积小很多)。
- 直接调用编译好的函数渲染。
💡 使用命令行预编译
Handlebars 提供了命令行工具,可以把 .hbs 文件预编译成 JS。
安装
npm install handlebars@4.7.9 --save-dev
预编译单个文件
npx handlebars src/templates/user.hbs -f dist/templates/user.js
-f 指定输出文件路径。编译后的文件是一个 AMD/CommonJS/全局变量兼容的模块。
预编译整个目录
npx handlebars src/templates -f dist/templates/all.js
这样会把 src/templates 下所有 .hbs 文件打包到一个 JS 文件里。
🛠 浏览器里怎么用预编译模板
假设你已经用命令行把 user.hbs 预编译成了 dist/templates/user.js。现在要在浏览器里使用它,只需要做三件事:
- 引入运行时:加载体积很小的
handlebars.runtime.min.js。 - 引入预编译模板:加载
dist/templates/user.js。 - 传入数据渲染:调用
Handlebars.templates.user(数据)得到 HTML。
<!-- 1. 引入 Handlebars 运行时(只负责渲染,体积小) -->
<script src="node_modules/handlebars/dist/handlebars.runtime.min.js"></script>
<!-- 2. 引入预编译好的模板文件 -->
<script src="dist/templates/user.js"></script>
<!-- 3. 传入数据,得到 HTML -->
<script>
var html = Handlebars.templates.user({ name: '小明', age: 18 });
document.getElementById('app').innerHTML = html;
</script>
Handlebars.templates.user 这个名字对应你预编译时的文件名 user.hbs。如果文件叫 card.hbs,那么调用方式就是 Handlebars.templates.card(数据)。handlebars.runtime.min.js,而不是完整版 handlebars.min.js。完整版会把编译功能也带进来,体积更大,预编译就没意义了。⚡ 不想用命令行,怎么在 Node.js 里预编译
如果你希望用 Node.js 脚本代替命令行,可以这样做:
const fs = require('fs');
const Handlebars = require('handlebars');
// 1. 读取模板文件内容
const source = fs.readFileSync('./src/templates/user.hbs', 'utf-8');
// 2. 预编译,得到中间描述对象
const spec = Handlebars.precompile(source);
// 3. 保存到 JS 文件
fs.writeFileSync('./dist/templates/user.js', `module.exports = ${spec};`);
预编译得到的 spec 还不能直接调用,需要先用 Handlebars.template() 包装一下:
const Handlebars = require('handlebars/runtime');
const spec = require('./dist/templates/user.js');
// 把预编译结果包装成可执行的模板函数
const template = Handlebars.template(spec);
// 传入数据渲染
const html = template({ name: '小明', age: 18 });
console.log(html);
🧰 与构建工具结合
实际项目中,Handlebars 预编译通常会交给构建工具处理:
- Webpack:使用
handlebars-loader。 - Vite:使用
vite-plugin-handlebars。 - Rollup:使用
rollup-plugin-handlebars。
这些插件会自动把 .hbs 文件预编译好,你只需正常 import 使用。
🧾 小节总结
- Handlebars 完整版包含编译和渲染,运行时版只包含渲染。
- 预编译可以在构建阶段完成,浏览器只需要加载运行时版,性能更好。
- 使用命令行
handlebars可以把.hbs文件预编译成 JS。 - 浏览器端通过
Handlebars.templates.模板名调用预编译模板。
❓ 知识问答
Q1:预编译后的模板还能修改吗?
A:不能。预编译结果是编译好的函数,模板内容需要在源 .hbs 文件里修改后重新预编译。
Q2:开发环境也需要预编译吗?
A:可以预编译,也可以直接用完整版实时编译。开发环境更注重方便调试,生产环境建议预编译。
Q3:浏览器端加载了完整版 Handlebars,还能用预编译模板吗?
A:可以,但没必要。完整版体积更大,会浪费流量和加载时间。
Q4:Handlebars 预编译和 Vue/React 的编译有什么区别?
A:Handlebars 预编译是把模板字符串变成渲染函数;Vue/React 的编译会更进一步,生成针对各自框架运行时的渲染代码。思想上类似,但产物不同。
🧪 小练习
请完成以下步骤:
- 创建一个
src/templates/card.hbs文件,内容如下:
<div class="card">
<h3>{{title}}</h3>
<p>{{desc}}</p>
</div>
- 执行预编译命令:
# 请在这里输入预编译命令
- 编写
index.html,在浏览器中使用运行时版加载并渲染该模板。
🎉 恭喜你完成了 Handlebars 课程的学习!你已经掌握了从基础语法、内置函数、模板复用、自定义 Helper 到预编译的完整知识体系,可以在项目中灵活使用 Handlebars 了。
