Node12系 AWS LambdaでHTMLをPDFに変換しようとしたらいろいろハマった
Node8系でwkhtmktopdfを使ってHTMLをPDFに変換するLambdaを使っていたのだが、Node8系で動いていた。 Node8系がサポートされなくなるということで、12系にそのままあげたら動かなくなってしまったのでNode12系でHTMLをPDFに変換するLambdaを作り直す必要が出てきた。
HTMLをPDFに変換するLambdaについては結構多くの記事が見つかったが、なかなか上手くいかなかった。
やりたかったこと
Lambdaで日本語を含むHTMLをPDFに変換し、S3に保存する
試したが上手くいかなかった方法
- wkhtmlpdf
- 自分が見つけられなかっただけかもしれないが、Node12系でも問題なく動くソースを見つけられなかった
- html-pdf
- phantomjsの128エラーでちっとも動かなかった
- puppeteer
- 動きそうな気配はあったが、node_modulesのサイズが大きすぎてLambdaの最大ソースサイズをオーバーしてしまった
上手く行った方法
使用モジュール
chrome-aws-lambda を使った。 puppeteer-coreもnpm installする必要があるが、puppeteerだと大きすぎるから必要なcoreだけ使ってるっぽい。
注意点
- Lambdaのメモリ設定を512MBにする必要があった
.fonts
をちゃんとzipファイルに含める- Lambda環境に日本語フォントはない。自分で.fontsとして読み込ませる必要があるが、日本語が反映されへんな〜と思ったら.fontsをzipファイルに含むのが漏れていたというオチだった
コード
構造
┣ pdfGenerator.js ┣ package.json ┣ package-lock.json ┣ .fonts ┣ ipaexg.ttf ┣ ipaexm.ttf
コード
/* Lambda環境でも日本語フォントを使えるようにするには.fontsを読み込ませるためにHOMEを設定する必要ある */ process.env['HOME'] = "/var/task"; process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT']; const AWS = require("aws-sdk"); const S3 = new AWS.S3({ signatureVersion: "v4" }); const chromium = require("chrome-aws-lambda"); exports.handler = async function(event, context, callback) { try { if (!event.html) { callback("unable to get html"); return; } const fileName = event.filename, tmpFileName = `/tmp/${Math.random().toString(36).slice(2)}.pdf`, bucket = event.bucket, pageSize = event.pageSize || "A4", html = event.html; const executablePath = await chromium.executablePath, browser = await chromium.puppeteer.launch({ args: chromium.args, defaultViewport: chromium.defaultViewport, executablePath, headless: chromium.headless, ignoreHTTPSErrors: true }); const page = await browser.newPage(); await page.setContent(html); const pdf = await page.pdf({ path: tmpFileName, format: pageSize }); browser.close(); S3.putObject({ Bucket: bucket, Key: fileName, Body: pdf, ContentType: "application/pdf" }, (error) => { callback(error); }); } catch(e) { callback(e); } };