Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Commit

Permalink
Resuse puppeteer browser instance (#5)
Browse files Browse the repository at this point in the history
* move browser instance to closure

* update readme
  • Loading branch information
moshensky committed Jan 17, 2018
1 parent 6391980 commit e8c394b
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 89 deletions.
42 changes: 31 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,46 @@ All fonts that are used inside passed html document need to be installed on the
Headers and footers could be generated by passing either as a separate html document or as a single line that can be customized to `left`, `center` and `right` sections.
There are two special placeholders `{page}` and `{pages}` that could be used inside your document footers and headers, which are going to be replaced by current page number and total pages count respectively.
`mkCompoundPdf` accepts array of html documents that would be concatenated. Total page count is going to be the sum of the final generated pdf.
All documents had to be proper HTML documents.
All documents had to be proper HTML documents.

For usage checkout `./src/compound-pdf.ts` file. For JS strip all types.

```ts
import { PrintMargin, pageSizeInMM, mkCompoundPdf, mkPdf } from 'html-to-pdf-converter'
const footerFontPath = join(
__dirname, 'path_to_font/roboto-v18-latin_greek_cyrillic-regular.ttf',
)

// sizes are in millimeters
const footerFontSize = 10
const margin: PrintMargin = {
const fontPath = join(__dirname, '../fonts/roboto-v18-latin_greek_cyrillic-regular.ttf')
const footerFontSize = Millimeters.of(4.2)

const margin: PrintMargin = PrintMargin.ofMillimeters({
top: 7.5,
right: 15,
bottom: 5,
left: 17,
})

const puppeteerOptions: MkPdfOptions = {
puppeteer: {
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
},
}

export const getPDFWithSimpleOneLineFooter= (document: string): Buffer => {
return mkCompoundPdf([
// Initialize converter, puppeteer browser launch options could be passed in
const converter: HtmlToPdfConverter = await initialize(puppeteerOptions)
// When finished don't forget to release resources
// await converter.destroy()

// Converter signature
export interface HtmlToPdfConverter {
mkCompoundPdf: (contents: PdfContentWithSlots[]) => Promise<Buffer>
mkPdf: (content: PdfContent) => Promise<Buffer>
destroy: () => Promise<void>
}

export const getPDFWithSimpleOneLineFooter= (document: string): Promise<Buffer> => {
converter.mkCompoundPdf([
{
pdfContent: document,
footer: {
Expand Down Expand Up @@ -69,8 +90,8 @@ export const getPDFProtocolStream = (
firstPage: string,
firstPageFooter: string,
restPages: string,
): Buffer => {
return mkCompoundPdf([
): Promise<Buffer> =>
converter.mkCompoundPdf([
{
pdfContent: firstPage,
footer: {
Expand Down Expand Up @@ -102,10 +123,9 @@ export const getPDFProtocolStream = (
pageSize: pageSizeInMM.A4.landscape,
},
])
}

export const getPDFWithCustomSize = (document: string): Buffer =>
mkPdf({
export const getPDFWithCustomSize = (document: string): Promise<Buffer> =>
converter.mkPdf({
pdfContent: document,
margin: {
top: 5,
Expand Down
136 changes: 68 additions & 68 deletions src/compound-pdf.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { readFileSync } from 'fs'
import { join } from 'path'

import { mkCompoundPdf, MkPdfOptions } from '../src/compound-pdf'
import { PrintMargin, pageSizeInMM } from '../src/types'
import { Millimeters } from './index'
import { initialize, MkPdfOptions, HtmlToPdfConverter, Millimeters } from './index'
import { compareToExpectedMultiple, compareToExpected } from './utils/test-helpers'

const headerHtml = readFileSync(join(__dirname, './test-files/header.html'), 'utf8')
Expand All @@ -21,47 +20,54 @@ const margin: PrintMargin = PrintMargin.ofMillimeters({
left: 17,
})

// TODO: find out how to run without those options
// Travis-CI Docker image workaround
const puppeteerOptions: MkPdfOptions = {
puppeteer: {
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
},
}

const TEST_TIMEOUT = 10000 // 10 seconds
const OUTPUT_NEW_EXPECTED_FILES = false

let converter: HtmlToPdfConverter

beforeAll(async () => {
// TODO: find out how to run without those options
// Travis-CI Docker image workaround
const puppeteerOptions: MkPdfOptions = {
puppeteer: {
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
},
}

converter = await initialize(puppeteerOptions)
})

afterAll(async () => {
await converter.destroy()
})

describe('mkCompoundPdf()', () => {
it(
'text footer',
async () => {
const pdfBuffer = await mkCompoundPdf(
[
{
pdfContent: firstPageHtml,
footer: {
type: 'TextSlot',
left: {
fontPath: fontPath,
text: 'https://github.com/moshensky/html-to-pdf-converter',
size: footerFontSize,
underline: true,
color: 0x0060bf, // '#0060bf'
},
right: {
fontPath: fontPath,
text: 'Page {page} of {pages}',
size: footerFontSize,
color: 0x000000, // '#000000'
},
const pdfBuffer = await converter.mkCompoundPdf([
{
pdfContent: firstPageHtml,
footer: {
type: 'TextSlot',
left: {
fontPath: fontPath,
text: 'https://github.com/moshensky/html-to-pdf-converter',
size: footerFontSize,
underline: true,
color: 0x0060bf, // '#0060bf'
},
right: {
fontPath: fontPath,
text: 'Page {page} of {pages}',
size: footerFontSize,
color: 0x000000, // '#000000'
},
margin,
pageSize: pageSizeInMM.A4.portrait,
},
],
puppeteerOptions,
)
margin,
pageSize: pageSizeInMM.A4.portrait,
},
])

await compareToExpected('textFooter', pdfBuffer, OUTPUT_NEW_EXPECTED_FILES)
},
Expand All @@ -72,29 +78,26 @@ describe('mkCompoundPdf()', () => {
it(
'multiple pages with different html footers',
async () => {
const pdfBuffer = await mkCompoundPdf(
[
{
pdfContent: firstPageHtml,
footer: {
type: 'HtmlSlot',
html: footerHtml,
},
margin,
pageSize: pageSizeInMM.A4.portrait,
const pdfBuffer = await converter.mkCompoundPdf([
{
pdfContent: firstPageHtml,
footer: {
type: 'HtmlSlot',
html: footerHtml,
},
{
pdfContent: resultsHtml,
footer: {
type: 'HtmlSlot',
html: footerHtml,
},
margin,
pageSize: pageSizeInMM.A4.landscape,
margin,
pageSize: pageSizeInMM.A4.portrait,
},
{
pdfContent: resultsHtml,
footer: {
type: 'HtmlSlot',
html: footerHtml,
},
],
puppeteerOptions,
)
margin,
pageSize: pageSizeInMM.A4.landscape,
},
])

await compareToExpectedMultiple('htmlFooter', pdfBuffer, OUTPUT_NEW_EXPECTED_FILES)
},
Expand All @@ -104,20 +107,17 @@ describe('mkCompoundPdf()', () => {
it(
'single page with html header',
async () => {
const pdfBuffer = await mkCompoundPdf(
[
{
pdfContent: firstPageHtml,
header: {
type: 'HtmlSlot',
html: headerHtml,
},
margin,
pageSize: pageSizeInMM.A4.portrait,
const pdfBuffer = await converter.mkCompoundPdf([
{
pdfContent: firstPageHtml,
header: {
type: 'HtmlSlot',
html: headerHtml,
},
],
puppeteerOptions,
)
margin,
pageSize: pageSizeInMM.A4.portrait,
},
])

await compareToExpected('singlePageWithHtmlHeader', pdfBuffer, OUTPUT_NEW_EXPECTED_FILES)
},
Expand Down
31 changes: 22 additions & 9 deletions src/compound-pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,10 @@ export interface MkPdfOptions {
puppeteer?: puppeteer.LaunchOptions
}

export const mkCompoundPdf = async (
const mkCompoundPdf = async (
contents: PdfContentWithSlots[],
options: MkPdfOptions = {},
browser: puppeteer.Browser,
): Promise<Buffer> => {
const browser = await puppeteer.launch(options.puppeteer)
const page = await browser.newPage()
const pdfsWithSpaceForSlots: {
content: PdfWithSpaceForSlots
Expand Down Expand Up @@ -147,20 +146,34 @@ export const mkCompoundPdf = async (
startPage += pagesCount
}

await browser.close()
await page.close()

return appendPdfs(pdfsWithSlots)
}

export const mkPdf = async (
const mkPdf = async (
{ margin, pageSize, pdfContent }: PdfContent,
options: MkPdfOptions = {},
browser: puppeteer.Browser,
): Promise<Buffer> => {
const browser = await puppeteer.launch(options.puppeteer)
const page = await browser.newPage()
const pdfBuffer = await mkSizedPdf(pdfContent, page, pageSize, margin)

await browser.close()
await page.close()

return pdfBuffer
}

export interface HtmlToPdfConverter {
mkCompoundPdf: (contents: PdfContentWithSlots[]) => Promise<Buffer>
mkPdf: (content: PdfContent) => Promise<Buffer>
destroy: () => Promise<void>
}

export const initialize = async (options: MkPdfOptions = {}): Promise<HtmlToPdfConverter> => {
const browser = await puppeteer.launch(options.puppeteer)

return {
mkCompoundPdf: (contents: PdfContentWithSlots[]) => mkCompoundPdf(contents, browser),
mkPdf: (content: PdfContent) => mkPdf(content, browser),
destroy: () => browser.close(),
}
}
Loading

0 comments on commit e8c394b

Please sign in to comment.