728x90

SvelteKit은 기본적으로 서버 사이드 렌더링(SSR)을 지원합니다. 그런데 writable()로 만든 store 값이 페이지를 새로고침하거나 이동할 때 초기화되는 문제가 발생할 수 있습니다.

문제 원인

  • SvelteKit은 SSR 시 매 요청마다 store 인스턴스를 새로 생성합니다.
  • 이로 인해 클라이언트에서 저장한 store 값이 서버에는 전달되지 않고 초기값으로 리셋됩니다.

간단한 해결 방법: sessionStorage 동기화

클라이언트 환경에서만 store 값을 sessionStorage에 저장하고, 컴포넌트가 로드될 때 다시 불러오도록 설정하면 값이 유지됩니다.

1. store 정의

src/lib/stores/locationStore.ts
import { writable } from 'svelte/store';
import { browser } from '$app/environment';

const initial = browser && sessionStorage.getItem('location')
  ? JSON.parse(sessionStorage.getItem('location'))
  : {
      x: null,
      y: null,
      address: '',
      name: ''
    };

export const locationStore = writable(initial);

locationStore.subscribe(value => {
  if (browser) {
    sessionStorage.setItem('location', JSON.stringify(value));
  }
});
  

2. 사용 예 (store 값 설정)

import { locationStore } from '$lib/stores/locationStore';

function selectStoreData(data) {
  locationStore.set({
    x: data.x,
    y: data.y,
    address: data.address,
    name: data.name
  });
}
  

3. 다른 페이지에서 가져오기

<code class="language-svelte">
<script>
  import { locationStore } from '$lib/stores/locationStore';
  $: location = $locationStore;
</script>

<p>선택된 주소: {location.address}</p>
<p>좌표: {location.x}, {location.y}</p>
</code>

 

 

보완 팁

  • sessionStorage는 탭 간 공유되지 않지만, 새로고침이나 뒤로가기엔 적합
  • localStorage를 사용하면 브라우저 간에도 값 유지 가능
  • 민감한 정보는 절대 저장하지 마세요 (브라우저 저장소는 안전하지 않음)

결론

SvelteKit에서 클라이언트 상태를 SSR 환경에서도 유지하고 싶다면,

가장 간단한 해결책은 스토어 값을 sessionStorage에 저장하고, 페이지 로드시 다시 복원하는 방식입니다.

728x90
728x90

SvelteKit SSR(서버사이드 렌더링) 프로젝트를 Cloudflare Pages Functions 환경에 wranglerwrangler.toml을 이용해 직접 배포한 과정을 정리합니다.

1. SvelteKit 프로젝트 설정

  • @sveltejs/adapter-cloudflare 어댑터 설치
    npm install -D @sveltejs/adapter-cloudflare
  • svelte.config.js에 어댑터 적용
    import adapter from '@sveltejs/adapter-cloudflare';
    export default {
      kit: {
        adapter: adapter()
      }
    };

2. wrangler.toml 파일 작성

프로젝트 루트에 wrangler.toml 파일을 만들고 아래와 같이 작성합니다.

하나라도 빠지면 실패합니다.

name = "프로젝트이름"
pages_build_output_dir = ".svelte-kit/cloudflare"
compatibility_date = "2025-06-04"
compatibility_flags = [ "nodejs_compat" ]
  • name: 프로젝트 이름(영문, 소문자, 숫자, 하이픈 등)
  • pages_build_output_dir: SvelteKit Cloudflare 어댑터 빌드 결과 폴더
  • compatibility_flags: SSR을 위한 Node.js 호환 플래그

3. 빌드 및 배포

  • Cloudflare 계정 로그인
    npx wrangler login
  • 프로젝트 빌드
    npm run build
  • Cloudflare Pages Functions로 배포
    npx wrangler pages deploy .svelte-kit/cloudflare
TIP: wrangler.toml을 수정할 때마다 npm run buildwrangler pages deploy를 다시 실행해야 변경사항이 반영됩니다.

