미새문지

24.10.10 day77 Next.js 폴더 구조, 프론트엔드 시점의 SaaS 본문

개발 TIL

24.10.10 day77 Next.js 폴더 구조, 프론트엔드 시점의 SaaS

문미새 2024. 10. 10. 21:43
728x90

넥스트를 처음 설치하게 되면 프로젝트 폴더의 구조는 이렇게 되어있다.

 

app 폴더는 넥스트의 App Router 기능을을 사용하여 페이지와 라우트를 구성한다.

 

page.tsx 파일은 해당 파일이 각 페이지의 기본 파일이며, 이 파일이 루트 경로(/)에 해당한다. 넥스트는 app폴더에서 page.tsx파일을 페이지로 인식하고, 자동으로 라우팅해준다.

 

layout.tsx 파일은 해당 파일은 모든 페이지에 공통으로 적용되는 레이아웃을 정의하는데 예를 들어, 헤더, 네비게이션 바, 푸터 등모든 페이지에 들어가는 공통 컴포넌트를 정의할 수 있다.

 

page.module.css 파일은 해당 페이지와 관련된 CSS 파일이며, 모듈 CSS 방식으로 컴포넌트에 스타일을 적용할 수 있다. css파일로 작성하던 css 파일 코드들을 모두 여기에 작성한다고 보면 된다.

 

globals.css 파일은 전역 스타일을 설정하는 파일이며, 사이트 전반에 적용될 공통적인 스타일을 정의할 때 사용한다.

공통 스타일은 아마 자주 쓰이는 공용 컴포넌트의 css라던지 페이지 자체의 css라던지를 작성하는 것 같다.

 

그럼 라우팅은 어떻게 연결하는가, 경로로 이동하는 페이지를 만들고 싶다면 src/app 폴더 안에 새 폴더를 만들고 page.tsx 파일을 생성하면 해당 파일의 구조가 폴더 이름의 경로가 된다.

예를 들어, src/app/login/page.tsx 파일을 만들면 /login 경로에 접근 시 login폴더 안에 있는 page 구조가 보이게 된다.

export default function About() {
  return (
    <div>
      <h1>로그인</h1>
      <p>로그인 페이지</p>
    </div>
  );
}
해당 코드를 작성하고 브라우저에 localhost:3000/login을 입력하면 해당 페이지가 출력되게 된다.
 
 
 
 
기존에는 함수 방식이 아니라 컴포넌트 방식으로 만들었었는데 이것도 뭔가 페이지 자체는 함수형으로 쓰고 부분만 컴포넌트형으로 만드는건가 한번 찾아봐야 할 것 같다.
 

:root {
  --background: #ffffff;
  --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

body {
  color: var(--foreground);
  background: var(--background);
  font-family: Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}
이 코드는 넥스트의 기본 세팅되어 있는 globals.css 코드이다. 리액트 프로젝트의 index.css에 들어있는 코드와 유사한데, 넥스트는 좀 더 세밀하게 기본 세팅을 해주는 것 같더라.
 
:root {
  --background: #ffffff;
  --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}
이 부분은 페이지의 다크모드에 대한 기본 설정인데 브라우저의 다크 모드를 인식하면 해당 배경을 다크 모드로 적용해준다.
만약 다크 모드같은 기능을 사용하지 않을 거라면 지워도 상관없는데 페이지의 기본적인 스타일 관리를 편하게 하려면 유지하는게 낫다고 한다.
 
html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

body {
  color: var(--foreground);
  background: var(--background);
  font-family: Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

이 부분은 페이지를 넘어가는 부분을 제한시키고, 수평 스크롤을 방지해준다. 그리고 root에서 지정한 배경 값과 색상값을 전체에 지정해주는 코드인데, 스크롤을 막는 경우 페이지의 구조 내에서만 스크롤을 발생시키거나 풀페이지를 작성할 때나 사용하지 않을까 하여 이 부분은 본인은 사용하진 않을 것 같다.

 

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

이 부분은 페이지의 여백을 초기화시키기 위한 코드이고 링크 이벤트를 발생시킬 때 해당 텍스트가 하이퍼텍스트 효과로 변경하는걸 방지해준다. 필수 요소기 때문에 해당 코드는 냅두려고 한다.

 

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}

제일 하단 부분이 다크모드를 인식하는 코드이다. 사용자의 브라우저가 다크모드일 때 사이트를 다크모드로 변경해주는 역할을 한다.

직접 설정해야 하는 리액트와  달리 넥스트는 기본 설정으로 다크모드를 지원해주기 때문에 유지해주는 게 좋은 것 같다.


import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";

const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        {children}
      </body>
    </html>
  );
}

