728x90
반응형

1. 로고 및 파비콘을 생성합니다.

클립스튜디오 : 로고 생성 화면

저는 클립스튜디오를 사용하여 직접 그려주었습니다. (기본 로고, 다크모드 로고, favicon 등)

 

더 빠른 느낌을 주기위해 'JS' 부분을 달리는 사람의 모습으로 표현하고 싶었습니다.

 

 

 

 

2. 프로젝트에 이미지 파일 추가

public > images > ...png

public 아래로 생성한 이미지들을 넣어줍니다.

 

저는 public > images 폴더에 이미지를 넣었습니다.

 

 

 

 

 

3. 파비콘 적용하기

 

metadata에서 icons로 favicon 이미지를 연결합니다.

 

 

favicon 변경

 

정상적으로 적용되었습니다만, 나중에 더 눈에 띄는 이미지로 교체할까 합니다.

 

 

 

4. 로고 적용하기

 

로고 이미지를 헤더 또는 원하는 위치에서 이미지 태그로 불러옵니다.

 

 

 

다크모드 설정에 따라 다르게 나오는 화면을 볼 수 있습니다.

 

728x90
반응형
728x90
반응형

 

업체별 인증코드 발급받기

 

구글

더보기

https://console.cloud.google.com/apis/dashboard

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

 

 

링크에 접속하여 프로젝트를 추가합니다.

 

 

 

User Type을 외부로 선택합니다.

 

 

 필수 정보만 입력하고 저장 후 완료합니다.

 

 

 

 

 사용자 인증 정보 > 사용자 인증 정보 만들기 > OAuth 클라이언트 ID 생성

 

 

 

 

생성된 OAuth 클라이언트에 들어가서 URL 정보를 입력합니다.

리디렉션 URI는 꼭 '/api/auth/callback/google'로 작성해야합니다.

 

 

해당 페이지에서 클라이언트 ID 및 시크릿 정보를 확인할 수 있습니다.

 

 

카카오 (prisma 적용 연구중)

더보기

https://developers.kakao.com/console/app

 

카카오계정

 

accounts.kakao.com

 

 

 

링크에 접속하여 카카오 로그인 서비스를 사용할 애플리케이션을 추가합니다.

 

 

 

저는 사용할 이미지가 아직 없어서 앱 아이콘을 제외하고 모두 채워주었습니다.

 

 

 

앱 키에서 제공하는 Javascript 키를 ClientID로 사용하게 됩니다.

 

 

 

플랫폼에서 Web 플랫폼 등록을 진행합니다.

 

 

 

사이트 도메인을 입력해줍니다. 저는 실제 도메인과 로컬 주소 모두를 입력해두었습니다.

 

 

 

 

카카오 로그인에서 카카오 로그인을 활성화 시키고 Redirect URL을 추가합니다.

 

 

 

Redirect URL은 /api/auth/callback/kakao로 작성해주셔야 원활하게 동작합니다.

 

 

 

 

동의항목에서 필요한 정보의 동의 상태를 변경합니다. 저는 우선 닉네임만 활성화 시켰습니다.

 

 

 

보안에서 Client Secret을 발급받습니다. clientSecret 키 정보도 clientID와 함께 인증을 위해 사용됩니다.

 

 

 

** Prisma로 DB를 사용중인 상태라고 생각하고 작성하겠습니다 **

https://fjdkslvn.tistory.com/153

 

[Next.js] Prisma로 기존 MYSQL 연동하기

1. 모듈설치npm install prisma   2. scheme.prisma 파일 생성npx prisma initsrc와 동일한 위치로 prisma 폴더가 생성되고 scheme.prisma 파일이 생성됩니다.provider를 mysql로 변경하고 url에 DATABASE_URL 환경변수를 설

fjdkslvn.tistory.com

 

 

 

1. next-auth 및 필요한 prisma 모듈 설치

npm install next-auth @types/next-auth @next-auth/prisma-adapter

 

 

 

2. schema.prisma 업데이트 (MYSQL)

model User {
  id            String      @id @default(uuid())
  name          String
  email         String?     @unique
  emailVerified DateTime?   @map("email_verified")
  image         String?
  createdAt     DateTime    @default(now())
  updatedAt     DateTime    @updatedAt
  accounts      Account[]
  favorites     favorites[]
  sessions      Session[]

  @@map("users")
}

