Help us understand the problem. What is going on with this article?

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にする必要があった
    • 最初256MBにしていて、browserがlaunchできなかったいうようなエラーが出て、chrome-aws-lambdaもダメかあと思っていたところBUG報告で512MBにしたらできたで、って書いてあった
  • .fontsをちゃんとzipファイルに含める
    • Lambda環境に日本語フォントはない。自分で.fontsとして読み込ませる必要があるが、日本語が反映されへんな〜と思ったら.fontsをzipファイルに含むのが漏れていたというオチだった

コード

構造

┣ pdfGenerator.js
┣ package.json
┣ package-lock.json
┣ .fonts
  ┣ ipaexg.ttf
  ┣ ipaexm.ttf

コード

pdfGenerator.js
/* 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);
    }
};

参考リンク

https://github.com/alixaxel/chrome-aws-lambda/issues/82

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした