この記事は DeNA 21 新卒 Advent Calendar 2020 の 17日目の記事です。
こんにちは。Pococha というライブコミュニケーションサービスの web チームで内定者アルバイトをしている小谷です。今回はサービスを運用していく上で必要不可欠である LP の実装自動化についてお話できればと思います!
Pococha の LP 事情
Pococha ではイベントの特設サイトなどの実装に画像 LP という独自のフォーマットを使用しています。 画像 LP とはなにか、3行で紹介すると
デザインにこだわった LP を作りたいけど
月に何本もコーディングするのは大変だから
ページ全体を画像で構成しちゃおう
というものです。例としてこのような LP を作っています。
画像 LP については DeNA Advent Calendar 2020 の同じく 17日目の記事、「 Pococha の LP を支える技術 」で紹介しています!ぜひこちらも合わせてご確認ください。
画像 LP のすごさ
画像 LP は普通にコーディングするよりも遥かに簡単に実装できます。 デザイナーより受け取ったデザインから背景画像とボタンを別々に書き出し、そのサイズや位置などを記入したメタファイルを用意するだけです。
3人日ほどかかりそうな LP であっても画像 LP であれば 2,3時間で実装できてしまいます。
画像 LP の抱える問題
実装コスト問題
しかし実際の運用では、修正が発生した場合に最初から実装し直しになってしまうことがあります。せっかく2時間程度で終わるはずが修正が入ることで半日浪費してしまうこともありました。
例えばボタンの中の文字を「応募する」から「利用規約に同意して応募する」へ変更になったとします。 通常の HTML コーディングであればテキストを修正するだけで終了です。HTML ではテキストに応じて要素のサイズが自動的に拡大されるためです。しかし画像 LP ではボタンも画像として扱うため再度書き出す必要があります。また、文字数が増えることでボタンの大きさが変わり、メタ情報も書き換えなければなりません。
レイヤー構造問題
また画像 LP では仕組み上、デザイン時のレイヤー構造に一部制限がかかります。デザイナーが作ったデザインに使用できないレイヤー構造が含まれていることに気づかず、実装後にレイアウトが崩れてから発覚したり、エンジニアが手直しするという問題ありました。
具体的にどういった構造が制限されるのか、例えばメタ情報にボタンの位置を記入することを考えてみます。Figma では一番近い Frame レイヤー(CSS でいう position: relative;
) を親とし、相対位置が表示されます (画像左)。そのため Figma 上に表示されている位置を入力するだけで問題ありません。しかし、Frame の中に Frame が含まれるようなレイヤー構造になっていると、基準となる親レイヤーがズレてしまい正しい座標を表示してくれません (画像右)。
これらを解消するために画像 LP の構造チェック・自動生成ツールを作成することにしました。
Figma 上で自動化を検討
要件を満たせる API を探します。 Figma には開発者向けの API が2種類あります。
-
REST APIです。これはデザインを操作するというより、プロジェクトやユーザーを管理するために使用する API です。なので今回のレイヤーを操作したり、画像を書き出したりする用途には使用できません。
-
こちらは API とは異なり GUI を持つプラグインです。Figma 上のレイヤー情報を読み取ったり書き換えたりすることができます。今回はこちらを使用します。
Figma Plugin は Setup Guide を見ながら進めれば誰でもかんたんに作成できます。 JavaScript (TypeScript) で動作し、Electron のようにメインプロセスとレンダラプロセスに分かれて動作します。 メインプロセスではレイヤーへのアクセスができますが、UI を操作することはできません。レンダラプロセスはその逆です。
Figma Plugin では以下のようなコードでレイヤーにアクセスすることができます。
レイヤー情報の取得
/* main.ts */
// 'button' というレイヤー名のノードを取得
const button = figma.currentPage.findOne(node => node.name === 'button');
// ボタンの位置とサイズを取得
const {x, y, width, height} = button;
画像として書き出し
エクスポート処理はメインプロセス側で行えますが、 fs
モジュールは使えないのでダウンロードするときはレンダラプロセスに投げる必要があります。
/* main.ts */
// API で書き出すと Unit8Array で出力される
const unit8array = await button.exportAsync({ format: 'PNG' });
// レンダラプロセスに画像を送る
figma.ui.postMessage(unit8array);
/* renderer.ts */
window.onmessage = e => {
// メインプロセスから送られてきた Unit8Array データ
const unit8array = e.data.pluginMessage;
// ダウンロードするために blob に変換
const blob = new Blob([unit8array], { type: 'image/png' });
// ダウンロードリンクを作ってクリック
const a = document.createElement('a');
a.style.display = 'none';
a.href = URL.createObjectURL(blob);
a.download = 'button.png';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
詳しい実装方法は検索していただければ他の方の記事が出てくると思いますのでそちらでご確認ください。
画像 LP Generator 爆誕
そして今回作成したのがこちら、画像 LP Generator です! 先程あげた問題を解決するための機能が実装されています。
レイヤー構造問題への解決
プレビュー時に構造チェックを行うようにし、書き出し前にレイヤー構造が正しく実装されているかを確認できるようにしました。これにより実装して初めて気づくという見落としを防ぎます。
現時点ではエンジニアのみで使用していますが、将来的にはデザイナーにもこのプラグインを配布する予定です。 デザイナー自身でも構造チェックを行えるようにすることでエンジニアに渡ってきた段階でデザインが完璧に実装されていることが保証されるほか、デザイナー自身でどのように出力されるのかを視覚的に確認できるようになります。
実装コストへの解決
画像 LP の実装は普通にコーディングするよりも手軽とはいえ、画像の書き出しやメタ情報の作成が必要でした。 このプラグインに実装されたエクスポート機能を使用することでそれを自動化できるようにしました。ボタンをひとつ押すだけですべての画像とメタ情報を含んだ zip ファイルがダウンロードできます。
自動生成が可能になったことで実装工数も減り、修正が発生した場合でも瞬時に対応することができるようになりました。
画像 LP Generator の誕生でどうなったか
実装時間が 1時間から 30秒へ
画像 LP Generator によって LP を**ボタン一つで生成できるようになりました!**もはや実装時間よりもデプロイ時間のほうが長い! LP を 30秒で実装できるってエンジニアにとっては夢のような話ではないでしょうか。
脱属人化
また今まで画像 LP はやり方を知らないと実装することが難しく、属人化していました。画像 LP Generator の誕生により誰でもかんたんに実装できるようになったため、早速画像 LP の実装ができる人を増やすことができました。工数削減だけでなく属人化すら排除できるプラグイン、いい話ですね。
さいごに
フロントエンドエンジニアと LP は切っても切れない関係にあると思います。いかにして効率的に、こだわって実装できるか。その課題に向かって私たちがどのような挑戦をしたかをご紹介できたかなと思います。 会社やサービスによって LP の事情が異なるとは思いますが、この画像 LP の仕組みが少しでも参考になれば幸いです。
この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ Twitter や facebook、はてなブックマークにてコメントをお願いします!
また DeNA 公式 Twitter アカウント @DeNAxTech では、 Blog記事だけでなく色々な勉強会での登壇資料も発信してます。ぜひフォローして下さい!
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。