marcbachmann / node-html-pdf

This repo isn't maintained anymore as phantomjs got dreprecated a long time ago. Please migrate to headless chrome/puppeteer.
MIT License
3.56k stars 543 forks source link

This package should either be updated or deprecated #601

Open LarsVonQualen opened 3 years ago

LarsVonQualen commented 3 years ago

DISCLAIMER: This is not an attack on the creator of this package. Consider it a path forward if PhantomJS never gets undeprecated.

This package relies on PhantomJS, which has suspended further development according to this! That means that the phantomjs-prebuilt package has been marked as deprecated and has not seen any updates, as of writing, in 3 years.

I tried forking and updating this package, but discovered that puppeteer actually support exactly the same things, probably because phantomjs also targeted chrome. Furthermore is puppeteer seeing active development. I tried switching phantomjs for puppeteer, but found that puppeteers interface is so simple, that it doesn't really make sense to wrap it.

I found two good resources for puppeteer:

And lastly here is my own typescript class wrapping puppeteer for convience, which does the exact same thing as this package:

import { launch, LaunchOptions, NavigationOptions, PDFOptions, MediaType } from 'puppeteer';

export interface PuppeteerOptions {
  emulateMedia?: MediaType;
  launch?: LaunchOptions;
  navigation?: NavigationOptions;
  pdf?: PDFOptions;
}

export class PuppeteerRenderer {
  public defaultOptions: PuppeteerOptions = {
    pdf: {
      format: 'A4',
    },
  };

  constructor(private options: PuppeteerOptions = {}) {}

  public async renderFromHtml(html: string) {
    const { browser, page } = await this.getBrowserAndPage();

    await page.setContent(html, this.options?.navigation ?? {});

    const pdfOptions: PDFOptions = this.options?.pdf ?? {};
    const buffer = await page.pdf({
      ...this.defaultOptions,
      ...pdfOptions,
    });

    await browser.close();

    return buffer;
  }

  /**
   *
   * @param path The file path to save the PDF to. If path is a relative path, then it is resolved relative to current
   * working directory. If no path is provided, the PDF won't be saved to the disk.
   */
  public async renderFromHtmlToFile(html: string, path: string) {
    const { browser, page } = await this.getBrowserAndPage();

    await page.setContent(html, this.options?.navigation ?? {});

    const pdfOptions: PDFOptions = this.options?.pdf ?? {};
    await page.pdf({
      ...this.defaultOptions,
      ...pdfOptions,
      path,
    });
    await browser.close();
  }

  private async getBrowserAndPage() {
    const browser = await launch(this.options?.launch ?? {});
    const page = await browser.newPage();

    if (this.options?.emulateMedia) {
      await page.emulateMediaType(this.options.emulateMedia);
    }

    return { browser, page };
  }
}
crazyoptimist commented 3 years ago

Looks great. It's pretty simple but you can still publish it as another package to npm registry.

ckifer commented 2 years ago

Bumping this as this package should still be updated or deprecated.