Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

kohigowild

SPA CSR SSR SEO SSG JKP 본문

mitmitwiki

SPA CSR SSR SEO SSG JKP

kohi ☕ 2023. 5. 19. 02:48

SPA (Single Page Application)

  • 한 개의 페이지로 구성된 웹 애플리케이션
  • 일반적으로 초기 로딩 시에 필요한 모든 리소스를 로드하고, 이후에는 동적으로 콘텐츠를 변경하거나 업데이트하는 방식으로 동작한다.

 

기존의 웹 애플리케이션(MPA)은 새로운 페이지를 로드할 때마다 전체 페이지를 서버에서 다시 가져와야 한다. 이는 사용자 경험과 성능에 부정적인 영향을 끼칠 수 있다.

📡 MPA (Multi Page Application)
여러 개의 페이지로 구성된 전통적인 웹 애플리케이션으로, 각 페이지는 서버에서 새로운 HTML 문서를 로드하여 표시하며, 사용자의 상호 작용에 따라 페이지가 전환된다.

장점
1. 각 페이지가 별개의 HTML 문서로 구성되어 있기 때문에 검색 엔진에서 더 잘 인덱싱될 수 있다.
2. 각 페이지는 필요한 시점에만 로드되기 때문에 초기 페이지 로딩 속도가 빠를 수 있다.

단점
1. 각 페이지 전환마다 서버에서 새로운 HTML을 가져와야 하기 때문에 페이지 전환 속도가 상대적으로 느릴 수 있다. 사용자 경험에 좋지 않다.
2. 각 페이지 요청마다 서버에서 HTML 문서를 생성하고 전송해야 한다. 이로 인해 서버에 더 큰 부담이 가게 될 수 있다.

 

반면에 SPA는 페이지 전환 시에 화면이 새로 고쳐지지 않고, 동적으로 콘텐츠를 업데이트하기 때문에 부드러운 사용자 경험을 제공한다. 페이지의 일부분만 업데이트되므로 사용자는 필요한 데이터나 콘텐츠를 즉시 볼 수 있다. 또한 초기에 필요한 리소스를 한 번에 로드하고, 이후에는 필요한 데이터만 가져오기 때문에 페이지 전환 속도가 빠르다는 장점이 있다.

SPA의 단점으로는 클라이언트 측에서 모든 페이지 전환에 필요한 리소스를 유지하므로, 오랜 시간 사용하거나 많은 페이지를 방문하는 경우 메모리 사용량이 증가할 수 있다. 초기에 필요한 모든 리소스를 한 번에 로드해야 하므로 초기 로딩 속도가 오래 걸릴 수 있다는 점이 있다.

SPA는 주로 CSR 방식을 채택하여 구현된다. SPA ≠ CSR

 

CSR (Client-Side Rendering)

CSR은 클라이언트(브라우저) 측에서 동적으로 콘텐츠를 렌더링하는 방식이다. 초기 로딩 시에는 주로 정적인 HTML, CSS, JavaScript 파일을 로드하고, 이후에는 JavaScript를 사용하여 동적으로 콘텐츠를 생성하고 렌더링한다. 서버에서 처리 없이 클라이언트로 보내주기 때문에 자바스크립트가 모두 다운로드 되고 실행이 끝나기 전까지 사용자는 볼 수 있는 게 없고, SEO 대응이 어렵다.

 

장점

  • 클라이언트 측에서 동적으로 콘텐츠를 렌더링하기 때문에 페이지 전환 시에 부드러운 사용자 경험을 제공할 수 있다.
  • 클라이언트에서 콘텐츠를 렌더링하므로 서버 부하가 감소하고, 서버에서는 주로 데이터 제공에 집중할 수 있다.

 

단점

  • 초기 로딩 시에는 비어있는 페이지가 로드되어 SEO(Search Engine Optimization)에 어려움이 있고, 검색 엔진이 콘텐츠를 크롤링하고 인덱싱하는데 시간이 걸릴 수 있다.
  • 초기 로딩 시에 필요한 자원을 모두 다운로드하고, 클라이언트에서 동적으로 콘텐츠를 생성하기 때문에 초기 로딩 속도가 상대적으로 느릴 수 있다.

 

권장 예시

  • 사용자와의 상호작용이 많고 동적인 콘텐츠를 제공해야 하는 경우
  • 웹 브라우저 뿐만 아니라 모바일 앱 등 다양한 플랫폼에서 동일한 코드베이스를 사용하고자 할 때
  • 클라이언트 측에서 자원(CPU, 메모리) 활용이 중요한 경우

 

