diff --git a/README.md b/README.md index 9efe82d..aab8dd2 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ yarn add @unleash/nextjs pnpm add @unleash/nextjs ``` +There is an [`./example`](./example) project that you can [deploy to Vercel](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FUnleash%2Funleash-client-nextjs%2Ftree%2Fmain%2Fexample) or [edit in CodeSandbox](https://codesandbox.io/s/github/Unleash/unleash-client-nextjs/tree/main/example). + ### Environment variables This package will attempt to load configuration from diff --git a/example/.env b/example/.env index 07f1a31..01d8364 100644 --- a/example/.env +++ b/example/.env @@ -1,13 +1,13 @@ NEXT_PUBLIC_UNLEASH_SERVER_API_URL=https://app.unleash-hosted.com/demo/api # or: UNLEASH_SERVER_URL=https://app.unleash-hosted.com/demo/api -UNLEASH_SERVER_API_TOKEN=test-server:default.8a090f30679be7254af997864d66b86e44dcfc5291916adff72a0fb5 +UNLEASH_SERVER_API_TOKEN=demo-app:dev.9fc74dd72d2b88bea5253c04240b21a54841f08d9918046ed55a06b5 # NEXT_PUBLIC_UNLEASH_FRONTEND_URL=https://app.unleash-hosted.com/demo/api/frontend # or: UNLEASH_FRONTEND_URL=https://app.unleash-hosted.com/demo/api/frontend -NEXT_PUBLIC_UNLEASH_FRONTEND_API_TOKEN=default:default.26d592049f821f731f94047e7d760252f431697e2153b26f7eaba014 -# or: UNLEASH_FRONTEND_API_TOKEN=demo-app:default.a901bd337765b46cfcf80d630c4c550e84845e840569b8f61e4c497d +NEXT_PUBLIC_UNLEASH_FRONTEND_API_TOKEN=demo-app:dev.95ae66ab673bf467facb68b2487904f4891064d26b47e89ca498063d +# or: UNLEASH_FRONTEND_API_TOKEN=demo-app:dev.95ae66ab673bf467facb68b2487904f4891064d26b47e89ca498063d NEXT_PUBLIC_UNLEASH_APP_NAME=nextjs-example # or: UNLAESH_APP_NAME=nextjs-example diff --git a/example/README.md b/example/README.md index b3bd2d9..43c15d7 100644 --- a/example/README.md +++ b/example/README.md @@ -1,5 +1,8 @@ ## Next.js with Unleash +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FUnleash%2Funleash-client-nextjs%2Ftree%2Fmain%2Fexample) +[![Edit in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/Unleash/unleash-client-nextjs/tree/main/example) + To run this code locally: ```bash @@ -11,30 +14,30 @@ pnpm dev Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. -Flag in use is `nextjs-example`. https://app.unleash-hosted.com/demo/projects/default/features/nextjs-example +Flag in use is `example-flag`. https://app.unleash-hosted.com/demo/projects/codesandbox/features/example-flag ## Available examples ### App Router -- `./src/app/app-page/page.tsx` - Server-side component page, with loader -- `./src/app/api-route/route.tsx` - JSON API response +- [`./src/app/page.tsx`](./src/app/page.tsx) - Server-side component page, with loader +- [`./src/app/api-route/route.ts`](./src/app/api-route/route.ts) - JSON API response ### Pages Router -- `./src/pages/csr.tsx` - Client-side rendering - simple use case, with loader -- `./src/pages/ssr.tsx` - Server-side rendering - when you need to keep some data private -- `./src/pages/ssg.tsx` - Static site generation - performance optimization +- [`./src/pages/csr.tsx`](./src/pages/csr.tsx) - Client-side rendering - simple use case, with loader +- [`./src/pages/ssr.tsx`](./src/pages/ssr.tsx) - Server-side rendering - when you need to keep some data private +- [`./src/pages/ssg.tsx`](./src/pages/ssg.tsx) - Static site generation - performance optimization ### API -- `./src/pages/api/hello.ts` - API route responding with JSON +- [`./src/pages/api/hello.ts`](./src/pages/api/hello.ts) - API route responding with JSON ### Middleware Example of A/B testing with Next.js Middleware. Redirect users to a different (pre-rendered) page based on a feature flag. -- `./src/pages/api/proxy-definitions.ts` - act as cache for feature flag definitions. This lets this SDK act as a substitute for Unleash Edge or the Unleash proxy that you can deploy on Next.js Edge. -- `./src/middleware.ts`- handle flag evaluation and transparently redirect to one of the pages in `./src/pages/ab` directory -- `./src/pages/ab/a` & `./src/pages/ab/b` - target pages. Both will be served at the URL `/ab`, but which one you see is decided by the feature flag in `./src/middleware.ts`. +- [`./src/pages/api/proxy-definitions.ts`](./src/pages/api/proxy-definitions.ts) - act as cache for feature flag definitions. This lets this SDK act as a substitute for Unleash Edge or the Unleash proxy that you can deploy on Next.js Edge. +- [`./src/middleware.ts`](./src/middleware.ts) - handle flag evaluation and transparently redirect to one of the pages in `./src/pages/ab` directory +- [`./src/pages/ab/a`](./src/pages/ab/a.tsx) & [`./src/pages/ab/b`](./src/pages/ab/b.tsx) - target pages. Both will be served at the URL `/ab`, but which one you see is decided by the feature flag in `./src/middleware.ts`. diff --git a/example/src/app/api-route/route.ts b/example/src/app/api-route/route.ts index a85b3ff..f1ce526 100644 --- a/example/src/app/api-route/route.ts +++ b/example/src/app/api-route/route.ts @@ -6,12 +6,11 @@ import { import type { NextRequest } from "next/server"; export const runtime = "edge"; export const preferredRegion = "fra1"; - -const COOKIE_NAME = "unleash-session-id"; +import { UNLEASH_COOKIE_NAME } from "../../utils"; export async function GET(request: NextRequest) { const sessionId = - request.cookies.get(COOKIE_NAME)?.value || + request.cookies.get(UNLEASH_COOKIE_NAME)?.value || `${Math.floor(Math.random() * 1_000_000_000)}`; const headers = { @@ -19,7 +18,7 @@ export async function GET(request: NextRequest) { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", - "Set-Cookie": `${COOKIE_NAME}=${sessionId}`, + "Set-Cookie": `${UNLEASH_COOKIE_NAME}=${sessionId}`, }; try { @@ -32,9 +31,9 @@ export async function GET(request: NextRequest) { JSON.stringify({ activeToggles: toggles.length, exampleToggle: { - url: "https://app.unleash-hosted.com/demo/projects/default/features/nextjs-example", - isEnabled: flags.isEnabled("nextjs-example"), - variant: flags.getVariant("nextjs-example"), + url: "https://app.unleash-hosted.com/demo/projects/codesandbox/features/example-flag", + isEnabled: flags.isEnabled("example-flag"), + variant: flags.getVariant("example-flag"), }, }), { diff --git a/example/src/app/client-page/_ClientComponent.tsx b/example/src/app/client-page/_ClientComponent.tsx index d20f263..b6f4673 100644 --- a/example/src/app/client-page/_ClientComponent.tsx +++ b/example/src/app/client-page/_ClientComponent.tsx @@ -4,8 +4,8 @@ import { useFlag, useFlagsStatus, useVariant } from "@unleash/nextjs/client"; import { LoadingDots } from "@vercel/examples-ui"; export default function ClientComponent() { - const isEnabled = useFlag("nextjs-example"); - const variant = useVariant("nextjs-example"); + const isEnabled = useFlag("example-flag"); + const variant = useVariant("example-flag"); const { flagsReady } = useFlagsStatus(); if (!flagsReady) { diff --git a/example/src/app/layout.tsx b/example/src/app/layout.tsx index 4865035..3cf8ff3 100644 --- a/example/src/app/layout.tsx +++ b/example/src/app/layout.tsx @@ -11,7 +11,7 @@ export default function Layout({ children }: { children: ReactNode }) { return (
-This page is server-side rendered.
- Feature flag nextjs-example
is{" "}
+ Feature flag example-flag
is{" "}
{isEnabled ? "ENABLED" : "DISABLED"}
diff --git a/example/src/app/server-page/page.tsx b/example/src/app/server-page/page.tsx
index 699ddb4..95aa82b 100644
--- a/example/src/app/server-page/page.tsx
+++ b/example/src/app/server-page/page.tsx
@@ -4,7 +4,7 @@ import { Text } from "@vercel/examples-ui";
export const runtime = "edge";
export default async function Page() {
- const { enabled } = await flag("nextjs-example");
+ const { enabled } = await flag("example-flag");
return (
<>
@@ -13,7 +13,7 @@ export default async function Page() {
This page is server-side rendered.
- Feature flag nextjs-example
is{" "}
+ Feature flag example-flag
is{" "}
{enabled ? "ENABLED" : "DISABLED"}
diff --git a/example/src/middleware.ts b/example/src/middleware.ts
index be1c106..d27bfcb 100644
--- a/example/src/middleware.ts
+++ b/example/src/middleware.ts
@@ -26,7 +26,7 @@ export async function middleware(req: NextRequest) {
// Evaluate based on provided context
const evaluated = evaluateFlags(definitions, context);
- const variant = flagsClient(evaluated.toggles).getVariant("nextjs-example")
+ const variant = flagsClient(evaluated.toggles).getVariant("example-flag")
?.payload?.value;
const newUrl = req.nextUrl.clone();
diff --git a/example/src/pages/_app.tsx b/example/src/pages/_app.tsx
index 406975b..7019ca4 100644
--- a/example/src/pages/_app.tsx
+++ b/example/src/pages/_app.tsx
@@ -4,7 +4,7 @@ import "@vercel/examples-ui/globals.css";
export default function MyApp({ Component, pageProps }: AppProps) {
return (
-