이 코드는 layout.tsx 파일의 기본 코드이다. 레이아웃은 화면에 기본적으로 보여지는 구조를 유지하는데 필요한데, UI가 보여질 하단의 RootLayout함수에 헤더와 푸터를 집어넣을 경우 어느 페이지를 가도 헤더 푸터가 유지가 되는 것이다. 리액트로 생각하면 app.js에 라우팅으로 묶기 전 헤더와 푸터를 지정해주는 것과 같은 듯.

 

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

이 코드는 메타데이터를 작성하는 곳이며, 사이트의 제목과 브라우저에서 보일 설명을 지정하는 곳이다.

브라우저가 크롬이라고 했을 때

파비콘과 함께 수정할 제목 부분을 여기서 지정해준다.

description부분은 아마 넥슨을 검색했을 때 하단에 보이는 설명 부분이 아닐까 예상한다.

 

import localFont from "next/font/local";
const geistSans = localFont({
  src: "./fonts/GeistVF.woff",
  variable: "--font-geist-sans",
  weight: "100 900",
});
const geistMono = localFont({
  src: "./fonts/GeistMonoVF.woff",
  variable: "--font-geist-mono",
  weight: "100 900",
});

이 코드는 폰트 지정 코드이며 현재는 기본 세팅에 들어있는 폰트를 받아오고 있지만, 나중에 폰트를 바꿀 일이 있다면 이 코드를 수정하면 된다.

 

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode; }>) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        {children}
      </body>
    </html>
  );
}

이 코드가 화면에 어떻게 보여질 지 출력해주는 코드인데, 현재는 app에 있는 page.tsx 코드를 화면에 출력해주고 있다.

classname엔 폰트명을 지정해서 사용할 폰트를 받아오고 있고, React.ReactNode는 타입스크립트로 현재 페이지 함수의 타입을 지정해주는 것이다. React.FC와 같지만 FC는 페이지가 컴포넌트형일 때 FC로 받아오는 거고 함수형은 Node인가보다.

 

여기에 만약 헤더랑 푸터를 넣는다고 가정하면

    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        <header>여긴 헤더</header>
        {children}
        <footer>여긴 푸터</footer>
      </body>
    </html>

해당 부분도 화면에 출력되게 된다.

주로 헤더는 사이트의 로고, 이름, 접근 아이콘등을 포함하는 편이고, 푸터는 본 사이트 기업의 설명이나 정보등이 들어있다.

이 코드도 필요없는 부분인줄 알고 지우려 했는데 찾아보니 너무 중요하고 필수적인 요소라 그대로 냅두고 화면 출력 부분만 컴포넌트를 추가해줄 계획이다.


컴포넌트의 경우 src폴더 안에 app과 같은 위치에 폴더를 생성해서 쓰는게 일반적이다. 하지만 리액트와 달리 넥스트는 app폴더 안에서 자동적으로 라우팅을 지원해주기 때문에 재사용이 가능한 컴포넌트의 경우만 컴포넌트 폴더에 집어넣는다고 한다.

그렇기 때문에 페이지 UI는 각 app/해당폴더/page.tsx에서 작성하되 컴포넌트만 리액트처럼 끌어오면 될 것 같다.

 

예시로 컴포넌트에 헤더 컴포넌트를 만들고 헤더를 layout.tsx 코드에 가지고 오면 기존 방식대로 헤더 컴포넌트의 내용이 화면에 출력된다.

const Header: React.FC = () => {
  return (
    <>
      <div>이건 헤더입니다. 컴포넌트 테스트</div>
    </>
  );
};
export default Header;

잘 가져오는 걸 확인할 수 있다.

 

그리고 css의 경우 해당 폴더 내에 페이지 코드가 page.tsx로 통일되기 때문에 css도 page.module.css로 이름을 지정해주면 해당 페이지를 자동으로 인식해서 적용시켜준다고 한다. 넥스트를 많이들 쓰는 이유가 너무 편한 기능때문인게 체감이 되고 있다.

 

import styles from "./page.module.css";

export default function About() {
  return (
    <div className={styles.loginContainer}>
      <h1>로그인</h1>
      <form>
        <input
          type="email"
          placeholder="이메일"
          className={styles.inputField}
        />
        <input
          type="password"
          placeholder="비밀번호"
          className={styles.inputField}
        />
        <button type="submit" className={styles.button}>
          로그인
        </button>
      </form>
    </div>
  );
}
.loginContainer {
  padding: 20px;
  max-width: 400px;
  margin: 0 auto;
  text-align: center;
}