친구(https://chat.openai.com/)에게 물어봤다 👇

CSR 환경에서 SEO 대응이 어려운 이유가 뭐야
CSR(Client-Side Rendering) 환경에서 SEO(Search Engine Optimization) 대응이 어려운 이유는 다음과 같습니다.

초기 로딩 시점: CSR은 초기 로딩 시에는 정적인 HTML 파일을 반환하지 않고, 비어있는 HTML을 렌더링합니다. 이후에 JavaScript가 실행되어 동적으로 콘텐츠를 생성하고 렌더링합니다. 이로 인해 검색 엔진이 초기 로딩 시에 콘텐츠를 크롤링하기 어려워집니다.

검색 엔진 크롤러의 제한: 일부 검색 엔진 크롤러는 JavaScript를 실행하지만, 모든 JavaScript 기반 애플리케이션을 완전히 이해하고 렌더링하지는 못합니다. 따라서 CSR 환경에서는 검색 엔진이 애플리케이션의 전체 콘텐츠를 이해하기 어려울 수 있습니다.

지연된 인덱싱: CSR 환경에서는 초기 로딩 시에는 비어있는 페이지가 로드되기 때문에 검색 엔진이 콘텐츠를 크롤링하고 인덱싱하는데 시간이 걸릴 수 있습니다. 이로 인해 새로운 페이지나 업데이트된 콘텐츠가 검색 결과에 반영되기까지의 지연이 발생할 수 있습니다.

메타데이터 관리의 어려움: CSR에서는 페이지 간 전환 시에 HTML의 메타데이터(예: 제목, 설명, 키워드)를 동적으로 변경해야 합니다. 이는 검색 엔진이 페이지의 정보를 파악하는 데 어려움을 줄 수 있습니다.

 

SSR(Server-Side Rendering)

SSR은 서버에서 사용자에게 보여줄 페이지를 모두 구성하여 사용자에게 페이지를 보여주는 방식이다. 서버에서 페이지를 구성해서 클라이언트로 넘기기 때문에 클라이언트에서 구성하는 CSR(client-side rendering)보다 페이지를 구성하는 속도는 늦어지지만 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다는 장점이 있다. 더불어 SEO(search engine optimization) 또한 쉽게 구성할 수 있다.

 

장점

  • 서버에서 콘텐츠를 렌더링하여 초기 로딩 시에도 완성된 HTML을 제공하기 때문에 검색 엔진이 콘텐츠를 크롤링하고 인덱싱하기 용이하다.
  • 초기 로딩 시에 완성된 HTML을 제공하므로, 클라이언트는 콘텐츠를 기다리지 않고 바로 렌더링할 수 있어 빠른 초기 로딩 속도를 제공할 수 있다.

 

단점

  • 서버에서 콘텐츠를 렌더링하므로 초기 로딩 시에 서버 부하가 발생할 수 있다.
  • 동적인 콘텐츠가 많은 페이지의 경우 서버에서 렌더링하는 과정이 복잡해질 수 있으며, 클라이언트에서 처리하는 CSR에 비해 렌더링 성능이 떨어질 수 있다.
  • SSR은 페이지 전환 시에 서버에 요청을 보내야 하므로 CSR에 비해 사용자 경험이 다소 제한될 수 있다.

 

권장 예시

  • 검색 엔진 최적화(SEO)가 프로젝트의 핵심 요구사항일 때
  • 검색 엔진에서 콘텐츠를 잘 인덱싱하고 검색 결과에 반영해야 하는 경우
  • 초기 로딩 속도가 중요한 경우

 

SEO (검색 엔진 최적화, Search Engine Optimization)

SEO는 웹 사이트의 방문자를 증가시키고 검색 엔진에서 더 높은 순위를 얻기 위해 웹 페이지를 최적화하는 프로세스고 왕년에 광고 회사 다닐 때 귀에 딱지가 앉도록 들은 거여서 뭔지 아주 잘 알기 때문에 나한테는 지금 이게 중요한 것이 아님 그럼 뭐가 중요하냐

 

SEO를 최적화하는 방법 (Feat. Next.js)

 

1. 메타 데이터 설정

import Head from 'next/head';

function MyPage() {
  return (
    <div>
      <Head>
        <title>My Page Title</title>
        <meta name="description" content="페이지에 대한 설명" />
      </Head>
      {/* 페이지의 내용 */}
    </div>
  );
}

각 페이지마다 메타 데이터를 설정하여 검색 엔진이 페이지를 이해하고 색인화할 수 있도록 한다. Next.js에서는 <Head> 컴포넌트를 사용하여 페이지의 <title>, <meta>, <link> 등을 설정할 수 있다.

 

2. 페이지 구조 최적화

Next.js는 페이지를 기반으로한 라우팅을 지원하므로, 페이지 URL 구조를 사용자 친화적이고 검색 엔진에 친숙한 방식으로 설계할 수 있다. 명확하고 의미 있는 URL을 사용하고, 중요한 키워드를 URL에 포함시키는 것이 좋다.

 

3. 서버 사이드 렌더링 (SSR)

import { useEffect, useState } from 'react';

function HomePage({ serverRenderedData }) {
  const [clientRenderedData, setClientRenderedData] = useState(null);

  useEffect(() => {
    // 클라이언트에서 데이터를 가져와서 설정
    setClientRenderedData('Client Rendered Data');
  }, []);

  return (
    <div>
      <h1>Server Side Rendering</h1>
      <p>서버에서 렌더링된 데이터: {serverRenderedData}</p>
      <p>클라이언트에서 렌더링된 데이터: {clientRenderedData}</p>
    </div>
  );
}

export async function getServerSideProps() {
  // 서버에서 데이터를 가져와서 props로 전달
  const serverRenderedData = 'Server Rendered Data';

  return {
    props: {
      serverRenderedData,
    },
  };
}

export default HomePage;

Next.js의 가장 큰 장점은 서버 사이드 렌더링을 지원한다는 것이다. getServerSideProps나 getStaticProps를 사용하여 서버 측에서 데이터를 가져올 수 있다. 해당 예제는 getServerSideProps 함수를 사용하여 서버에서 데이터를 가져오고, 컴포넌트에서 해당 데이터를 렌더링한다. 이렇게 함으로써 페이지의 초기 렌더링은 서버에서 이루어지며, 검색 엔진은 페이지의 완전한 내용을 색인화할 수 있다.

 

4. 이미지 최적화

이미지는 웹 페이지의 성능과 검색 엔진에서의 노출에 영향을 준다. Next.js에서는 next/image 컴포넌트를 사용하여 이미지를 최적화하고 렌더링할 수 있다.

 

SSG (Static Site Generation)

빌드 시점에 사전에 페이지를 생성하여 서버나 클라이언트 요청에 관계없이 사이트를 제공하는 방식이다.

전에 봤던 기술 면접 때 SSG 들어봤냐는 질문이 들어왔는데 신세계가 진심 턱 끝까지 찼지만 어른답게 참았다... 이제 어른 말고 개발자답게 신세계 꺼내고 정적 사이트 생성기 주입해 보겠음...

 

SSG 동작 방식

  • Next.js는 페이지의 데이터를 빌드 시점에서 가져와서 해당 데이터를 기반으로 페이지를 사전 렌더링한다. 매 요청마다 서버나 데이터베이스에 접근할 필요 없이 사전에 준비된 페이지를 제공할 수 있다.
  • 사전 렌더링된 페이지는 정적 HTML 파일로 생성된다. 이 HTML 파일은 다른 요청이 있을 때마다 재사용된다.
  • 이미 빌드 시점에 사전에 준비된 정적 HTML 파일이기 때문에 초기 로딩 속도가 빠르다.
  • 검색 엔진은 사이트의 콘텐츠를 색인화할 때 HTML 파일을 분석한다. 정적 HTML 파일을 생성하면 검색 엔진은 페이지의 콘텐츠를 보다 쉽게 이해하고 색인화할 수 있다.
  • SSG를 구현하려면 Next.js에서 getStaticProps라는 특수한 함수를 사용한다. 이 함수는 빌드 시점에서 데이터를 가져와서 페이지의 props로 전달한다. getStaticProps 함수를 사용하면 페이지를 사전 렌더링할 수 있고, 빌드 시에 정적 HTML 파일로 생성된다.

 

// pages/posts/[slug].js

import { useRouter } from 'next/router';

function Post({ post }) {
  const router = useRouter();

  // 동적 라우팅된 페이지에서의 로딩 상태 처리
  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

export async function getStaticPaths() {
  // 데이터베이스나 외부 API에서 포스트의 slug를 가져옴
  const paths = [
    { params: { slug: 'post-1' } },
    { params: { slug: 'post-2' } },
    // ...
  ];

  return {
    paths,
    fallback: true, // 다른 경로로 접근 시에 대체 컨텐츠를 제공할지 여부
  };
}

export async function getStaticProps({ params }) {
  // params.slug를 사용하여 데이터베이스나 외부 API에서 해당 포스트 데이터를 가져옴
  const post = {
    slug: params.slug,
    title: 'Post Title',
    content: 'Post Content',
  };

  return {
    props: {
      post,
    },
    revalidate: 60, // 캐시 유효성 검사를 위해 60초마다 페이지 재생성
  };
}

export default Post;

 

위의 코드는 동적 라우팅된 페이지의 SSG 예제이다. getStaticPaths 함수에서는 동적으로 생성될 수 있는 경로를 정의한다. getStaticProps 함수에서는 동적 경로에서 사용될 데이터를 가져온다.

이렇게 구현된 SSG 페이지는 빌드 시점에서 사전 렌더링되어 정적 HTML 파일로 생성된다. 이후 브라우저에서 해당 페이지에 접근할 때는 정적 HTML 파일이 사용되어 초기 로딩 속도가 향상되고, 검색 엔진은 페이지의 콘텐츠를 쉽게 인식하여 색인화할 수 있다.