model Account {
  id                String   @id @default(cuid())
  userId            String   @map("user_id")
  type              String?
  provider          String
  providerAccountId String   @map("provider_account_id")
  token_type        String?
  refresh_token     String?  @db.Text
  access_token      String?  @db.Text
  expires_at        Int?
  scope             String?
  id_token          String?  @db.Text
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  user              User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@index([userId], map: "accounts_user_id_fkey")
  @@map("accounts")
}

model Session {
  id           String   @id @default(cuid())
  userId       String?  @map("user_id")
  sessionToken String   @unique @map("session_token")
  accessToken  String?  @map("access_token") @db.Text
  expires      DateTime
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  user         User?    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId], map: "sessions_user_id_fkey")
  @@map("sessions")
}

model VerificationRequest {
  id         String   @id @default(cuid())
  identifier String
  token      String   @unique
  expires    DateTime
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  @@unique([identifier, token])
}

 

schema.prisma 파일에 사용자 관련 모델을 추가합니다.

 

prisma 공식 페이지에서 안내한 형태 그대로 사용하면 p.account.findUnique() 관련 오류가 발생합니다.

오류가 발생하지 않도록 수정된 모델을 사용하시면 좋을것같습니다.

 

(MYSQL이 아니더라도 같은 오류가 발생하시면 아래 이슈 문서 추천드립니다.)

https://github.com/nextauthjs/next-auth/issues/3815

 

Invalid `p.account.findUnique()` invocation with prisma · Issue #3815 · nextauthjs/next-auth

Title Invalid p.account.findUnique() invocation with prisma How to reproduce ☕️ next-auth: 4.0.0-beta.7 @next-auth/prisma-adapter: 0.5.2-next.19 /pages/api/[...nextauth].ts import { PrismaAdapter }...

github.com

 

 

 

 

 

파일에 모델을 추가하였다면 아래 명령어를 차례대로 실행하여 실제 DB 및 Prisma에 적용될 수 있도록 합니다.

 

npx prisma db pull

 

 

npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql

이 명령어는 본인의 파일 구조를 확인하시고 실행하시면 됩니다.

 

 

npx prisma generate

 

여기까지 하시면 새로 생성된 모델이 적용됩니다.

 

 

 

3. SessionProvider 적용

AuthProvider 파일을 생성하고 메인 layout.tsx 파일에 적용합니다.

 

#components > providers > authProvider.tsx

"use client";
 
import { SessionProvider } from "next-auth/react";
import { ReactNode } from "react";
import { Session } from "next-auth";
 
type Props = {
  session?: Session | null;
  children: ReactNode;
};
 
export default function AuthProvider({ session, children }: Props) {
  return <SessionProvider session={session}>{children}</SessionProvider>;
}

 

# layout.tsx

import type { Metadata } from "next";
import { Noto_Sans_KR } from 'next/font/google';
import "@/styles/globals.css";
import AuthProvider from '@/components/providers/authProvider'

...

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html>
      <body className={noto.className}>
      	<AuthProvider>
       	  {children}
      	</AuthProvider>
      </body>
    </html>
  );
}

 

 

4. auth API 작성

app > api > auth > [...nextauth] > route.ts

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()


const handler = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID || "",
      clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      return { ...token, ...user };
    },

    async session({ session, token }) {
      session.user = token as any;
      return session;
    },
  },
  session: {
    strategy: 'jwt'
  },
  secret: process.env.NEXTAUTH_SECRET
});

export { handler as GET, handler as POST };

 

app > api > auth > [...nextauth] > route.ts 위치에 위 코드를 작성해줍니다.

 

  • PrismaAdapter : prisma에 연결된 DB에서 user 정보를 자동으로 관리하도록 합니다.
  • provider : google, kakao 등 자동 로그인이 필요한 서비스를 연결할 수 있습니다.
  • clientId, clientSecret : 인증을 위해 각 서비스 발급받아서 사용하는 정보입니다. (보안상 환경변수로 사용하기 위해 .env에서 불러와 사용합니다.)
  • jwt, session : user ID를 받아내기 위해 jwt 및 session을 설정합니다.
  • NEXTAUTH_SECRET : JWT를 암호화하고 이메일 확인 토큰을 해시하는데 사용됩니다. (배포시 필수)

 

NEXTAUTH_SECRET 생성 명령어

// 터미널에 입력해서 NEXTAUTH_SECRET를 얻을 수 있습니다.
openssl rand -base64 32

 

 

 

 

