🙆

Unleash + Next.jsでフィーチャーフラグを実装する

2024/12/15に公開

以前の記事でバックエンドのUnleashを使ってフィーチャーフラグを実装しました。今回はフロントエンドのNext.jsでUnleashを使ってフィーチャーフラグを実装する方法を紹介します。

Next.jsのプロジェクトを作成

まずはNext.jsのプロジェクトを作成します。

$ npx create-next-app@latest --ts
Need to install the following packages:
create-next-app@15.1.0
Ok to proceed? (y) y

✔ What is your project named? … unleash-client-demo
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to use Turbopack for `next dev`? … Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No

ブラウザで http://localhost:3000 にアクセスします。以下のデフォルト画面が表示されます。

UnleashをローカルPCでセットアップ

UnleashのサーバをローカルPCでセットアップします。(本記事での方法はローカルPC上での動作確認のための方法であり、デフォルトのパスワードを使用するなどのセキュリティ上の問題があります。本番環境で使用する場合は別の方法でセットアップするようにしてください。)

Unleashサーバの起動

UnleashのサーバはDockerイメージとして提供されているので、Dockerを使ってローカルPC上で起動させます。適切なディレクトリ上で、以下のようにUnleashサーバを起動します。

wget https://raw.githubusercontent.com/Unleash/unleash/refs/heads/main/docker-compose.yml
docker compose up -d

管理画面へのサインイン

ブラウザで http://localhost:4242 にアクセスします。以下のサインイン画面が表示されます。以下の認証情報を入力してSign inボタンをクリックします。

User name: admin
Password: unleash4all

フィーチャーフラグの作成

左上のメニューから Projects を選択します。

Default プロジェクトを選択します。

Create flag ボタンをクリックします。

Feature flag nameDescriptionにフラグの名前と説明を入力し Create feature flag ボタンをクリックします。本記事ではタスク管理サービスで締め切り日時の管理機能の追加を例に解説するので名前を support-due-date-time-frontend としました。

トークンの発行

Connect SDK ボタンをクリックします。

Client side SDKsReactを選択します。

Enviroment を選択して、Nextボタンをクリックします。今回はローカルPCで動かすだけなのでdevelopmentを選択しています。

接続のための設定が表示され、クライアントからの接続待ち状態になります。

フィーチャーフラグを使ったWeb画面の実装

タスク管理アプリのAPIサーバで、フィーチャーフラグが有効になるとレスポンスに締め切り日時が表示されるケースを考えてみます。

締め切り機能追加前の状態を実装

まずは締め切り機能が追加されていない状態を実装します。

Todoの型を定義します。

src/app/Todo.ts
export type Todo = {
  id: string;
  title: string;
  description: string;
};

Todoのコンポーネントを作成します。

src/app/TodoComponent.tsx
import { Todo } from "./Todo";

export const TodoComponent = (todo: Todo) => {
    return (
        <li key={todo.id}>
            <h2 className='text-lg font-bold'>{todo.title}</h2>
            <p>{todo.description}</p>
        </li>
    )
};

page.tsxを以下のように修正します。

src/app/page.tsx
'use client'
import { Todo } from "./Todo";

const unleashConfig = {
    url: 'http://localhost:4242/api/frontend/',
    clientKey: 'default:development.unleash-insecure-frontend-api-token',
    appName: 'unleash-onboarding-react'
}

const todos: Todo[] = [
    {
        id: '1',
        title: 'Learn Next.js',
        description: 'Learn Next.js and build something great',
        dueDate: '2025-01-01'
    },
    {
        id: '2',
        title: 'Build something great',
        description: 'Learn Next.js and build something great',
        dueDate: '2025-01-02'
    }
]

export default function Home() {
  return (
      <FlagProvider config={unleashConfig}>
          <div className='container mx-auto p-4'>
              <h1 className='text-3xl font-bold mb-4'>Todo</h1>
              <ul className='list-disc'>
                  {todos.map(todo => (
                      <TodoComponent key={todo.id} {...todo} />
                  ))}
              </ul>
          </div>
      </FlagProvider>
  );
}

ブラウザには以下のように表示されます。

フィーチャーフラグを使った締め切り機能の追加

Todoの型をdueDateを追加します。

src/app/Todo.ts
export type Todo = {
  id: string;
  title: string;
  description: string;
  dueDate?: string;
};

Todoのコンポーネントを修正します。

src/app/TodoComponent.tsx
import { useEffect } from "react";
import { useFlag } from "@unleash/proxy-client-react";
import { Todo } from "./Todo";

export const TodoComponent = (todo: Todo) => {
    const hasVisited =
        typeof window !== "undefined" && !!localStorage.getItem("hasVisited");

    useEffect(() => {
        if (!hasVisited) localStorage.setItem("hasVisited", "true");
    }, []);

    const enabled = useFlag('support-due-date-time-frontend');

    return (
        <li key={todo.id}>
            <h2 className='text-lg font-bold'>{todo.title}</h2>
            <p>{todo.description}</p>
            {enabled ? <p>{todo.dueDate}</p> : null}
        </li>
    )
};

page.tsxを以下のように修正します。

src/app/page.tsx
'use client'
import dynamic from "next/dynamic";
import { FlagProvider } from "@unleash/proxy-client-react";
import { Todo } from "./Todo";

const unleashConfig = {
    url: 'http://localhost:4242/api/frontend/',
    clientKey: 'default:development.unleash-insecure-frontend-api-token',
    appName: 'unleash-onboarding-react'
}

const TodoComponent = dynamic(() => import('./TodoComponent').then((mod) => mod.TodoComponent), {
    ssr: false,
});

const todos: Todo[] = [
    {
        id: '1',
        title: 'Learn Next.js',
        description: 'Learn Next.js and build something great',
        dueDate: '2025-01-01'
    },
    {
        id: '2',
        title: 'Build something great',
        description: 'Learn Next.js and build something great',
        dueDate: '2025-01-02'
    }
]

export default function Home() {
  return (
      <FlagProvider config={unleashConfig}>
          <div className='container mx-auto p-4'>
              <h1 className='text-3xl font-bold mb-4'>Todo</h1>
              <ul className='list-disc'>
                  {todos.map(todo => (
                      <TodoComponent key={todo.id} {...todo} />
                  ))}
              </ul>
          </div>
      </FlagProvider>
  );
}

締め切りフィーチャーフラグの有効化

Unleashの管理画面で support-due-date-time-frontend のフィーチャーフラグを develop環境で有効化します。

ブラウザには以下のように表示されます。

GitHubで編集を提案

Discussion