4. 배포 결과 및 확인

  • 배포가 완료되면 https://프로젝트명.pages.dev에서 SSR이 적용된 SvelteKit 사이트를 확인할 수 있습니다.
  • Cloudflare Pages Functions 환경에서 SSR/Edge 기능이 정상 동작합니다.
  • Node.js 내장 모듈(예: async_hooks)을 사용하는 경우 compatibility_flags 옵션이 반드시 필요합니다.

5. 주요 에러 및 해결법

  • async_hooks 에러: wrangler.toml에 compatibility_flags = [ "nodejs_compat" ] 추가
  • Missing top-level field "name": wrangler.toml에 name = "프로젝트이름" 추가
  • pages_build_output_dir 경고: wrangler.toml에 pages_build_output_dir = ".svelte-kit/cloudflare" 추가

6. 참고 자료

정리:
  • SSR이 필요한 SvelteKit 앱은 @sveltejs/adapter-cloudflarewrangler.toml을 이용해 Pages Functions 환경에 배포
  • wrangler.toml에 name, pages_build_output_dir, compatibility_flags 필수
  • 빌드 & 배포는 npm run buildnpx wrangler pages deploy .svelte-kit/cloudflare

Github 연동해서 배포하면 이런 설정은 필요없습니다.

728x90
728x90

 

SvelteKit은 빠르고 유연한 웹 프레임워크로, 최근에는 npx sv create 방식으로 프로젝트를 생성하는 것이 권장됩니다.

📦 프로젝트 생성 명령어

npx sv create my-app

my-app 대신 원하는 프로젝트명을 넣으면 됩니다.

📂 생성 후 기본 작업

cd my-app
npm install
npm run dev

이후 http://localhost:5173에서 프로젝트를 확인할 수 있습니다.

🛠️ 선택 가능한 추가 도구 기능

도구 설명
Prettier 코드 스타일을 자동 정리해주는 포매터
ESLint 문법 오류와 코드 품질 문제를 탐지하는 검사기
Vitest Vite 기반의 빠르고 가벼운 단위 테스트 도구
Playwright 브라우저 기반의 E2E 테스트 도구로 UI 테스트 가능
Tailwind CSS 유틸리티 기반의 CSS 프레임워크로 빠른 스타일링 가능
Drizzle 타입 세이프한 SQL 쿼리 빌더, DB 접근에 적합
Lucia 사용자 인증, 로그인/로그아웃, 세션 관리 등을 지원
MDsveX Markdown을 Svelte 컴포넌트처럼 사용하는 플러그인
Paraglide 다국어(i18n) 지원을 위한 번역 도구
Storybook 컴포넌트 독립 개발 및 문서화를 위한 UI 도구

💡 추천 조합 예시

  • 웹앱 개발: Tailwind CSS, ESLint, Prettier, Vitest, Lucia, Drizzle
  • 블로그/문서 사이트: MDsveX, Prettier, ESLint, Tailwind CSS
  • 디자인 시스템/대규모 UI: Storybook, Prettier, ESLint, Vitest, Tailwind CSS

🔗 참고 링크

728x90
728x90

 

 

이 포스트에서는 MongoDB와 Redis를 결합하여, 자주 조회되는 데이터를 캐시하고, MongoDB에 대한 부하를 줄이는 방법을 설명합니다. 이 접근 방식은 웹 애플리케이션에서 성능을 최적화하는 데 매우 유용합니다.

1. 기본 개념

일반적으로 데이터베이스에서 데이터를 조회하는 과정은 시간이 걸리며, 동일한 데이터에 대해 반복적으로 쿼리를 실행하는 것은 비효율적입니다. Redis와 같은 캐시 시스템을 사용하면 데이터를 메모리에 저장하여 빠르게 조회할 수 있습니다. 이 예시에서는 MongoDB에서 데이터를 조회하고 Redis에서 캐시된 데이터를 사용하여 성능을 최적화합니다.

2. 코드 설명

아래 코드는 MongoDB와 Redis를 결합하여 데이터를 캐시하는 과정을 구현한 예시입니다.


import { connectToDatabase } from '$lib/mongodb'; // MongoDB 연결 함수 임포트
import redis from '$lib/redis';

const db = await connectToDatabase();