5. Session 타입 확장 

import { DefaultSession } from "next-auth";
 
declare module "next-auth" {
  interface Session {
    user?: {
      id?: string;
      role?: string;
    } & DefaultSession["user"];
  }
}

 

각 user를 식별할 수 있는 id 정보를 받기 위해서 타입 확장을 진행합니다.

 

 

6. 로그인

'use client'
import { useEffect } from 'react';
import { useSession, signIn, signOut } from "next-auth/react"

const Navbar: React.FC = () => {
  const { data: session } = useSession();

  useEffect(() => {
    console.log(session?.user?.id);
    console.log(session?.user?.name);
    console.log(session?.user?.email);
  },[session])
  
  return (
    <div>
        {session
        ?<>
          <div>{`${session.user?.name}님`}</div>
          <div  onClick={() => signOut()}>로그아웃</div>
        </>
        :<div onClick={() => signIn()}>로그인</div>}
    </div>
  );
};

export default Navbar;

 

  • useSession : session을 통해 로그인 한 사용자의 정보를 받아낼 수 있습니다.
  • signIn, signOut : 로그인, 로그아웃을 할 수 있습니다.

 

 

 

 

[공식문서 및 참고문서]

 

https://next-auth.js.org/getting-started/example

 

Getting Started | NextAuth.js

The example code below describes how to add authentication to a Next.js app.

next-auth.js.org

https://next-auth.js.org/configuration/initialization#route-handlers-app

 

Initialization | NextAuth.js

The main entry point of NextAuth.js is the NextAuth method that you import from next-auth. It handles different types of requests, as defined in the REST API section.

next-auth.js.org

https://powerku.tistory.com/312

 

next-auth 이용해서 10분만에 소셜 로그인 구현 하기

next-auth란? next-auth는 Next.js 프로젝트에서 소셜 로그인을 간단하게 구현할 수 있는 라이브러리 입니다. 국내에서는 구글, 카카오, 네이버, 페이스북, 애플 등 다양한 소셜 로그인을 이용하고 사용

powerku.tistory.com

https://blog.teamelysium.kr/nextjs-auth

 

NextAuth.js로 간편 로그인 기능 구현하기

팀엘리시움 블로그에서 제품, 테크, 고객사례, 뉴스 등의 이야기를 확인해보세요.

blog.teamelysium.kr

 

https://velog.io/@dosomething/Next-auth-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84

 

Next-auth 를 이용한 로그인 구현

next-auth 라이브러리를 이용해 로그인을 구현한 내용에 대해 공유합니다.

velog.io

 

728x90
반응형
728x90
반응형

 

1. 모듈설치

npm install prisma

 

 

 

2. scheme.prisma 파일 생성

npx prisma init

src와 동일한 위치로 prisma 폴더가 생성되고 scheme.prisma 파일이 생성됩니다.

provider를 mysql로 변경하고 url에 DATABASE_URL 환경변수를 설정해줘야합니다.

 

 

 

.evn 파일에 local 환경변수 설정

DATABASE_URL=mysql://USER:PASSWORD@HOST:PORT/DATABASE

USER : mysql Username

PASSWORD : mysql password

HOST : mysql Server Host

PORT : mysql port number

DATABASE : mysql DB name

 

 

 

3. prisma 파일 하이라이팅 확장 추가

 

확장에서 Prisma를 검색해서 설치합니다.

prisma 파일의 코드에 하이라이팅을 넣어주어 가독성이 높아집니다.

 

 

 

4. 기존 DB 데이터 모델 생성

npx prisma db pull

 

 

-  schema.prisma 파일에 연동된 DB 테이블이 prisma 데이터 모델로 추가되었습니다.

-  설정된 데이터 모델을 토대로 쿼리를 작성할 수 있습니다.

-  외래키가 설정되어있다면 테이블 간 관계도 인식하고 추가됩니다.

 

 

 

 

5. 데이터베이스 마이그레이션

이미 테이블에 데이터가 포함되어있고 데이터가 초기화 되면 안되는 데이터베이스의 경우는 마이그레이션을 초기화 합니다.

 

mkdir -p prisma/migrations/0_init

 

폴더를 생성합니다.

 

 

npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql

 

