Next.jsのブログにInstagramストーリーズ向けシェア機能を実装したので振り返り

Next.jsのブログにInstagramストーリーズ向けシェア機能を実装したので振り返り

投稿日: 2024年10月02日

Tips
要約
  • Next.jsを使ってInstagramのストーリーズ用画像を生成しダウンロードする仕組みを作成した。
  • puppeteer-coreと@sparticuz/chromiumを使って、指定のページをスクリーンショットしAPI経由で画像データを返す。
  • ユーザーは取得した画像をダウンロードしてInstagramでシェアできるようにした。

Instagramでは、Xのような公式のシェア機能がありません。

ですが、僕のスクールは一応Instagramから始まったのもあり、できればInstagramでシェアしやすい仕組みが欲しいなと思いました。

Instagramで手軽に投稿というとストーリーズなので、

  1. 記事ページでInstagramシェアボタンを押す
  2. 記事情報が表示された、ストーリーズサイズの画像が生成される
  3. ダウンロードしてストーリーズ投稿に使える

こんな機能をNext.jsで作ってみました。

処理の流れ

実装方針としては、

「Next.js内に隠しURLを作って、そこにストーリーサイズで記事情報が表示されるページを作り、そのページをスクショしてダウンロードする」

という処理を行うことにしました。

動的なOGP画像を生成する際などに、よく使われる手法です。

1. ストーリーサイズの表示用ページの作成

まず、隠しURLを作って、ストーリーズサイズ(縦長の1920px - 1080px)で記事情報を表示させるページを作ります。

このページが、後にスクリーンショットを撮る対象となります。

このページは以下のURLに実装しています。

https://shiftb.dev/story_images/n_ziqaqgh

2. ストーリー画像取得用APIの作成

次に、バックエンドでWebブラウザを立ち上げ、上記ページにアクセスし、スクリーンショットを撮るためのAPIを作成しました。

以下のライブラリを使用しています。

  • puppeteer-core: Node.jsでブラウザを自動操作するライブラリ
  • @sparticuz/chromium: AWS LambdaやVercelなどのサーバーレス環境でもChromiumを起動するためのパッケージ

ChromiumとはGoogle Chromeのオープンソース版のブラウザです。今回のようなWebページのスクショを撮ったり、スクレイピングでWebサイトから情報を抜き取る際によく使います。
通常、サーバー側でブラウザを操作するのはかなり重たい処理です。AWS Lambdaのようなサーバーレス環境ではリソースが限られているため、軽量化されたChromiumが使用されます。@sparticuz/chromiumは、この軽量なChromiumをサーバーレス環境でも動かせるようにするためのライブラリです。

以下、これらのライブラリを用いて書いたコードです。

import chromium from "@sparticuz/chromium";
import { NextRequest, NextResponse } from "next/server";
import puppeteer from "puppeteer-core";

export async function GET(
  _request: NextRequest,
  { params: { id } }: { params: { id: string } }
) {
  // ブラウザを起動
  const browser = await puppeteer.launch({
    args: chromium.args,
    defaultViewport: chromium.defaultViewport,
    executablePath: await chromium.executablePath(),
    headless: chromium.headless,
    ignoreHTTPSErrors: true,
  });

 // ブラウザのタブを開く
  const page = await browser.newPage();

 // スクショ対象のページにアクセス
  await page.goto(`${process.env.NEXT_PUBLIC_APP_BASE_URL}/story_images/${id}`);

  // ページの表示が完了するまで待つ
  await page.waitForSelector("body", { visible: true });

  // サイズを指定してスクショを撮ってbase64方式の画像データを取得
  const image = await page.screenshot({
    encoding: "base64",
    fullPage: false,
    clip: { x: 0, y: 0, width: 1080, height: 1920 },
  });

  // ブラウザを閉じる
  await browser.close();

  // 取得した画像データをクライアントに返す
  try {
    return NextResponse.json({ status: "OK", image }, { status: 200 });
  } catch (error) {
    return NextResponse.json(error);
  }
}

3. フロントエンドでの表示とダウンロード

フロントエンドでは、このAPIから取得した画像をユーザーに表示します。

ユーザーはこの画像を、PCなら右クリック、スマホなら長押しでダウンロードし、Instagramのストーリーズとしてシェアすることができます。

動作

こんな感じです。

こちらもShiftBのリポジトリで見れるので、動的に画像を生成みたいな機能を作りたい方は、参考にしてみてください。

シェア!

Threads
icon
ぶべ
Webの修行中 / 個人開発奮闘中 / ベンチプレス110kg / Reactの先生
Loading...
記事一覧に戻る
Threads
0