넥스트 14버전
npx create-next-app@14.2.15 --use-pnpm
pnpm 추가기능들 설치
//prettier, tailwindcss-prettier
pnpm add -D prettier prettier-plugin-tailwindcss
//supabase, zustand, tanstack-query, icons
pnpm add @supabase/ssr @supabase/supabase-js zustand @tanstack/react-query react-icons
util
공통적으로 사용되는 유틸리티 함수나 로직을 모아 두는 용도
Next.js의 미들웨어 정의
import type { NextRequest } from 'next/server';
import { updateSession } from './utils/supabase/middleware';
export const middleware = async (request: NextRequest) => {
return await updateSession(request);
};
export const config = { //config : 미들웨어가 적용될 경로 지정
matcher: ['/'] //모든 경로에 미들웨어 적용(빈값이면 안댐)
};
브라우저 환경에서 Supabase 클라이언트를 생성하는 함수인 createClient을 정의
import { createBrowserClient } from '@supabase/ssr';
import { SupabaseClient } from '@supabase/supabase-js';
export const createClient = (): SupabaseClient =>
createBrowserClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!);
const browserClient: SupabaseClient = createClient();
export default browserClient;
Supabase 클라이언트를 사용하여 세션을 업데이트하는 미들웨어 함수 정의
import { createServerClient } from '@supabase/ssr';
import { type NextRequest, NextResponse } from 'next/server';
export const updateSession = async (request: NextRequest) => {
try {
let response = NextResponse.next({
request: {
headers: request.headers
}
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
response = NextResponse.next({
request
});
cookiesToSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options));
}
}
}
);
// 여기 부분은 리다이렉트
// const { data } = await supabase.auth.getUser();
// 로그인 한 상태라면 메인페이지로 리다이렉트
// if (
// data?.user &&
// (request.nextUrl.pathname.startsWith('/login') || request.nextUrl.pathname.startsWith('/signup'))
// ) {
// return NextResponse.redirect(new URL('/', request.url));
// }
// // 로그인을 하지 않았는데 접근한다면 로그인 페이지로 리다이렉트
// if (
// !data?.user &&
// (request.nextUrl.pathname.startsWith('/mypage') || request.nextUrl.pathname.startsWith('/update-password'))
// ) {
// return NextResponse.redirect(new URL('/login', request.url));
// }
return response;
} catch (e) {
console.log(e, 'error');
return NextResponse.next({
request: {
headers: request.headers
}
});
}
};
Supabase 클라이언트를 생성하는 함수인 createClient을 정의
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export const createClient = () => {
const cookieStore = cookies();
return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options);
});
} catch (error) {
console.log('error: ', error);
}
}
}
});
};
tanstack-query 사용하기 위한 컴포넌트
'use client';
import { isServer, QueryClient, QueryClientProvider } from '@tanstack/react-query';
//서버 환경
function makeQueryClient() {
return new QueryClient({ //새로운 QueryClient 인스턴스를 생성
defaultOptions: { //기본옵션
queries: {
staleTime: 60 * 1000 //60초
}
}
});
}
//브라우저 환경에서 사용할 QueryClient 인스턴스를 저장
let browserQueryClient: QueryClient | undefined = undefined;
//서버와 브라우저 환경에 따라 QueryClient 인스턴스를 반환
function getQueryClient() {
if (isServer) {
return makeQueryClient();
} else {
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
}
export default function RQProviders({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient(); //getQueryClient를 호출
//QueryClientProvider의 client 속성으로 전달
//자식 컴포넌트에 React Query 기능을 제공
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
}
RQProviders로 감싸주기
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
<RQProviders>{children}</RQProviders>
</body>
</html>
);