마이그레이션을 생성합니다.

 

  • --from-empty: 마이그레이션하려는 데이터 모델이 비어 있다고 가정합니다.
  • --to-schema-datamodel: 현재 데이터베이스 상태
  • --script: SQL 스크립트를 출력합니다.

마이그레이션 결과

 

 

npx prisma migrate resolve --applied 0_init

 

마이그레이션을 적용하는 명령어를 실행합니다.

 

 

 

 

6. 프리즈마 클라이언트 설치

npm install @prisma/client

 

프리즈마 쿼리를 사용하기 위해 프리즈마 클라이언트를 설치합니다.

 

 

 

npx prisma generate

 

프리즈마 클라이언트를 생성하는 명령어를 실행합니다.

 

 

 

7. 쿼리 실행

'use server'

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export async function getAllNotice() {
  try {
    const data = await prisma.notice.findMany();
    return data;
  } catch (error) {
    throw new Error(`Error getting all notice`);
  } finally {
    await prisma.$disconnect();
  }
}

 

findMany()를 사용하여 notice 테이블의 데이터를 모두 조회하는 쿼리를 실행하는 코드입니다.

 

 

 

 

[공식문서]

https://www.prisma.io/docs/getting-started/setup-prisma/add-to-existing-project/relational-databases-typescript-postgresql

 

Add Prisma ORM to an existing project using TypeScript and PostgreSQL (15 min) | Prisma Documentation

Learn how to add Prisma ORM to an existing TypeScript project by connecting it to your PostgreSQL database and generating a Prisma Client for database access.

www.prisma.io

 

728x90
반응형
728x90
반응형

* Next.js에 Tailwind css를 적용시킨 후 따라해주세요.

 

1.  next-themes 설치

# NPM
npm install next-themes

# Yarn 
yarn add next-themes

 

 

 

2.  Root Layout에  ThemeProvider 추가

import "@/styles/globals.css";
import { ThemeProvider } from 'next-themes';

...

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html suppressHydrationWarning>
      <body>
        <ThemeProvider attribute='class'>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

 

- ThemeProvider가 children을 감싸도록 작성합니다.

- 경고 표시를 무시하기 위해 html 태그에 suppressHydrationWarning를 입력합니다.

- 추가적인 설정이 없다면 system이 기본 테마로 설정됩니다.

 

 

 

3.  tailwind.config.js에  다크모드 설정 추가

// tailwind.config.ts

import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      backgroundImage: {
        "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
        "gradient-conic":
          "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
      },
    },
  },
  darkMode: 'class', // 다크 모드를 클래스 기반으로 설정
  plugins: [],
};
export default config;

 

darkMode: 'class' 를 추가하여 클래스 기반으로 다크모드일때의 스타일을 지정할 수 있도록 설정합니다.

 

 

 

4.  다크모드 스타일 지정

export default function Page() {

  return (
    <div className="text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100">
    	기본인 light 모드에서는 text-gray-600의 색상에서 hover시 text-gray-900으로 색이 변경되며 더욱 진해집니다.
        dartk 모드에서는 text-gray-300의 색상에서 hover시 text-gray-100으로 색이 변경되며 더욱 밝아집니다.
    </div>
  );
}

 

 

 

 

 

5.  테마 변경 컴포넌트

import { useState } from "react";
import { useTheme } from "next-themes";
import LightModeOutlinedIcon from '@mui/icons-material/LightModeOutlined';
import BedtimeOutlinedIcon from '@mui/icons-material/BedtimeOutlined';
import MonitorIcon from '@mui/icons-material/Monitor';

