Downloading PDF larger than 30 pages - browser freeze?
Is your feature request related to a problem? Please describe. There is a suggestion on the react-pdf main website for this specific problem. The suggestion is to implement service workers. However, this implementation makes sense only for static PDF components that are consisted of plain text, some images. For PDF components that use advanced logic (global state, functions, hooks) it's not possible to implement worker logic (as far as I know)
Describe the solution you'd like I would like to find a solution that will allow me to offload the main browser thread in instances where PDF's might have more than 30 pages (even 100)
Describe alternatives you've considered Don't know of any alternatives to service workers.
Additional context Rewriting my current PDF generating logic is too costly and would last too long to consider
Current Code Responsible for the Download
export const useQuoteReport = (shareQuoteConfig: TShareQuote) => {
const { t } = useTranslation();
const { cropsToQuoteFilteredP14s } = useCropsToQuoteFilter();
const { p14s } = useGetQuoteCrops();
const { quote } = useQuoterContext();
const { tableOptions, checkedFilters } = useTableOptionsContext();
const [loading, setLoading] = useState(false);
const { username, fullName, logoURL, phoneNumber } = useAuthContext();
const { getUnitOfMeasure } = useGetUnitOfMeasure();
const { resolveAppendix } = usePdfAppendix();
const { sortedAndFilteredData: sortedAndFilteredCrops } = useSortAndFilter({
data: mappedData(cropsToQuoteFilteredP14s),
type: 'P14'
});
const { userPreferencesData: userPreferences } = useUserPreferencesContext();
const { logEvent, userFullName } = useEventLogging();
const handleDownload = useCallback(() => {
setLoading(true);
const headerData: TPDFHeaderData = {
userData: { email: username, fullName, logoURL, phoneNumber },
policyData: {
producerName: quote?.producerName,
producerType: quote?.producerType,
policyNumber: quote?.p10Data && quote?.p10Data[0]?.policyNumber,
cropYear: quote?.reinsuranceYear
},
quoteNumber: `${t('common.quote')}: ${quote?.reinsuranceYear}-${
quote?.quoteId
}`
};
const quoterActiveFilters: TQuoterActiveFilters = {
CLUs: checkedFilters.P11,
units: checkedFilters.P15
};
const configFilters: TConfigFilters = {
filterCLUs: shareQuoteConfig.filterCLUs,
filterUnits: shareQuoteConfig.filterCLUs
? true
: shareQuoteConfig.filterLocations
};
pdf(
<QuoteOutputDocument
quote={quote}
p14s={p14s}
orderedP14s={sortedAndFilteredCrops as TInsuranceInForce[]}
tableOptions={tableOptions}
summary={shareQuoteConfig.summary}
headerData={headerData}
getUnitOfMeasure={getUnitOfMeasure}
userPreferences={userPreferences}
quoterActiveFilters={quoterActiveFilters}
configFilters={configFilters}
/>
)
.toBlob()
.then(async initialBlob => {
if (shareQuoteConfig.includePamphlets) {
const appendixBlobs = await resolveAppendix();
return [initialBlob, ...appendixBlobs];
}
return initialBlob;
})
.then(async data => {
if (shareQuoteConfig.includePamphlets && Array.isArray(data)) {
const merger = new PDFMerger();
for (const blob of data) {
const arrayBuffer = await blob?.arrayBuffer();
if (arrayBuffer) {
await merger.add(arrayBuffer, null);
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- type definition wrong, will change once library updates
// @ts-ignore
const mergedPdf = await merger.saveAsBlob();
return mergedPdf;
}
return data;
})
.then(instance => {
const url = URL.createObjectURL(instance);
const link = document.createElement('a');
link.href = url;
link.download = `Quote-${quote?.reinsuranceYear}-${quote?.quoteId}.pdf`;
link.click();
setLoading(false);
logEvent({ event: 'ShareQuote', section: 'Quoter', userFullName });
})
.catch(error => {
console.error(error);
toast.error(t('shareQuote.downloadPDFError'));
setLoading(false);
});
}, [quote, tableOptions, sortedAndFilteredCrops, shareQuoteConfig, t]);
return { loading, handleDownload };
};