async function reloadCacheWithExpiration(cacheKey, data) {
  // Redis에 데이터를 저장하면서 만료 시간을 리셋 (3600초 = 1시간)
  redis.setex(cacheKey, 3600, JSON.stringify(data));
}

export async function load() {
  // 예시로 상품 ID를 이용한 cacheKey 설정
  // const cacheKey = 'test'; // 'product:987' 형식
  const limit = 1000;
  const cacheKey = `post:${limit}`;  // 캐시 키 설정: 조건에 따라 캐시 키가 달라짐

  // Redis에서 데이터 조회
  let cachedData = await new Promise((resolve, reject) => {
    redis.get(cacheKey, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data ? JSON.parse(data) : null);
    });
  });

  // 캐시가 없으면 MongoDB에서 조회 후 Redis에 저장
  if (!cachedData) {
    console.log('캐시가 없어 MongoDB에서 조회');
    const data = await db.collection('Data').find().limit(limit).toArray();

    // MongoDB에서 데이터를 가져왔다면 Redis에 캐시 저장
    if (data) {
      reloadCacheWithExpiration(cacheKey, data); // 1시간 동안 캐시
      cachedData = data;
    }
  }
  return {
    data: cachedData
  };
}

3. 코드 동작 원리

이 코드는 MongoDB와 Redis를 사용하여 데이터를 캐시하고 관리하는 방법을 설명합니다. 각 주요 단계는 아래와 같습니다:

1) 캐시 조회

처음 요청이 들어오면 Redis에서 캐시된 데이터를 조회합니다. Redis에 데이터가 있다면, 이를 바로 반환합니다. 이를 통해 MongoDB에 불필요한 요청을 줄일 수 있습니다.

2) 캐시가 없으면 MongoDB에서 데이터 조회

만약 Redis에서 데이터가 없으면, MongoDB에서 데이터를 조회한 후 Redis에 캐시를 저장합니다. 캐시된 데이터는 1시간 동안 유지되며, 만료 시간이 지나면 Redis에서 자동으로 삭제됩니다.

3) Redis에 데이터 저장

MongoDB에서 데이터를 가져왔다면, 그 데이터를 Redis에 저장하고, 1시간 후에 만료되도록 설정합니다. 이 과정을 통해 데이터베이스 조회를 최소화하고 성능을 최적화합니다.

4. 캐시 만료 시간 설정

Redis의 setex 명령어는 데이터를 저장하면서 만료 시간을 설정합니다. 이 예시에서는 캐시된 데이터가 1시간 후에 자동으로 삭제되도록 설정하고 있습니다. 만약 데이터가 갱신될 필요가 있을 경우, 데이터가 새롭게 조회되면 해당 데이터를 다시 Redis에 저장합니다.

5. 성능 최적화

이 접근 방식의 주요 장점은 MongoDB와 같은 데이터베이스 시스템에 대한 부하를 줄이고, 빠른 데이터 조회가 가능하게 만든다는 것입니다. Redis 캐시는 메모리 기반으로 작동하므로, 데이터가 메모리에 저장되어 빠르게 조회할 수 있습니다.

캐시된 데이터가 만료되면, MongoDB에서 다시 데이터를 조회하여 새로운 데이터를 Redis에 저장하게 됩니다. 이를 통해 최신 데이터를 항상 제공하면서도 캐시를 사용해 성능을 최적화할 수 있습니다.

6. 결론

Redis와 MongoDB를 결합하여 캐시를 사용하면 성능을 크게 향상시킬 수 있습니다. 특히 데이터베이스 조회가 빈번한 경우, 캐시된 데이터를 활용하여 시스템 부하를 줄이고 더 빠르게 응답할 수 있습니다. 이 방법은 특히 웹 애플리케이션에서 데이터 처리 성능을 향상시키는 데 매우 유용합니다.

728x90
728x90

 

 

SvelteKit 애플리케이션에서 MongoDB를 사용하고, 그 데이터를 Redis로 캐시하여 성능을 최적화하는 방법을 소개합니다. 이 글에서는 Redis와 MongoDB를 통합하는 방법과 함께, 캐시를 적용하여 더 빠르고 효율적인 데이터를 제공하는 방법을 설명합니다.

1. 환경 설정

