You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用docxtemplater生成多份docx并打包Zip后文件无法打开的问题

问题:生成包含多份docx的Zip文件后,docx无法打开

使用docxtemplater生成单个.docx文件功能正常,但生成两份docx并加入PizZip实例打包成Zip后,Zip内的docx文件无法打开,提示“文件无效”。

原代码

import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils";
import { saveAs } from "file-saver";
import expressionParser from "docxtemplater/expressions";
import JSZip from "jszip";

const storage = getStorage();

//New zip instance
const outputZip = new PizZip();
function loadFile(url, callback) {
  PizZipUtils.getBinaryContent(url, callback);
}

export const renderRelianceForms = async () => {
  try {
    await getDownloadURL(ref(storage, "RS1PD.docx")).then((url) => {
      loadFile(url, function (error, content) {
        if (error) {
          throw error;
        }

        const zip = new PizZip(content);
        const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true, parser: expressionParser });

        doc.render({
        //   date: referral?.creation_date.toDate().toLocaleDateString(),
        });
        const out = doc.getZip().generate({
          type: "arraybuffer",
          compression: "DEFLATE",
          mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        });

        outputZip.file("Reliance Section 1 - Personal Details.docx", out, { base64: true });
        console.log("success", out);
      });
    });

    await getDownloadURL(ref(storage, "RS1MP.docx")).then((url) => {
      loadFile(url, function (error, content) {
        if (error) {
          throw error;
        }

        const zip = new PizZip(content);
        const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true, parser: expressionParser });
        doc.render({
        //   date: referral?.creation_date.toDate().toLocaleDateString(),
        });
        const out = doc.getZip().generate({
          type: "arraybuffer",
          compression: "DEFLATE",
          mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        });

        outputZip.file("Reliance Section 1 - Missing Person Form.docx", out, { base64: true });
        console.log("success", out);
      });
    });

    //OUTZIP
    const output = outputZip.generate({
      type: "blob",
      compression: "DEFLATE",
      mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    });

    console.log(outputZip);
    saveAs(output, "Reliance.zip");
  } catch (err) {
    console.error(err);
  }
};

问题原因及修复方案

  1. 数据类型不匹配:生成docx时用type: "arraybuffer",但添加到outputZip时指定了{ base64: true },导致二进制文件被错误编码。arraybuffer本身就是二进制数据,无需base64编码,需移除该选项。
  2. Zip文件MIME类型错误:生成最终Zip时,mimeType应使用"application/zip",而非docx的MIME类型,否则会导致系统无法正确识别Zip格式。
  3. 异步流程混乱:原代码混用await和回调函数,可能导致未完成两个docx的生成与添加就提前打包Zip。需将loadFile包装为Promise,统一用async/await处理异步操作,保证流程顺序。

修复后的代码

import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils";
import { saveAs } from "file-saver";
import expressionParser from "docxtemplater/expressions";

const storage = getStorage();

// 将loadFile包装为Promise,适配async/await
const loadFileAsync = (url) => {
  return new Promise((resolve, reject) => {
    PizZipUtils.getBinaryContent(url, (error, content) => {
      if (error) reject(error);
      else resolve(content);
    });
  });
};

export const renderRelianceForms = async () => {
  try {
    const outputZip = new PizZip();

    // 处理第一个docx
    const url1 = await getDownloadURL(ref(storage, "RS1PD.docx"));
    const content1 = await loadFileAsync(url1);
    const zip1 = new PizZip(content1);
    const doc1 = new Docxtemplater(zip1, { 
      paragraphLoop: true, 
      linebreaks: true, 
      parser: expressionParser 
    });
    doc1.render({
      // date: referral?.creation_date.toDate().toLocaleDateString(),
    });
    const out1 = doc1.getZip().generate({
      type: "arraybuffer",
      compression: "DEFLATE"
    });
    outputZip.file("Reliance Section 1 - Personal Details.docx", out1);

    // 处理第二个docx
    const url2 = await getDownloadURL(ref(storage, "RS1MP.docx"));
    const content2 = await loadFileAsync(url2);
    const zip2 = new PizZip(content2);
    const doc2 = new Docxtemplater(zip2, { 
      paragraphLoop: true, 
      linebreaks: true, 
      parser: expressionParser 
    });
    doc2.render({
      // date: referral?.creation_date.toDate().toLocaleDateString(),
    });
    const out2 = doc2.getZip().generate({
      type: "arraybuffer",
      compression: "DEFLATE"
    });
    outputZip.file("Reliance Section 1 - Missing Person Form.docx", out2);

    // 生成Zip文件,使用正确的MIME类型
    const output = outputZip.generate({
      type: "blob",
      compression: "DEFLATE",
      mimeType: "application/zip"
    });

    saveAs(output, "Reliance.zip");
  } catch (err) {
    console.error(err);
  }
};

内容的提问来源于stack exchange,提问作者Yumma Tech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:52:45