const ThemeSelector: React.FC = () => {
  const { theme, setTheme } = useTheme();
  const [themeToggle, setThemeToggle] = useState(false);

  const themeShowToggle = () => {
    setThemeToggle(!themeToggle);
  };

  const handleChange = (themeValue: string) => {
    setTheme(themeValue);
    setThemeToggle(false);
  };

  return (
    <div className="relative">
        <div className="text-blue-500 mr-6 cursor-pointer" onClick={themeShowToggle}>
          {theme === 'light'
            ? <LightModeOutlinedIcon id="theme_light"/>
            : theme === 'dark'
            ? <BedtimeOutlinedIcon id="theme_dark"/>
            : <MonitorIcon id="theme_system"/>}
        </div>
        {themeToggle &&
          <div className="absolute top-16 right-4 w-28 bg-white shadow-lg py-1 rounded-md border-solid border border-gray-300 text-gray-900 font-medium text-sm dark:text-gray-100 dark:bg-backDarkColor">
            <div className={["flex flex-row cursor-pointer px-3 py-1 hover:bg-gray-100 dark:hover:bg-zinc-800", theme === 'light' && "text-blue-500"].join(' ')} onClick={() => handleChange('light')}>
              <LightModeOutlinedIcon className={[theme === 'light'?"text-blue-500":"text-gray-400", "w-5 mr-2"].join(' ')}/>
              Light
            </div>
            <div className={["flex flex-row cursor-pointer px-3 py-1 hover:bg-gray-100 dark:hover:bg-zinc-800", theme === 'dark' && "text-blue-500"].join(' ')} onClick={() => handleChange('dark')}>
              <BedtimeOutlinedIcon className={[theme === 'dark'?"text-blue-500":"text-gray-400", "w-5 mr-2"].join(' ')}/>
              Dark
            </div>
            <div className={["flex flex-row cursor-pointer px-3 py-1 hover:bg-gray-100 dark:hover:bg-zinc-800", theme === 'system' && "text-blue-500"].join(' ')} onClick={() => handleChange('system')}>
              <MonitorIcon className={[theme === 'system'?"text-blue-500":"text-gray-400", "w-5 mr-2"].join(' ')}/>
              System
            </div>
          </div>
        }
    </div>
  );
};

export default ThemeSelector;

 

* MUI(Material UI) 아이콘이 사용된 코드입니다.

* 다듬어지지 않은 예시 코드입니다. 실제로 사용시에는 새로 만들거나 다듬어서 사용하시길 추천드립니다.

 

- useTheme()를 통해 현재 설정된 theme를 불러올 수 있고, setTheme를 사용하여 테마 설정을 변경할 수 있습니다.

   (system, light, dark 등으로 설정)

 

 

 

 

 

 

[next-themes 공식문서]

https://github.com/pacocoursey/next-themes

 

GitHub - pacocoursey/next-themes: Perfect Next.js dark mode in 2 lines of code. Support System preference and any other theme wi

Perfect Next.js dark mode in 2 lines of code. Support System preference and any other theme with no flashing - pacocoursey/next-themes

github.com

728x90
반응형
728x90
반응형

* git 연동 후 vercel에 등록된 상태로 진행해주세요*

 

1.  Postgres Database 생성

 

Storage -> Create Database 클릭

 

 

 

 

Postgres -> Database 설정

 

- Database Name : 데이터베이스명을 입력합니다.

- Region : 데이터센터의 물리적 위치를 선택합니다. (프로그램이 실행되는 위치와 가까운 장소를 선택할수록 빠른 통신이 가능합니다)

 

 

 

 

2. 프로젝트에 DB 연결

 

생성된 postgres database로 접속후 -> Getting Started -> Connect Project 클릭

 

 

 

 

vercel에 연결되어있는 프로젝트 중 DB에 연결할 프로젝트를 선택합니다.

 

저는 기본설정으로 연결하였습니다.

 

 

 

 

vercel link

vercel env pull .env.development.local

 

vscode로 프로젝트에 접속하여 로컬에서도 postgres를 사용할 수 있도록 설정합니다.

 

* .env.development.local 파일에는 postgres 관련 민감한 정보들이 들어있으니

    git 또는 외부에 공유되지 않도록 주의해야합니다.

 

 

 

 

3. 테이블 생성 및 데이터 추가

 

vercel -> Storage -> 생성한 postgres -> Data -> Query 로 접근

 

아래 쿼리들을 실행하여 데이터를 넣고 테스트 해봅시다.

 

 

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255),
    content TEXT,
    author VARCHAR(100)
);

 

해당 쿼리는 게시글 테이블을 생성합니다.

 

INSERT INTO posts (title, content, author) VALUES
    ('첫 번째 게시물', '첫 번째 게시물의 내용입니다.', '홍길동'),
    ('두 번째 게시물', '두 번째 게시물의 내용입니다.', '이순신'),
    ('세 번째 게시물', '세 번째 게시물의 내용입니다.', '강감찬'),
    ('네 번째 게시물', '네 번째 게시물의 내용입니다.', '유관순'),
    ('다섯 번째 게시물', '다섯 번째 게시물의 내용입니다.', '김유신');

 

해당 쿼리는 게시글 테이블에 데이터를 넣습니다.

 

 

 

