elliotblackburn/mdpdf

Cannot read property 'top' of undefined

enisz opened this issue · 7 comments

enisz commented

Hi @BlueHatbRit,

I'm just trying to generate a PDF from a markdown file but I'm facing the issue mentioned in the title. I would like to make this work in a Typescript Node.js project (maybe this has something to do with it).

The related section of my code is:

case 'pdf':

    const mdpdf = require('mdpdf');

    const options = {
        source : 'c:\\wamp64\\www\\sandbox\\guide\\output\\New Document.md',
        destination : 'c:\\wamp64\\www\\sandbox\\guide\\output\\New Document.pdf',
        // styles : 'c:\\wamp64\\www\\sandbox\\guide\\css\\pdf.css',
        debug : true,
        ghStyle : true,
        pdf : {
            format : 'A4',
            orientation : 'portrait'
        }
    }

    mdpdf.convert(options)
    .then(
        (path: string) => {
            resolve(path);
        }
    )
    .catch(
        (error: any) => {
            reject(error);
        }
    )
break;

With the debug option enabled I can see the temporary HTML file, but for some reason the PDF is not generated. The exact error message I get:

TypeError: Cannot read property 'top' of undefined
    at Object.getOptions (C:\wamp64\www\sandbox\guide\node_modules\mdpdf\src\puppeteer-helper.js:13:31)
    at writeFile.then.then.then.then (C:\wamp64\www\sandbox\guide\node_modules\mdpdf\src\index.js:190:45)
    at tryCatcher (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\util.js:16:23)
    at Promise._settlePromiseFromHandler (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\promise.js:512:31)
    at Promise._settlePromise (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\promise.js:569:18)
    at Promise._settlePromise0 (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\promise.js:614:10)
    at Promise._settlePromises (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\promise.js:694:18)
    at _drainQueueStep (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\async.js:138:12)
    at _drainQueue (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\async.js:131:9)
    at Async._drainQueues (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\async.js:147:5)
    at Immediate.Async.drainQueues [as _onImmediate] (C:\wamp64\www\sandbox\guide\node_modules\bluebird\js\release\async.js:17:14)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)
    at process.topLevelDomainCallback (domain.js:120:23)

Can you take a look?

Thanks!

enisz commented

I have tried to make it work as a standalone project without typescript, but got the same error with the example script in the README

index.js

const mdpdf = require('mdpdf');
const path = require('path');

let options = {
    source: path.join(__dirname, 'README.md'),
    destination: path.join(__dirname, 'output.pdf'),
    styles: path.join(__dirname, 'md-styles.css'),
    pdf: {
        format: 'A4',
        orientation: 'portrait'
    }
};

mdpdf.convert(options).then((pdfPath) => {
    console.log('PDF Path:', pdfPath);
}).catch((err) => {
    console.error(err);
});

output:

C:\wamp64\www\pdf>node index
TypeError: Cannot read property 'top' of undefined
    at Object.getOptions (C:\wamp64\www\pdf\node_modules\mdpdf\src\puppeteer-helper.js:13:31)
    at writeFile.then.then.then.then (C:\wamp64\www\pdf\node_modules\mdpdf\src\index.js:190:45)
    at tryCatcher (C:\wamp64\www\pdf\node_modules\bluebird\js\release\util.js:16:23)
    at Promise._settlePromiseFromHandler (C:\wamp64\www\pdf\node_modules\bluebird\js\release\promise.js:512:31)
    at Promise._settlePromise (C:\wamp64\www\pdf\node_modules\bluebird\js\release\promise.js:569:18)
    at Promise._settlePromise0 (C:\wamp64\www\pdf\node_modules\bluebird\js\release\promise.js:614:10)
    at Promise._settlePromises (C:\wamp64\www\pdf\node_modules\bluebird\js\release\promise.js:694:18)
    at _drainQueueStep (C:\wamp64\www\pdf\node_modules\bluebird\js\release\async.js:138:12)
    at _drainQueue (C:\wamp64\www\pdf\node_modules\bluebird\js\release\async.js:131:9)
    at Async._drainQueues (C:\wamp64\www\pdf\node_modules\bluebird\js\release\async.js:147:5)
    at Immediate.Async.drainQueues [as _onImmediate] (C:\wamp64\www\pdf\node_modules\bluebird\js\release\async.js:17:14)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)

Hi @enisz, thanks for the bug report, especially the code samples and stack trace. Let me take a look, it seems to be coming rfom Puppeteer but obviously that'll be due to something either mdpdf is pushing in, or something it's letting you push in. I'll debug this and will find the issue and will report back asap.

I've found the issue, it's todo with the way we construct the margin options for puppeteer inside our options helper. It seems it was working properly for the cli but failing on the js api, I guess not many people are using the js api (don't worry, it'll keep existing, I need it to).

I've corrected the issue and made more checks around it. I'll commit the fix but I don't have my keys on me to do the release until I get home this evening.

If you need it working immedietely, then you should set all of the border options to their default value of "20mm". Once I've cut the new release you'll be able to remove that.

enisz commented

Thanks for the fast response!

I'm not home either so I can test it in the afternoon. From the documentation it's not clear for me how to set the border property in the options properly. Does it look like this?

let options = {
    source: path.join(__dirname, 'README.md'),
    destination: path.join(__dirname, 'output.pdf'),
    styles: path.join(__dirname, 'md-styles.css'),
    border : {
        top: "20mm",
        left: "20mm",
        right: "20mm",
        bottom: "20mm"
    }
    pdf: {
        format: 'A4',
        orientation: 'portrait'
    }
};

Thanks!

@enisz you're right that isn't clear, I'll see if I can add more documentation for the JS api. When in doubt, you can check the ./bin/index.js file which is the cli script that makes use of the JS API.

So you will want to nest the border inside the "pdf" options, as such:

let options = {
    source: path.join(__dirname, 'README.md'),
    destination: path.join(__dirname, 'output.pdf'),
    styles: path.join(__dirname, 'md-styles.css'),
    pdf: {
        format: 'A4',
        orientation: 'portrait',
        border: {
            top: "20mm", // etc
        }
    }
};
enisz commented

With the updated options object it is working like a charm

const mdpdf = require('mdpdf');
const path = require('path');

let options = {
    source: path.join(__dirname, 'README.md'),
    destination: path.join(__dirname, 'output.pdf'),
    styles: path.join(__dirname, 'md-styles.css'),
    pdf: {
        border : {
            top: "20mm",
            left: "20mm",
            right: "20mm",
            bottom: "20mm"
        },
        format: 'A4',
        orientation: 'portrait'
    }
};

mdpdf.convert(options).then((pdfPath) => {
    console.log('PDF Path:', pdfPath);
}).catch((err) => {
    console.error(err);
});

I will check out the index.js in the bin folder as well.

Thanks!

Brilliant thanks @enisz, I'm going to re-open this until I've got the release out with the fix so I can track it a bit easier 😄 also hopefully people won't report it multiple times as well.