react-pdf: Multiple `toBlob` executed at the same time throws TypeError: Cannot read property 'hasGlyphForCodePoint' of null
OS: Linux manjaro 4.14.67-1-MANJARO
React-pdf version:
1.0.0-alpha.17
Description:
I created my custom createPDF function which returns blob instance promise, it works perfectly, but the problem is that if I run multiple calls to this async function, then I sometimes get this error:
react-pdf.browser.es.js:3367 Uncaught (in promise) TypeError: Cannot read property ‘hasGlyphForCodePoint’ of null
at eval (react-pdf.browser.es.js:3367)
at Array.reduce (<anonymous>)
at buildSubsetForFont (react-pdf.browser.es.js:3366)
at eval (react-pdf.browser.es.js:3376)
at Array.map (<anonymous>)
at ignoreChars (react-pdf.browser.es.js:3375)
at getFragments (react-pdf.browser.es.js:3466)
at eval (react-pdf.browser.es.js:3447)
at Array.forEach (<anonymous>)
at getFragments (react-pdf.browser.es.js:3422)
How to replicate issue including code snippet (if applies): This is how this function looks like:
const MyDocument = ({ children }) => (
<Document>
<Page
size="A4"
wrap
>
<Text
render={({ pageNumber, totalPages }) => `${pageNumber} z ${totalPages}`}
fixed
style={{ position: 'absolute', bottom: 10, right: 10 }}
/>
{children}
</Page>
</Document>
);
export const createPDF = pdfContent => {
const instance = pdf();
instance.updateContainer(<MyDocument>{pdfContent}</MyDocument>);
return instance.toBlob();
};
And this is where I call it:
const {
createPDF,
} = await import(/* webpackChunkName: "pdf" */ 'pdf');
const blobs = await Promise.all(
this.props.attachments.map(a =>
createPDF(a.pdfContent),
),
);
Do you have any idea what could cause this error? Is it forbidden to render multiple pdfs at the same time? Does PDF rendering has any side effects or use some global state?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 5
- Comments: 31 (6 by maintainers)
I’m getting this error with two separate
PDFDownloadLinkcomponents, so it doesn’t seem to be restricted toPDFViewer. Both byPDFDownloadLinkcomponents are rendering different documents with different data. The only shared data is the fonts. EDIT: actually, they also share some styled components using@react-pdf/styled-components, however when not using custom fonts there are no errors.I’m using
v1.5.6Not sure how it’s related or is it helpful, but I also have similar behavior (an error as @klis87 mentioned).
I have 3 instances of Components using main REPL code for
Quixotehttps://react-pdf.org/repl<QuixoteDownloadLink /><QuixotePdfViewer /><QuixoteBlobProvider />My code is simple aggregation and split.
When only Download, or only Viewer or only Blob rendered, all is OK. not errors. When Viewer renedered together with EITEHR Download or Blob, then I have that TypeError in console.
Most probably, @mmichelli is right, that we can’t use Viewer and other instances together.
I also tried both approaches of registering font: old:
and new:
And sure thing, when I comment code related to
Font.registerI have no TypeError when I render all 3 components (Viewer, Download, Blob).Note: I created separated issue for the outdated REPL code: #586
@diegomura could you plz confirm, that it was designed so, and if so, plz reflect it in README or doc page and close this issue? Is it an issue at all, or just wrong usage of
@react-pdf/rendererAPI?PS. I use MacOS
v10.14.4, Nodev11.14.0, Reactv16.8.6, Webpackv4.30, Babelv7.4.3,@react-pdf/rendererv1.5.4.I have the same problem. I have ParentComponent, that map ChildrenComponents, in which I have <PDFDownloadLink>, that generates PDF for each child. The solution I found is next:
Hope this will help 😃
UPD: @diegomura thank u very much for this project ❤️
This is not a solution. It’s a workaround i’ve used that in my hook. Since it did not fit my architecture to render the pdf’s one by one i made a solution that will just retry if document creation fails. Works surprisingly well actually. Hope it can help someone out:
Try to execute your function / loop with async-await promise.
Keep in mind that the bug will still present if you loop with forEach (parallel execution). Use a simple for … of to read/execute the files in sequence, and so avoiding any congestion while generating pdf files.
The key here is await first
createPDFpromise to be resolved, then u can execute next calls in parallel in any number desired, for instance like:This is workaround of course, but for me it mitigated this issue.
@diegomura see the problem at https://codesandbox.io/s/jjjpp84v7y
I confirm that this only happens with custom font, so probably this is some kind of registration font race condition
So, I spent a lot of time today getting this module working with Redux and I wanted to make a few notes of my journey… not sure this is the best place… but maybe this could be some update to the doco? Also… this started out as a solution for the multiple distinct PDFs this thread discusses, but turned into something else, so sorry for the dump, but hope it helps someone.
Pretty much boils down to this innocent looking code:
Notice
DocDefaultcomponent is passed without any props because I assumed I could reference Redux state in theDocDefaultcomponent … but the problem is, when the referenced Redux state changes it tries to re-render theDocDefaultcomponent, which fails horribly (often causes a browser debugger crash), which I now clearly see is because it is inside thePDFDownloadLinkcomponent!Once I finally figured out the issue was the re-render triggered by Redux, I was able to fix it.
So, essentially when integrating with a Redux project I would do one of these three things: 1) include the whole
PDFDownloadLinkcomponent in theDocumentdefinition, or 2) pass the Redux variables as props, or maybe 3) reference the Redux store directly with getState(), anyway, I ended up doing 2) and removing all ReduxmapStateToPropsvariables fromDocDefault:So I got this working with a setTimeout hack. (After trying a bunch of other things like moving the Font registration code around)
Firstly, the layout I have is a
Sidebarcomponent with some print options like page size, orientation, etc; aTopbarcomponent with some action buttons including the download link; and lastly the mainPDFViewercomponent.Hack was to delay load the
Topbarcomponent containing the download link, after loading thePDFViewer. No doubt some sort of callback from React render of the PDFViewer component would be much more robust.Code extract here cut down for clarity.
@diegomura yeah, I tried it also with alpha.17, sry for consusion, I could prepare the example in this version in the 1st place. But Problem still occurs, tr to reload your example and click
Get multiple blob, I just got errorUnhandled Rejection (TypeError) Cannot read property 'hasGlyphForCodePoint' of nulltoo.Anyone stumbling on this who is using PDFDownloadLink, I ended up using this solution to generate the PDFs on user click and it ended up working!
@theobat use my sandbox as a base, because it really has it reproduced already - https://codesandbox.io/s/jjjpp84v7y but for older version, you could upgrade too see whether newest version is still affected by this issue.
For now I am still living with workaround I mentioned above