GAミント至上主義

安くて速いが好きなWEBアプリ開発者。最近はPython, Vue.js, Firebase, GKE。@株式会社ビズオーシャン

Headless Chrome + puppeteerを使ったHTML→PDF変換サーバーを作る puppeteer編

Headless Chromeを使ったHTML→PDF変換サーバー第3弾。

前回は下記。
ヘッドレスChrome + Node.js + express + DockerでPDF生成サーバーを作る - 仕事中の問題と解決メモ。
ヘッドレスChromeを使ったHTML→PDF変換サーバーを作る 改善編 - 仕事中の問題と解決メモ。

下記の記事をどっかで発見し、つい最近Chromeの開発チームが作っているクライアントPuppeteerがv1になったということでこっちに変更してみた。
www.infoq.com

以前のものはchrome-remote-interfaceを使っていた。
github.com

さすが公式なのか、PDF生成に200ms程度かかっていたのが、Puppeteerに書き直したら100ms以下になった。

ドキュメントもさすがGoogle、しっかりしていてよい。

github.com

まだ動いたばっかりだけどコードもかなりすっきりした。

(async function() {
  const chromeBinary = '/usr/bin/google-chrome'
  const options = {
    landscape: false,
    format: 'A4',
    printBackground: true,
    displayHeaderFooter: false,
    margin :{top:0, right:0, bottom:0, left:0}
  };
  console.log("RenderPDF options\n", options);
  const puppeteer = require('puppeteer');
  const express = require('express');
  const app = express();
  const timeout = require('connect-timeout');
  const timeout_msec = 5000;
  app.use(timeout(timeout_msec));

  const launchOptions = {args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu'], executablePath: chromeBinary};
  const browser = await puppeteer.launch(launchOptions);
  console.log("chrome version:", await browser.version());
  const page = await browser.newPage();

  app.listen(8000, function(){
    console.log('Listening on 8000');
  });

  app.get('/', async (req, res) => {
    const url = req.query.url;

    if (! url) {
      res.status(404);
      res.end('parameter "url" is not set');
      return;
    }
    try{
      console.time('rennderPdf');
      await page.goto(url, {timeout: 10000, waitUntil:["load", "domcontentloaded"]});
      const buff = await page.pdf(options);
      console.timeEnd('rennderPdf');
      res.contentType("application/pdf");
      res.send(buff);
      res.status(200);
      res.end();
    } catch(e) {
      console.log(e);
      res.status(503);
      res.end();
    }
  });
  // Health Check
  app.get('/hc', function (req, res) {
    console.log('health check ok');
    res.setHeader( 'X-Chrome-Version', chromeVersion);
    res.status(200);
    res.end('ok');
  });
  process.on('SIGINT', async function() {
    await browser.close();
    console.log('process exit with SIGINT');
    await process.exit();
  });
})();

いたるところでawaitが必要になるので、expressも含めすべてをasyncで囲んでいる。
とりあえずawaitしまくればいつもの言語と近い感じで書けるのを覚えてしまった。