데이터가 잘 들어왔다면 프로젝트에서 조회해봅시다.

 

 

 

 

4. 데이터 조회하기

npm install @vercel/postgres

 

postgres 데이터를 조회할 수 있는 라이브러리를 설치합니다.

 

 

 

/* /services/posts.ts */

'use server'

import { sql } from "@vercel/postgres";

export interface Posts {
	id : number,
	title : string,
	content : string,
	author : string,
}

export async function getPostsData(): Promise<Posts[]> {
	try {
		const { rows }: { rows: Posts[] } = await sql
			`SELECT id, title, content, author FROM posts;`;
		return rows;
	} catch (error) {
		throw new Error('Failed to fetch posts data');
	}
}

 

조회 쿼리를 통해 직접 게시글 목록을 조회하는 파일입니다.

 

 

/* page.tsx */

'use client'
import { Posts, getPostsData } from "@/services/posts";
import { useEffect, useState } from "react";

const defaultPosts: Posts = {
  id: 0,
  title: "",
  content: "",
  author: "",
};

export default function Page() {
  const [posts,getPosts] = useState<Posts[]>([defaultPosts]);

  useEffect(() => {
    fetchData();
  },[]);

  const fetchData = async () => {
    try {
      const postsData = await getPostsData();
      getPosts(postsData);
    } catch (error) {
      throw new Error('Failed to fetch posts data');
    }
  };

  return (
    <div>
      <div className="overflow-x-auto">
        <table className="min-w-full bg-white">
          <thead>
            <tr>
              <th className="px-6 py-3 bg-gray-100 text-left text-xs leading-4 font-medium text-gray-600 uppercase tracking-wider">제목</th>
              <th className="px-6 py-3 bg-gray-100 text-left text-xs leading-4 font-medium text-gray-600 uppercase tracking-wider">내용</th>
              <th className="px-6 py-3 bg-gray-100 text-left text-xs leading-4 font-medium text-gray-600 uppercase tracking-wider">작성자</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-200">
            {posts.map((post)=>(
              <tr key={post.id}>
                <td className="px-6 py-4 whitespace-no-wrap">{post.title}</td>
                <td className="px-6 py-4 whitespace-no-wrap">{post.content}</td>
                <td className="px-6 py-4 whitespace-no-wrap">{post.author}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

 

조회된 데이터가 테이블에 출력될 수 있도록 처리합니다.

 

 

 

 

 

postgres에 쿼리로 넣었던 데이터가 정상적으로 조회되는것을 볼 수 있습니다.

 

 

 

 

DROP TABLE posts;

 

마지막으로 테스트용 테이블인 posts를 삭제하고 프로젝트에 맞게 사용하시면 됩니다.

728x90
반응형
728x90
반응형

1.  SVRG 설치

# NPM
npm install --save-dev @svgr/webpack

# Yarn 
yarn add --dev @svgr/webpack

 

 

 

2. next.config.js에  웹팩 구성 추가

[next.config.js에 추가하는 경우]

module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      use: ['@svgr/webpack'],
    })

    return config
  },
}

 

[next.config.mjs에 추가하는 경우]

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      use: ['@svgr/webpack'],
    })

    return config
  },
};

export default nextConfig;

 

웹팩 구성으로 위의 코드를 추가하지 않으면 아래와 같은 오류가 발생합니다.

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

 

 

 

3. svg 이미지를 컴포넌트로 import


import Note from '@public/svgs/note.svg';

const TodoList: React.FC = () => {

  return (
    <>
      <Note/>
    </>
  );
};

export default TodoList;

 

 

 

*svg 관련해서 폴더 구조 잡을때 아래 글도 참고하기 좋았습니다. 추천드립니다.

Next.js 폴더/파일 구조 잡기 (miriya.net)

 

Next.js 폴더/파일 구조 잡기

주니어 개발자들이 가장 많이 물어보는 질문이 폴더 구조에 대해 묻는 것이다. 사실 이런 질문들은 항상 답이 정해져있다. “그때 그때 달라요” 아니 시발 그때 그때 다른게 어딨어? 하고 빡이

miriya.net

* 공식문서

https://blog.logrocket.com/import-svgs-next-js-apps/

 

How to import SVGs into your Next.js apps - LogRocket Blog

This article will explore the different methods you can use to import and use SVGs in a Next.js application.

blog.logrocket.com

 

728x90
반응형

+ Recent posts