먼저, SvelteKit 애플리케이션에서 Redis와 MongoDB를 사용할 수 있도록 환경을 설정해야 합니다.

필요한 패키지 설치

먼저 Redis와 MongoDB를 사용하기 위한 패키지를 설치합니다. 터미널에서 아래 명령어를 실행하여 필요한 라이브러리를 설치합니다:

npm install redis mongodb ioredis

Redis 연결 설정

Redis 연결을 위한 설정을 `src/lib/redis.js` 파일에 작성합니다. 아래 코드처럼 Redis 연결을 설정하고 이를 다른 파일에서 사용할 수 있게 export합니다.

// src/lib/redis.js
import Redis from 'ioredis';

// Redis 연결 설정 (실제 환경에 맞게 수정해야 함)
const redis = new Redis({
  host: '192.168.1.10',   // Redis 서버 주소
  port: 6379,          // 기본 포트
  password: '',        // 패스워드 설정이 필요하다면
});

export default redis;

위 코드에서는 Redis 서버 주소, 포트, 비밀번호를 설정하고, `ioredis` 패키지를 사용해 Redis 클라이언트를 생성한 후 export합니다. 이렇게 설정된 Redis 클라이언트를 다른 파일에서 import하여 사용할 수 있습니다.

2. 캐시 구현

MongoDB에서 데이터를 가져오기 전에 Redis 캐시를 먼저 확인하여 데이터가 이미 캐시되어 있는지 확인합니다. 만약 캐시가 없다면 MongoDB에서 데이터를 조회한 후 Redis에 저장합니다.

캐시 조회 및 저장 로직

캐시 조회 및 저장을 위한 기본적인 로직을 작성합니다. Redis에서 데이터를 조회하고, 데이터가 없으면 MongoDB에서 가져와서 Redis에 저장합니다.

import redis from '$lib/redis';
import { MongoClient } from 'mongodb';

// MongoDB 연결 설정
const mongoClient = new MongoClient('mongodb://localhost:27017');
const db = mongoClient.db('your_database_name');
const collection = db.collection('your_collection_name'); 

// 예시: 상품 정보 조회
export async function load() {
  const productId = 987;
  const cacheKey = `product:${productId}`;  // 캐시 키 설정

  // Redis에서 데이터 조회
  let cachedData = await new Promise((resolve, reject) => {
    redis.get(cacheKey, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data ? JSON.parse(data) : null);
    });
  });

  // 캐시가 없으면 MongoDB에서 조회 후 Redis에 저장
  if (!cachedData) {
    console.log('캐시가 없어 MongoDB에서 조회');
    await mongoClient.connect();
    const data = await collection.findOne({ productId });

    // MongoDB에서 데이터를 가져왔다면 Redis에 캐시 저장
    if (data) {
      redis.setex(cacheKey, 3600, JSON.stringify(data)); // 1시간 동안 캐시
      cachedData = data;
    }
  }

  return {
    props: { data: cachedData },
  };
}

코드 설명

  • 캐시 조회: `redis.get(cacheKey)`를 통해 Redis에서 캐시된 데이터를 가져옵니다.
  • 캐시가 없을 경우: 캐시된 데이터가 없으면, MongoDB에서 데이터를 조회하여 Redis에 캐시하고 반환합니다.
  • 캐시 저장: `redis.setex(cacheKey, 3600, JSON.stringify(data))`를 사용하여 1시간 동안 데이터를 Redis에 저장합니다.

3. 캐시 만료 및 관리

Redis에서 저장한 데이터는 일정 시간이 지나면 만료됩니다. 이를 통해 데이터를 최신 상태로 유지할 수 있습니다. Redis는 기본적으로 **만료 시간**을 설정할 수 있으며, 이를 통해 데이터가 일정 시간 후에 자동으로 삭제되도록 할 수 있습니다.

캐시 만료 시간 설정

위 코드에서 `setex`를 사용하여 만료 시간을 설정했습니다. 만약 더 세밀한 만료 시간 설정이나 캐시 정책을 관리하고 싶다면 Redis의 `maxmemory-policy` 등을 활용할 수 있습니다.

캐시 갱신

