2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1人フロントエンドAdvent Calendar 2024

Day 23

Vercelが提供するFeature flagsをNext.jsと合わせて利用する

Last updated at Posted at 2024-12-23

はじめに

VercelではFeature Flagsと呼ばれる特定の機能のOn・Offを切り替える機能が提供されています。

Feature Flagsを使えば、特定のタイミングでのみ表示させる機能や、アクセス時にランダムで異なるパスへ振り分ける機能を簡単に作れます。

この記事ではNext.jsでFeature Flagsを使う方法と、Vercelへデプロイしたときに使える便利な機能を紹介します。

この記事で利用したコードはGitHub上に上げています。

フラグの動きはVercel上にアップロードしたサイトで確認出来ます

Feature Flagsは執筆現在、beta版として公開されています。製品版になるまでにいくつか変更が加わる可能性があるのでご了承ください。

Next.js

Feature Flags機能は@vercel/flagsパッケージを用いて利用します。

pnpm i @vercel/flag

パッケージをインストールしたら、環境変数をFlags_SECRETを登録します。公式では次のコマンドで生成することを勧めています。

node -e "console.log(crypto.randomBytes(32).toString('base64url'))"

Vercelのツールバーと連携してフラグを上書したときにその値を読み取るために使用するようです。

フラグを管理するファイルflag.tsを用意します。

flag.ts
import { unstable_flag as flag } from '@vercel/flags/next';

export const showFeatureA = flag({
  key: 'feature-a',
  decide: () => false,
});

unstable_flag関数を用いて利用するフラグを定義しています(今後は単にflag関数と呼びます。)。showFeatureAは機能Aを表示するかしないかを判定する非同期関数です。await showFeatureA()でフラグを取り出します。

引数のkeyはこのフラグを識別するための一意な文字列です。

もう1つの引数であるdecideはフラグの値を決めるための関数です。この場合は常にfalseを返すので、Offになります。decideには非同期な関数も渡せます(showFeatureAが非同期関数なのはおそらくこのためです)。

decideを利用すれば環境変数をベースにフラグを切り替えることもできます。

import { unstable_flag as flag } from '@vercel/flags/next';

export const showFeatureA = flag({
  key: 'feature-a',
  decide: () => process.env.FEATURE_A_ENABLED === '1',
});

引数はそのほかにも、decideundefinedを返した時のフラグ値となるdefaultValueやフラグの説明を記述するdescription、フラグが管理されるURLを指定するorigin、フラグの値によってどのようにVercelのツールバーに表示するかを決めるoptionsがあります。

定義したshowFeatureAは非同期コンポーネントで以下のように呼び出します。

app/page.tsx
import { showFeatureA } from "./../flag";

export default async function Home() {
  const featureA = await showFeatureA();
  return (
    <main className="flex flex-col items-center justify-center h-screen gap-8">
      {featureA ? <div>機能1</div> : <div>デフォルト</div>}
    </main>
  );
}

decidefalseを返せば「デフォルト」が表示され、decidetureを返すば「機能1」が表示されます。

middlewareを使えばA・Bテストのようなこともできます。
まず、50%の確率でshowTypeA関数のresolvedされる値がtrueになるフラグを定義します。

flat.ts
import { unstable_flag as flag } from '@vercel/flags/next';

...

export const showTypeA = flag({
  key: 'type-a',
  decide: () => Math.random() > 0.5,
});

それを元に、middlewareでレスポンスを書き換えます。

middleware
import { NextResponse, type NextRequest } from 'next/server';
import { showTypeA } from './flag';

export const config = { matcher: ['/dashboard', '/dashboard/type-a'] };

export async function middleware(request: NextRequest) {
  const typeA = await showTypeA();

  const url = typeA ? '/dashboard/type-a' : '/dashboard';

  if (request.url.endsWith('type-a')) {
    request.nextUrl.pathname = '/dashboard';
    return NextResponse.redirect(request.nextUrl);
  }

  const nextUrl = new URL(url, request.url);
  return NextResponse.rewrite(nextUrl);
}

50%の確率で/dashboardへのアクセスを/dashboard/type-aの内容で表示するようにしました。

middlewareで実行することで、/dashboardの内容も/dashboard/type-aの内容も他のページと同じように構築できるので、middlewareの分岐処理を除いてパフォーマンス上の欠点がないのが良いところです。。

Vercelのツールバーで書き換える

この状態でVercelにアプリケーションを公開して、Vercelのツールバーを見てみましょう。(本番でツールバーを見るにはいくつかの準備が必要です。add-to-productionを読んでください)

私が作成したこれまで紹介したフラグを実装したサイトで確認できます(ツールバーを利用するにはVercelにログインが必要です。ツールバーが見えなければコメント等で教えてください)。

ツールバーにあるトグルボタンのような見た目をしたFlags Explorerをクリックするとフラグについて管理するUIが出てきます。
スクリーンショット 2024-12-23 17.49.02.png
その内容は.well-known/vercel/flagsにフラグの内容を記述してくれというものです。スクリーンショット 2024-12-23 20.16.41.png
Route Handlerで記述しましょう。伝える内容は@vercel/flagsApiDataとして提供されているのでそれを元に作成します。

app/.well-known/vercel/flags/route.ts
import { NextResponse, type NextRequest } from 'next/server';
import { verifyAccess, type ApiData } from '@vercel/flags';

export async function GET(request: NextRequest) {
  const access = await verifyAccess(request.headers.get('Authorization'));
  if (!access) return NextResponse.json(null, { status: 401 });

  return NextResponse.json<ApiData>({
    definitions: {
      ['feature-a']: {
        options: [
          { value: false, label: 'Off' },
          { value: true, label: 'On' },
        ],
      },
      ['type-a']: {
        options: [
          { value: false, label: 'Off' },
          { value: true, label: 'On' },
        ],
      },
    },
  });
}

verifyAccessでログインしていないユーザーを弾くようにして、flag.tsで作ったフラグを再定義しています。

このように情報をツールバーから取得できるようにすると、ツールバー上でフラグを切り替えるUIに切り替わります。
スクリーンショット 2024-12-23 20.30.56.png

feature-aのトグルボタンを切り替えて、Applyを押すとそのフラグが画面に反映されます。

dashboardを開いてからtype-aのトグルボタンをonにしてApplyを押すと「通常のダッシュボード」が必ず表示されます。offにすると「type-aのダッシュボード」が表示されます。
A・Bテストを実行しつつも、開発側で表示する画面を決められるのはかなり嬉しいです。

おわりに

Feature Flagsでできることを簡単に紹介しました。

この記事で紹介した機能の他にも、LCPや画面のチラつきを抑制するフラグの事前読み込みや、Vercelが提供する他のパッケージと組み合わせて利用する機能、ツールバーで上書きした値についてCookieをもとに検証するdecrypt機能などさまざまな機能が提供されています。

Vercelを利用している人にとってはかなり便利なので、使ってみてはいかがでしょうか。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?