はじめに
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
を用意します。
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',
});
引数はそのほかにも、decide
がundefined
を返した時のフラグ値となるdefaultValue
やフラグの説明を記述するdescription
、フラグが管理されるURLを指定するorigin
、フラグの値によってどのようにVercelのツールバーに表示するかを決めるoptions
があります。
定義したshowFeatureA
は非同期コンポーネントで以下のように呼び出します。
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>
);
}
decide
がfalse
を返せば「デフォルト」が表示され、decide
がture
を返すば「機能1」が表示されます。
middleware
を使えばA・Bテストのようなこともできます。
まず、50%の確率でshowTypeA
関数のresolvedされる値がtrue
になるフラグを定義します。
import { unstable_flag as flag } from '@vercel/flags/next';
...
export const showTypeA = flag({
key: 'type-a',
decide: () => Math.random() > 0.5,
});
それを元に、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が出てきます。
その内容は.well-known/vercel/flags
にフラグの内容を記述してくれというものです。
Route Handlerで記述しましょう。伝える内容は@vercel/flags
でApiData
として提供されているのでそれを元に作成します。
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に切り替わります。
feature-a
のトグルボタンを切り替えて、Applyを押すとそのフラグが画面に反映されます。
dashboard
を開いてからtype-a
のトグルボタンをonにしてApplyを押すと「通常のダッシュボード」が必ず表示されます。offにすると「type-aのダッシュボード」が表示されます。
A・Bテストを実行しつつも、開発側で表示する画面を決められるのはかなり嬉しいです。
おわりに
Feature Flags
でできることを簡単に紹介しました。
この記事で紹介した機能の他にも、LCPや画面のチラつきを抑制するフラグの事前読み込みや、Vercelが提供する他のパッケージと組み合わせて利用する機能、ツールバーで上書きした値についてCookieをもとに検証するdecrypt
機能などさまざまな機能が提供されています。
Vercelを利用している人にとってはかなり便利なので、使ってみてはいかがでしょうか。