UNPKG

webpage-to-pdf

Version:

Utility to export multiple webpages into single PDF

1 lines 7.46 kB
{"version":3,"sources":["../src/index.ts","../src/pdf-creator.ts"],"sourcesContent":["import fs from 'fs';\r\nimport { Cluster } from 'puppeteer-cluster';\r\nimport PDFCreator from './pdf-creator';\r\nimport { PuppeteerLaunchOptions } from 'puppeteer';\r\n\r\ninterface ITaskData {\r\n url: string;\r\n index: number;\r\n headers: Record<string, string>;\r\n}\r\nexport enum Status {\r\n SUCCESS,\r\n SESSION_ALREADY_ACTIVE,\r\n NOT_INITIALIZED,\r\n CONERSION_IN_PROGRESS\r\n}\r\n\r\ninterface WebpageToPdfOptions {\r\n options: PuppeteerLaunchOptions;\r\n parallelRequests: number;\r\n shareCookies: boolean;\r\n}\r\n\r\nexport type WebpageToPdfArgument = Partial<WebpageToPdfOptions>;\r\n\r\nconst DEFAULT_OPTIONS: WebpageToPdfOptions = {\r\n parallelRequests: 5,\r\n shareCookies: false,\r\n options: {}\r\n}\r\n\r\nclass WebpageToPdf {\r\n\r\n private isSessionActive: boolean = false;\r\n private isConversionInProgress = false;\r\n private cluster!: Cluster<ITaskData>;\r\n private pdfCreator!: PDFCreator; \r\n private numPages: number = 0;\r\n\r\n async init(wtpArguments: WebpageToPdfArgument=DEFAULT_OPTIONS) {\r\n let args:WebpageToPdfArgument = {\r\n ...DEFAULT_OPTIONS,\r\n ...wtpArguments\r\n }\r\n if (this.isSessionActive) {\r\n return Status.SESSION_ALREADY_ACTIVE;\r\n }\r\n // Create and initialize PDFCreator\r\n this.pdfCreator = new PDFCreator();\r\n await this.pdfCreator.init();\r\n\r\n //Initialize internal states\r\n this.numPages = 0;\r\n this.isConversionInProgress = false;\r\n\r\n // Initialize puppeteer cluster\r\n this.cluster = await Cluster.launch({\r\n concurrency: args.shareCookies? Cluster.CONCURRENCY_PAGE : Cluster.CONCURRENCY_CONTEXT,\r\n maxConcurrency: args.parallelRequests,\r\n puppeteerOptions: args.options\r\n });\r\n\r\n await this.cluster.task(async({page, data: taskData}) => {\r\n await page.setExtraHTTPHeaders(taskData.headers);\r\n await page.goto(taskData.url);\r\n const pdfBytes = await page.pdf();\r\n await this.pdfCreator.addPdfBytesAtIndex(pdfBytes, taskData.index);\r\n });\r\n this.isSessionActive = true;\r\n return Status.SUCCESS;\r\n }\r\n\r\n convertPageToPdf(url: string, headers: Record<string, string> = {}): Status {\r\n if (!this.isSessionActive) {\r\n return Status.NOT_INITIALIZED;\r\n }\r\n if (this.isConversionInProgress) {\r\n return Status.CONERSION_IN_PROGRESS;\r\n }\r\n this.cluster.queue({\r\n url: url,\r\n index: this.numPages++,\r\n headers: headers\r\n\r\n });\r\n return Status.SUCCESS;\r\n }\r\n\r\n async saveAllPagesToPdf(path: string) {\r\n await this.cluster.idle();\r\n const pdfBytes = await this.pdfCreator.getPdf();\r\n await fs.promises.writeFile(path, pdfBytes);\r\n await this.cluster.close();\r\n // reset the seesion back to inactive\r\n this.isSessionActive = false;\r\n }\r\n}\r\n\r\nexport default WebpageToPdf;\r\n","import { PDFDocument } from 'pdf-lib';\r\n\r\nclass PDFCreator {\r\n\r\n private pdfDoc!:PDFDocument;\r\n private isReady:boolean = false;\r\n private pdfBytesMap!:Map<number, Uint8Array>;\r\n private nextPdfBytesIndex:number = 0;\r\n\r\n async init() {\r\n this.pdfDoc = await PDFDocument.create();\r\n this.pdfBytesMap = new Map();\r\n this.isReady = true;\r\n this.nextPdfBytesIndex = 0;\r\n }\r\n\r\n async addPdfBytesAtIndex(pdfBytes:Uint8Array, index:number) {\r\n this.checkReady();\r\n this.pdfBytesMap.set(index, pdfBytes);\r\n while (true) {\r\n let nextPdfBytes = this.pdfBytesMap.get(this.nextPdfBytesIndex);\r\n if (nextPdfBytes == undefined) {\r\n break;\r\n }\r\n await this.addPdfBytesToDoc(nextPdfBytes);\r\n this.pdfBytesMap.delete(this.nextPdfBytesIndex);\r\n this.nextPdfBytesIndex++;\r\n }\r\n }\r\n\r\n async addPdfBytes(pdfBytes: Uint8Array) {\r\n this.checkReady();\r\n this.addPdfBytesToDoc(pdfBytes);\r\n }\r\n\r\n async getPdf() {\r\n this.checkReady();\r\n return this.pdfDoc.save();\r\n }\r\n\r\n private async addPdfBytesToDoc(pdfBytes: Uint8Array) {\r\n const doc = await PDFDocument.load(pdfBytes);\r\n for (var i = 0; i < doc.getPageCount(); i++) {\r\n const [docPage] = await this.pdfDoc.copyPages(doc, [i]);\r\n this.pdfDoc.addPage(docPage);\r\n }\r\n }\r\n\r\n private checkReady() {\r\n if (!this.isReady) {\r\n throw new Error(\"PDF Creator is not initialized yet. Call init() before calling me.\");\r\n }\r\n }\r\n}\r\n\r\nexport default PDFCreator;"],"mappings":"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","names":["Status"]}