1

I am working with docxtemplater with nodejs and have read the documentation from the link below: https://docxtemplater.readthedocs.io/en/latest/generate.html#node

Unlike with the provided documentation, I am trying to load a document from my firebase storage called

'tag-example.docx'

and have the docxtemplater run on the tags on there. The generated document is then saved back to my firebase storage. Simply put:

  1. Load 'tag-example.docx' from firebase storage;
  2. docxtemplater does its thing on the document;
  3. revised output saved to firebase storage.

My issue is that I keep getting the error message below:

Unhandled error TypeError: Cannot read property 'toLowerCase' of undefined
at Object.exports.checkSupport (/workspace/node_modules/pizzip/js/utils.js:293:32)
at ZipEntries.prepareReader (/workspace/node_modules/pizzip/js/zipEntries.js:275:11)
at ZipEntries.load (/workspace/node_modules/pizzip/js/zipEntries.js:295:10)
at new ZipEntries (/workspace/node_modules/pizzip/js/zipEntries.js:32:10)
at PizZip.module.exports [as load] (/workspace/node_modules/pizzip/js/load.js:25:20)
at new PizZip (/workspace/node_modules/pizzip/js/index.js:41:10)
at /workspace/index.js:66:11
at func (/workspace/node_modules/firebase-functions/lib/providers/https.js:336:32)
at processTicksAndRejections (internal/process/task_queues.js:95:5)

Is there a way to solve this issue? Is this because I am not loading the document as a binary like in the example? Can this even be done with firebase storage?

    const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {Storage} = require('@google-cloud/storage');
var PizZip = require('pizzip');
var Docxtemplater = require('docxtemplater');
admin.initializeApp();
const BUCKET = 'gs://myapp.appspot.com';

    const https = require('https');
    
    const storage = new Storage({
    projectId: 'myapp' });
    const cors = require('cors')({origin: true});


exports.test2 = functions.https.onCall((data, context) => {
// The error object contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
function replaceErrors(key, value) {
    if (value instanceof Error) {
        return Object.getOwnPropertyNames(value).reduce(function(error, key) {
            error[key] = value[key];
            return error;
        }, {});
    }
    return value;
}

function errorHandler(error) {
    console.log(JSON.stringify({error: error}, replaceErrors));

    if (error.properties && error.properties.errors instanceof Array) {
        const errorMessages = error.properties.errors.map(function (error) {
            return error.properties.explanation;
        }).join("\n");
        console.log('errorMessages', errorMessages);
        // errorMessages is a humanly readable message looking like this :
        // 'The tag beginning with "foobar" is unopened'
    }
    throw error;
}

//Load the docx file as a binary
let file_name = 'tag-example.docx';
const myFile =storage.bucket(BUCKET).file(file_name);
var content =  myFile.createReadStream();

var zip = new PizZip(content);
var doc;
try {
    doc = new Docxtemplater(zip);
} catch(error) {
    // Catch compilation errors (errors caused by the compilation of the template : misplaced tags)
    errorHandler(error);
}

//set the templateVariables
doc.setData({
    first_name: 'John',
    last_name: 'Doe',
    phone: '0652455478',
    description: 'New Website'
});

try {
    // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
    doc.render();
}
catch (error) {
    // Catch rendering errors (errors relating to the rendering of the template : angularParser throws an error)
    errorHandler(error);
}
var buf = doc.getZip()
             .generate({type: 'nodebuffer'});

// buf and then save to firebase storage.
buf.pipe(myFile.createWriteStream());

});
Kola Ayanwale
  • 105
  • 1
  • 8

1 Answers1

0

this error message is from pizzip, not directly from docxtemplater.

It happens when the argument given to pizzip is invalid.

In your case, you did :

var content =  myFile.createReadStream();
var zip = new PizZip(content);

and the problem is that content is I think a specific object, a stream, and not something that has been finished reading.

You need to first resolve the content to a string or a buffer and then you can do :

var zip = new PizZip(buffer);
edi9999
  • 19,701
  • 13
  • 88
  • 127