Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add links to interactive examples #87

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions example/.env
Original file line number Diff line number Diff line change
@@ -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
Expand Down
23 changes: 13 additions & 10 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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`.
13 changes: 6 additions & 7 deletions example/src/app/api-route/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ 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 = {
"Content-Type": "application/json",
"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 {
Expand All @@ -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"),
},
}),
{
Expand Down
4 changes: 2 additions & 2 deletions example/src/app/client-page/_ClientComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion example/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Page>{children}</Page>
<Page className="p-6">{children}</Page>
</body>
</html>
);
Expand Down
6 changes: 3 additions & 3 deletions example/src/app/server-page-advanced/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const getData = async () => {
const flags = flagsClient(toggles);

return {
isEnabled: flags.isEnabled("nextjs-example"),
isEnabled: flags.isEnabled("example-flag"),
count: definitions?.features?.length || 0,
sessionId,
};
Expand All @@ -51,7 +51,7 @@ export default async function Page() {

// 'flag' function from SDK is configurable
const { variant } = await flag(
"nextjs-example",
"example-flag",
{
sessionId: cookies().get(COOKIE_NAME)?.value || "0", // context
},
Expand All @@ -66,7 +66,7 @@ export default async function Page() {
</Text>
<p>This page is server-side rendered.</p>
<p>
Feature flag <code>nextjs-example</code> is{" "}
Feature flag <code>example-flag</code> is{" "}
<strong>
<code>{isEnabled ? "ENABLED" : "DISABLED"}</code>
</strong>
Expand Down
4 changes: 2 additions & 2 deletions example/src/app/server-page/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<>
Expand All @@ -13,7 +13,7 @@ export default async function Page() {
</Text>
<p>This page is server-side rendered.</p>
<p>
Feature flag <code>nextjs-example</code> is{" "}
Feature flag <code>example-flag</code> is{" "}
<strong>
<code>{enabled ? "ENABLED" : "DISABLED"}</code>
</strong>
Expand Down
2 changes: 1 addition & 1 deletion example/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion example/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import "@vercel/examples-ui/globals.css";

export default function MyApp({ Component, pageProps }: AppProps) {
return (
<Page>
<Page className="p-6">
<Component {...pageProps} />
</Page>
);
Expand Down
2 changes: 1 addition & 1 deletion example/src/pages/csr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LoadingDots } from "@vercel/examples-ui";
import type { NextPage } from "next";

const ExampleComponent = () => {
const isEnabled = useFlag("nextjs-example");
const isEnabled = useFlag("example-flag");
const { flagsReady } = useFlagsStatus();

if (!flagsReady) {
Expand Down
4 changes: 2 additions & 2 deletions example/src/pages/ssg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export const getStaticProps: GetStaticProps<Data> = async (_ctx) => {

return {
props: {
isEnabled: flags.isEnabled("nextjs-example"),
variant: flags.getVariant("nextjs-example"),
isEnabled: flags.isEnabled("example-flag"),
variant: flags.getVariant("example-flag"),
},
};
};
Expand Down
4 changes: 2 additions & 2 deletions example/src/pages/ssr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export const getServerSideProps: GetServerSideProps<Data> = async (ctx) => {

return {
props: {
isEnabled: flags.isEnabled("nextjs-example"),
variant: flags.getVariant("nextjs-example"),
isEnabled: flags.isEnabled("example-flag"),
variant: flags.getVariant("example-flag"),
percent: Math.round((toggles.length / definitions.features.length) * 100),
},
};
Expand Down
Loading