.inputField {
  display: block;
  margin: 10px 0;
  padding: 8px;
  width: 100%;
}

.button {
  padding: 10px;
  background-color: #0070f3;
  color: white;
  border: none;
  cursor: pointer;
  width: 100%;
}

예시로 로그인폴더의 page.tsx와 page.module.css를 작성해서 localhost:3000/login으로 가면 제대로 css가 적용되게 된다.

결국 넥스트의 폴더 구조를 유지한 채 각 페이지 별로 app폴더 안에서 경로 명으로 폴더를 생성 후에 안에서 작업하면 끝인 것 같다. 컴포넌트의 경우 컴포넌트 폴더를 만들어서 가져오면 되는 거고, 너무 편한데?


이력서를 넣었던 기업 중 자격요건이 SaaS개발 해본 사람을 뽑길래 뭔지 궁금해서 찾아봤었다. 

SaaS(Software as a Service)는 클라우드에서 호스팅되고 구독 모델로 제공되는 소프트웨어로, 사용자가 서버에 설치하지 않고 인터넷을 통해 애플리케이션에 접근해 사용할 수 있다고 한다.

사용자는 애플리케이션을 구독하여 특정 기간 동안 기능을 이용하고, 서비스가 지속적으로 업데이트된다고 하는데, 클라우드로 띄우는 서비스 자체를 SaaS라고 하는건지 궁금해서 프론트엔드 시점에서 좀 찾아봤다.

프론트엔드 개발자는 SaaS에서 사용자가 주로 직접 상호작용하는 UI와 UX를 개발하는 역할을 하며, 사용자의 데이터 입력과 데이터 처리 등을 맡는다. 

 

SaaS에서 프론트엔드 개발자의 업무

UI/UX 설계

  • SaaS 애플리케이션의 UI는 효율적이고 직관적이어야 한다. 특히 대시보드, 데이터 시각화, 설정 페이지 등 다양한 기능을 제공하는 화면을 설계해야 하기 때문에 가독성이 좋아야 한다.
  • 사용자 경험을 고려한 디자인과 흐름을 설계하여, 사용자가 서비스에 쉽게 접근하고 사용할 수 있도록 만들어야 한다.
  • 그렇기 때문에 반응형 웹 디자인을 적용하여 모바일, 태블릿, 데스크탑 환경 모두에서 잘 작동하도록 해야 한다.

상태 관리 및 데이터 처리

  • SaaS 애플리케이션은 복잡한 상태 관리를 요구할 수 있는데, 사용자의 데이터 입력과 애플리케이션의 상태를 실시간으로 업데이트하기 위해 리덕스 같은 상태 관리 라이브러리가 자주 쓰인다.
  • 데이터는 보통 백엔드 API와 연동하여 처리되기 때문에, API 요청, 데이터 처리, 응답 처리를 효율적으로 구현해야 하며, 주로 REST API, GraphQL 등이 사용된다고 한다.

사용자 인증 및 권한 관리

  • SaaS 서비스는 다수의 사용자가 사용할 수 있어야 하므로 사용자 인증권한 관리가 중요하다.
  • 예를 들어, OAuth2, JWT, 세션 관리 등을 통해 사용자가 로그인하고 인증을 거친 후에 서비스를 사용할 수 있도록 해야 한다.
  • 권한 관리 기능을 통해 사용자가 접근할 수 있는 기능과 제한된 기능을 구분하는데, 예를 들어, 관리자일반 사용자의 권한을 다르게 설정할 수 있다.

보안

  • SaaS 애플리케이션에서 보안은 매우 중요하며, 민감한 데이터가 다뤄지므로 SSL/TLS와 같은 데이터 암호화 보안 기술을 사용하여 사용자의 정보를 보호해야 한다.
  • 또한 CORS(Cross-Origin Resource Sharing), XSS(Cross-Site Scripting), CSRF(Cross-Site Request Forgery) 등의 보안 위협에 대해 충분한 대비책을 마련해야 한다.

다국적 사용자 지원

  • 많은 SaaS 애플리케이션은 다국적 사용자를 대상으로 서비스를 제공하기 때문에 다국어 지원국가별 시간대 처리 등을 고려하여 애플리케이션을 설계해야 한다.
  • 프론트엔드는 i18n(국제화)과 l10n(지역화) 기능을 통해 다양한 언어와 지역에 맞는 콘텐츠를 제공해야 한다.

또한, SaaS개발을 하기 위해선 프론트엔드 배포도 따로 할 수 있어야 하기 때문에 나중에 코드를 빌드해 캡슐화 하는 부분과 배포 하는 부분을 학습하려고 한다.

728x90