目次
以下の画像のようにLambda+VueでOGP画像を生成してS3に保存する仕組みを作ったので記録を残します。
![](https://i.gyazo.com/4a15a155e51f7f2e93aa9a115857a1b0.png)
これはContentfulというヘッドレスCMSを使用してメディア(セリフデータベース)を作成した際の副産物になります。
何ができるのか?
LambdaにPOSTリクエストを送ると、以下赤枠の様なOGP画像を生成してS3に保存します。
OGP画像のデザインはVueコンポーネントとしてカスタマイズできます。凝ったデザインのOGP画像も作成できるのが強みです。
また、送信したテキストをOGP画像に埋め込んだり出来ます。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fi.gyazo.com%2Fbe4f488854b56801a6b3218c6c08155b.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=dc35ee1f41d11ba67e4a1445f003b5f4)
ライブラリとして切り出しました
serverless-vue-ogp-rendererに置いています。
READMEにしたがってコマンドを打てばローカルで動作確認できるようになっています。
よかったら参考にしてみてください。
Serverless Frameworkについて
Serverlessフレームワーク を使用する事で、簡単にLambdaアプリケーションが作成できます。
今回作成したツールはこのServerlessフレームワークを使用しています。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fi.gyazo.com%2F288452b615bcdfb4f3285c866a68cfda.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=522f5e33b2f8edf3faf133c862465927)
Serverlessフレームワークとは、サーバーレスな環境にアプリケーションを構築/デプロイできるフレームワークで、AWSやGCP, Azureなどのプラットフォームをサポートしています。
YAMLベースの設定ファイルを記述しコマンドを実行すると環境が構築され、アプリケーションがデプロイされます。
今回使用した設定ファイルは以下の通りです。(ファイルはこちら)
service: serverless-vue-ogp-renderer provider: name: aws runtime: nodejs12.x stage: prod region: ap-northeast-1 functions: app: handler: index.handler events: - http: POST /render plugins: - serverless-offline - serverless-dotenv-plugin
/render
にリクエストを送信するとindex.js
のhandler
関数が呼び出されるようになっています。serverless-offline
プラグインを使用してローカルで動作確認できるようにしています。serverless-dotenv-plugin
で.env
ファイル(環境毎の設定)をロードできるようにしています。
Puppeteerについて
puppeteerはプログラムからchromiumを操作できるライブラリです。
![](https://i.gyazo.com/0a0d0fc32e03c0dc9ba98f832a966ffe.png)
puppeteer経由でchromiumを操作して、Vueを描画&画像として保存します。
1点ハマりポイントがありまして、lambda上で使用する場合、ファイルサイズの問題で通常のchromiumが使用できません。
なので今回は、lambda向けに軽量化されたchromium(chrome-aws-lambda)を使用しました。
自分はVueComponentRenderer
というクラスを作成してchromiumに関する処理をまとめました。(ファイルはこちら)
いくつかかいつまんで説明します。
chromiumを起動する
const browser = await chromium.puppeteer.launch({ args: chromium.args, executablePath: await chromium.executablePath, headless: chromium.headless, ignoreHTTPSErrors: true, defaultViewport: { width, height, } });
ページを開く
あらかじめ、Vueコンポーネントを描画するhtmlを用意しておき、それを開きます。
await page.goto('file://' + dir + '/renderer/dest/renderer.html', {waitUntil: 'networkidle2'});
Vueにパラメータを渡す
リクエストで送信されたテキストをVueに渡しています。
Vueのコンポーネント側では$body
をwatchしており、値が設定されるとコンポーネントが再描画される仕組みになっています。
await page.evaluate((body) => { window.vue.$body = body; }, reqBody);
スクリーンショットを撮影する
await page.screenshot({ path: outPath, clip: { x: 0, y: 0, width, height } });
S3への画像の保存について
aws-sdkを使用しています。
今回はS3Repository
というクラスに処理をまとめました。(ファイルはこちら)
特に珍しいものはないので解説はしません。
おわりに
最後に、処理の大枠であるindex.jsをざっくり紹介すると、以下の画像のようになります。
![](https://i.gyazo.com/1647b275bccf970d8299de3a4a2931a6.png)
副作用(※)を伴う処理をクラスとして切り出しただけですが、ひと目見れば大筋の処理が分かるコードになりました。
※通信やディスクIOを伴う処理の事
副作用を別のクラスに切り出す事でユニットテストが掛けるようにもなるので、こういう書き方があたりまえになるといいなぁと常々願ってます。(仕事で2000行超えのファイルに苦しめられながら)
以上です!
Webエンジニアをやっています
UX/UIデザインからプログラミング、DB設計、SEO、インフラ構築など幅広く対応してます
PHP/PHPUnit/Laravel/Vue/Nuxt/Docker/Terraform
ご連絡はTwitterのDMまで。