写点什么

docx-handlebars 一个用于处理 DOCX 文件 Handlebars 模板的 Rust 库,支持多平台使用

作者:黄智勇
  • 2025-10-12
    广东
  • 本文字数:3786 字

    阅读完需:约 12 分钟

中文文档 | English | 在线演示


一个用于处理 DOCX 文件 Handlebars 模板的 Rust 库,支持多平台使用:


  • 🦀 Rust 原生

  • 🌐 WebAssembly (WASM)

  • 📦 npm 包

  • 🟢 Node.js

  • 🦕 Deno

  • 🌍 浏览器端

  • 📋 JSR (JavaScript Registry)

功能特性

  • 智能合并:自动处理被 XML 标签分割的 Handlebars 语法

  • DOCX 验证:内置文件格式验证,确保输入文件有效

  • Handlebars 支持:完整的模板引擎,支持变量、条件、循环、Helper 函数

  • 跨平台:Rust 原生 + WASM 支持多种运行时

  • TypeScript:完整的类型定义和智能提示

  • 零依赖:WASM 二进制文件,无外部依赖

安装

Rust

cargo add docx-handlebars
复制代码

npm

npm install docx-handlebars
复制代码

Deno

import { render_template, init } from "jsr:@sail/docx-handlebars";
复制代码

使用示例

Rust

use docx_handlebars::render_template;use serde_json::json;
fn main() -> Result<(), Box<dyn std::error::Error>> { // 读取 DOCX 模板文件 let template_bytes = std::fs::read("template.docx")?; // 准备数据 let data = json!({ "name": "张三", "company": "ABC科技有限公司", "position": "软件工程师", "projects": [ {"name": "项目A", "status": "已完成"}, {"name": "项目B", "status": "进行中"} ], "has_bonus": true, "bonus_amount": 5000 }); // 渲染模板 let result = render_template(template_bytes, &data)?; // 保存结果 std::fs::write("output.docx", result)?; Ok(())}
复制代码

JavaScript/TypeScript (Node.js)

import { render_template, init } from 'docx-handlebars';import fs from 'fs';
async function processTemplate() { // 初始化 WASM 模块 await init(); // 读取模板文件 const templateBytes = fs.readFileSync('template.docx'); // 准备数据 const data = { name: "李明", company: "XYZ技术有限公司", position: "高级开发工程师", projects: [ { name: "E-commerce平台", status: "已完成" }, { name: "移动端APP", status: "开发中" } ], has_bonus: true, bonus_amount: 8000 }; // 渲染模板 const result = render_template(templateBytes, JSON.stringify(data)); // 保存结果 fs.writeFileSync('output.docx', new Uint8Array(result));}
processTemplate().catch(console.error);
复制代码

Deno

import { render_template, init } from "https://deno.land/x/docx_handlebars/mod.ts";
async function processTemplate() { // 初始化 WASM 模块 await init(); // 读取模板文件 const templateBytes = await Deno.readFile("template.docx"); // 准备数据 const data = { name: "王小明", department: "研发部", projects: [ { name: "智能客服系统", status: "已上线" }, { name: "数据可视化平台", status: "开发中" } ] }; // 渲染模板 const result = render_template(templateBytes, JSON.stringify(data)); // 保存结果 await Deno.writeFile("output.docx", new Uint8Array(result));}
if (import.meta.main) { await processTemplate();}
复制代码

浏览器端

<!DOCTYPE html><html><head>    <title>DOCX Handlebars 示例</title></head><body>    <input type="file" id="fileInput" accept=".docx">    <button onclick="processFile()">处理模板</button>        <script type="module">        import { render_template, init } from './pkg/docx_handlebars.js';                // 初始化 WASM        await init();                window.processFile = async function() {            const fileInput = document.getElementById('fileInput');            const file = fileInput.files[0];                        if (!file) return;                        const arrayBuffer = await file.arrayBuffer();            const templateBytes = new Uint8Array(arrayBuffer);                        const data = {                name: "张三",                company: "示例公司"            };                        try {                const result = render_template(templateBytes, JSON.stringify(data));                                // 下载结果                const blob = new Blob([new Uint8Array(result)], {                    type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'                });                const url = URL.createObjectURL(blob);                const a = document.createElement('a');                a.href = url;                a.download = 'processed.docx';                a.click();            } catch (error) {                console.error('处理失败:', error);            }        };    </script></body></html>
复制代码

模板语法

基础变量替换

员工姓名: {{name}}公司: {{company}}职位: {{position}}
复制代码

条件渲染

{{#if has_bonus}}奖金: ¥{{bonus_amount}}{{else}}无奖金{{/if}}
{{#unless is_intern}}正式员工{{/unless}}
复制代码

循环渲染

项目经历:{{#each projects}}- {{name}}: {{description}} ({{status}}){{/each}}
技能列表:{{#each skills}}{{@index}}. {{this}}{{/each}}
复制代码

Helper 函数

内置的 Helper 函数:


{{upper name}}           <!-- 转大写 -->{{lower company}}        <!-- 转小写 -->{{len projects}}         <!-- 数组长度 -->{{#if (eq status "completed")}}已完成{{/if}}    <!-- 相等比较 -->{{#if (gt score 90)}}优秀{{/if}}               <!-- 大于比较 -->{{#if (lt age 30)}}年轻{{/if}}                 <!-- 小于比较 -->
<!-- 图片插入 -->{{img base64_data}} <!-- 嵌入式图片 -->{{img base64_data 300 200}} <!-- 指定宽高的嵌入式图片 -->{{img base64_data 300 200 options}} <!-- 带定位选项的浮动图片 -->
复制代码

复杂示例

=== 员工报告 ===
基本信息:姓名: {{employee.name}}部门: {{employee.department}}职位: {{employee.position}}入职时间: {{employee.hire_date}}
{{#if employee.has_bonus}}💰 奖金: ¥{{employee.bonus_amount}}{{/if}}
项目经历 (共{{len projects}}个):{{#each projects}}{{@index}}. {{name}} 描述: {{description}} 状态: {{status}} 团队规模: {{team_size}}人 {{/each}}
技能评估:{{#each skills}}- {{name}}: {{level}}/10 ({{years}}年经验){{/each}}
在表格中若需要删除一整行, 只需要在任意单元格上添加:{{removeTableRow}}

{{#if (gt performance.score 90)}}🎉 绩效评级: 优秀{{else if (gt performance.score 80)}}👍 绩效评级: 良好{{else}}📈 绩效评级: 需改进{{/if}}
图片:{{img base64_image_data [width] [height] [options]}} 只传 height:{{img base64 "" 200}} 只传 width:{{img base64 300}} 都不传:{{img base64}} 都传:{{img base64 300 200}} 浮动图片示例: {{img base64 200 100 options}} 其中 options 可以是: { "anchor": true, // 是否使用锚点定位(浮动图片) "behind_doc": false, // 图片是否在文字下方(false=覆盖文字,true=文字覆盖图片) "allow_overlap": true, // 是否允许与其他对象重叠 "position_h": 40, // 水平偏移,单位为像素(负值表示向左偏移) "position_v": -14 // 垂直偏移,单位为像素(负值表示向上偏移) } 图片定位说明: - anchor: false(默认)- 嵌入式图片,随文字流动 - anchor: true - 浮动图片,可自由定位和覆盖文字 - position_h/position_v: 不传参数时,默认使用图片尺寸的一半作为偏移量实现居中 - 支持负数偏移,实现精确的图片定位
复制代码

构建和开发

构建 WASM 包

# 构建所有目标npm run build
# 或分别构建npm run build:web # 浏览器版本npm run build:npm # Node.js 版本 npm run build:jsr # Deno 版本
复制代码

运行示例

# Rust 示例cargo run --example rust_example
# Node.js 示例node examples/node_example.js
# Deno 示例 deno run --allow-read --allow-write examples/deno_example.ts
# 浏览器示例cd tests/npm_testnode serve.js# 然后在浏览器中打开 http://localhost:8080# 选择 examples/template.docx 文件测试
复制代码

性能和兼容性

  • 零拷贝: Rust 和 WASM 之间高效的内存管理

  • 流式处理: 适合处理大型 DOCX 文件

  • 跨平台: 支持 Windows、macOS、Linux、Web

  • 现代浏览器: 支持所有支持 WASM 的现代浏览器

许可证

本项目采用 MIT 许可证 - 详见 LICENSE-MIT 文件。

发布于: 2025-10-12阅读数: 3
用户头像

黄智勇

关注

还未添加个人签名 2018-08-29 加入

还未添加个人简介

评论

发布
暂无评论
docx-handlebars 一个用于处理 DOCX 文件 Handlebars 模板的 Rust 库,支持多平台使用_webassembly_黄智勇_InfoQ写作社区