mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
fix nextjs linting hints and improve adapter to support config as function
This commit is contained in:
@@ -1,15 +1,22 @@
|
|||||||
import type { App } from "bknd";
|
import type { App } from "bknd";
|
||||||
import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
|
import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
|
||||||
import { getRuntimeKey, isNode } from "core/utils";
|
import { isNode } from "core/utils";
|
||||||
|
|
||||||
export type NextjsBkndConfig = FrameworkBkndConfig & {
|
export type NextjsBkndConfig = FrameworkBkndConfig & {
|
||||||
cleanRequest?: { searchParams?: string[] };
|
cleanRequest?: { searchParams?: string[] };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NextjsContext = {
|
||||||
|
env: Record<string, string | undefined>;
|
||||||
|
};
|
||||||
|
|
||||||
let app: App;
|
let app: App;
|
||||||
let building: boolean = false;
|
let building: boolean = false;
|
||||||
|
|
||||||
export async function getApp(config: NextjsBkndConfig) {
|
export async function getApp<Args extends NextjsContext = NextjsContext>(
|
||||||
|
config: NextjsBkndConfig,
|
||||||
|
args?: Args,
|
||||||
|
) {
|
||||||
if (building) {
|
if (building) {
|
||||||
while (building) {
|
while (building) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 5));
|
await new Promise((resolve) => setTimeout(resolve, 5));
|
||||||
@@ -19,7 +26,7 @@ export async function getApp(config: NextjsBkndConfig) {
|
|||||||
|
|
||||||
building = true;
|
building = true;
|
||||||
if (!app) {
|
if (!app) {
|
||||||
app = await createFrameworkApp(config);
|
app = await createFrameworkApp(config, args);
|
||||||
await app.build();
|
await app.build();
|
||||||
}
|
}
|
||||||
building = false;
|
building = false;
|
||||||
@@ -52,7 +59,7 @@ function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequ
|
|||||||
export function serve({ cleanRequest, ...config }: NextjsBkndConfig = {}) {
|
export function serve({ cleanRequest, ...config }: NextjsBkndConfig = {}) {
|
||||||
return async (req: Request) => {
|
return async (req: Request) => {
|
||||||
if (!app) {
|
if (!app) {
|
||||||
app = await getApp(config);
|
app = await getApp(config, { env: process.env ?? {} });
|
||||||
}
|
}
|
||||||
const request = getCleanRequest(req, cleanRequest);
|
const request = getCleanRequest(req, cleanRequest);
|
||||||
return app.fetch(request);
|
return app.fetch(request);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import type { ReactNode } from "react";
|
import { Footer } from "@/components/Footer";
|
||||||
import { Footer } from "./Footer";
|
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
||||||
children,
|
children,
|
||||||
@@ -36,41 +35,3 @@ export default async function Layout({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Buttons = () => (
|
|
||||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel logomark"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
Deploy now
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
|
|
||||||
href="https://docs.bknd.io/integration/nextjs"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Read our docs
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const List = ({ items = [] }: { items: ReactNode[] }) => (
|
|
||||||
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
|
||||||
{items.map((item, i) => (
|
|
||||||
<li key={i} className={i < items.length - 1 ? "mb-2" : ""}>
|
|
||||||
{item}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getApi } from "@/bknd";
|
import { getApi } from "@/bknd";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { List } from "@/app/(main)/layout";
|
import { List } from "@/components/List";
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
// without "{ verify: true }", this page can be static
|
// without "{ verify: true }", this page can be static
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { getApi } from "@/bknd";
|
import { getApi } from "@/bknd";
|
||||||
import { Buttons, List } from "../layout";
|
import { Buttons } from "@/components/Buttons";
|
||||||
|
import { List } from "@/components/List";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default async function SSRPage() {
|
export default async function SSRPage() {
|
||||||
const api = await getApi({ verify: true });
|
const api = await getApi({ verify: true });
|
||||||
@@ -11,21 +13,21 @@ export default async function SSRPage() {
|
|||||||
<List items={data.map((todo) => todo.title)} />
|
<List items={data.map((todo) => todo.title)} />
|
||||||
<Buttons />
|
<Buttons />
|
||||||
|
|
||||||
<p>
|
<div>
|
||||||
{user ? (
|
{user ? (
|
||||||
<>
|
<>
|
||||||
Logged in as {user.email}.{" "}
|
Logged in as {user.email}.{" "}
|
||||||
<a className="font-medium underline" href="/api/auth/logout">
|
<Link className="font-medium underline" href="/api/auth/logout">
|
||||||
Logout
|
Logout
|
||||||
</a>
|
</Link>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<p>
|
<p>
|
||||||
Not logged in.{" "}
|
Not logged in.{" "}
|
||||||
<a className="font-medium underline" href="/admin/auth/login">
|
<Link className="font-medium underline" href="/admin/auth/login">
|
||||||
Login
|
Login
|
||||||
</a>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs opacity-50">
|
<p className="text-xs opacity-50">
|
||||||
Sign in with:{" "}
|
Sign in with:{" "}
|
||||||
@@ -39,7 +41,7 @@ export default async function SSRPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
29
examples/nextjs/src/components/Buttons.tsx
Normal file
29
examples/nextjs/src/components/Buttons.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export const Buttons = () => (
|
||||||
|
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||||
|
<a
|
||||||
|
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
|
||||||
|
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className="dark:invert"
|
||||||
|
src="/vercel.svg"
|
||||||
|
alt="Vercel logomark"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
Deploy now
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
|
||||||
|
href="https://docs.bknd.io/integration/nextjs"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Read our docs
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
@@ -2,27 +2,28 @@
|
|||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
||||||
<a
|
<Link
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
href={pathname === "/" ? "/ssr" : "/"}
|
href={pathname === "/" ? "/ssr" : "/"}
|
||||||
>
|
>
|
||||||
<Image aria-hidden src="/file.svg" alt="File icon" width={16} height={16} />
|
<Image aria-hidden src="/file.svg" alt="File icon" width={16} height={16} />
|
||||||
{pathname === "/" ? "SSR" : "Home"}
|
{pathname === "/" ? "SSR" : "Home"}
|
||||||
</a>
|
</Link>
|
||||||
<a
|
<Link
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
href="/admin"
|
href="/admin"
|
||||||
>
|
>
|
||||||
<Image aria-hidden src="/window.svg" alt="Window icon" width={16} height={16} />
|
<Image aria-hidden src="/window.svg" alt="Window icon" width={16} height={16} />
|
||||||
Admin
|
Admin
|
||||||
</a>
|
</Link>
|
||||||
<a
|
<Link
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
href="https://bknd.io"
|
href="https://bknd.io"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -30,7 +31,7 @@ export function Footer() {
|
|||||||
>
|
>
|
||||||
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
|
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
|
||||||
Go to bknd.io →
|
Go to bknd.io →
|
||||||
</a>
|
</Link>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
11
examples/nextjs/src/components/List.tsx
Normal file
11
examples/nextjs/src/components/List.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
export const List = ({ items = [] }: { items: ReactNode[] }) => (
|
||||||
|
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||||
|
{items.map((item, i) => (
|
||||||
|
<li key={i} className={i < items.length - 1 ? "mb-2" : ""}>
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user