만약 데이터가 변경되면 캐시도 갱신해야 합니다. 예를 들어, 상품 정보를 업데이트할 때마다 Redis의 해당 캐시를 삭제하고 새로운 데이터를 캐시할 수 있습니다. Redis에서 데이터를 삭제하는 방법은 `del` 명령어를 사용합니다.

redis.del(cacheKey); // 캐시 삭제
  redis.setex(cacheKey, 3600, JSON.stringify(updatedData)); // 갱신된 데이터 캐시 저장

4. Redis와 MongoDB의 장점

  • 성능 향상: Redis는 메모리 기반 캐시 시스템으로 매우 빠르기 때문에, MongoDB와 같은 데이터베이스의 부담을 줄여줍니다.
  • 데이터베이스 부하 감소: 캐시된 데이터를 Redis에서 빠르게 읽을 수 있기 때문에, MongoDB나 다른 데이터베이스에 대한 부하를 줄일 수 있습니다.
  • 데이터 최신화 관리: Redis는 캐시 만료 시간 설정을 통해 일정 주기로 데이터를 최신 상태로 유지할 수 있습니다.

5. 결론

이번 글에서는 SvelteKit과 MongoDB를 연동하여 Redis 캐시를 사용하여 성능을 최적화하는 방법에 대해 설명했습니다. 캐시를 잘 활용하면 데이터를 빠르게 조회하고, 데이터베이스의 부하를 줄일 수 있습니다. Redis와 MongoDB의 연동을 통해 더 나은 성능을 제공하는 애플리케이션을 만들 수 있습니다.

728x90
728x90

 

1. SvelteKit에서 데이터 전달 흐름

SvelteKit에서 서버 측에서 데이터를 클라이언트로 전달하는 방식은 매우 직관적입니다. 서버에서 클라이언트로 전달되는 데이터는 자동으로 data 객체로 포함되어 전달됩니다.

즉, 서버에서 값을 반환할 때 data 객체로 감싸서 전달할 필요가 없고, 반환된 데이터는 클라이언트에서 data 객체 안에서 꺼내어 사용할 수 있습니다.

2. 서버에서 데이터 전달하기

서버 측에서는 load 함수 안에서 클라이언트로 전달할 데이터를 반환할 수 있습니다. 이때 데이터를 반환할 때는 별도로 data 객체를 감싸지 않아도 자동으로 data 객체로 전달됩니다.

예시: +page.server.ts

          // +page.server.ts
          export async function load({ params }) {
            const { cate } = params;  // URL 파라미터에서 cate 값 추출
            console.log('Server-side Params:', cate); // 서버에서 cate 값 출력
            
            return cate;  // 값만 리턴하면 자동으로 `data.cate`로 클라이언트에 전달됨
          }

3. 클라이언트에서 데이터 사용하기

클라이언트 측에서는 서버에서 전달된 데이터를 data 객체에서 추출하여 사용합니다. data 객체는 자동으로 클라이언트로 전달되므로, 해당 값에 접근할 때는 data에서 꺼내서 사용하면 됩니다.

예시: +page.svelte


          <!-- +page.svelte -->
          <script>
            export let data;  // `data` 객체로 자동으로 전달된 값
            console.log('Client-side Data:', data);  // 클라이언트에서 `data` 확인
            
            const cate = data?.cate;  // `data` 객체에서 `cate` 추출
          </script>

          <h1>Selected Category: {cate}</h1>
        

위 코드에서, data.cate는 서버에서 전달된 카테고리 값이 됩니다. 클라이언트에서는 이를 사용하여 페이지에 출력할 수 있습니다.

4. 주의 사항

SvelteKit에서는 데이터를 서버에서 클라이언트로 전달할 때 자동으로 data 객체에 포함되어 전달됩니다. 따라서 data 객체 안에서 데이터를 추출하여 사용해야 하며, 중복된 방식으로 접근하지 않도록 주의해야 합니다.

이 글은 SvelteKit에서 서버와 클라이언트 간 데이터 전달 방식을 간단히 정리한 포스팅입니다. SvelteKit을 사용한 프로젝트에서 데이터 전달과 관련된 문제를 해결하는 데 도움이 되기를 바랍니다.

728x90

+ Recent posts