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

1.
여느 때처럼 인터넷 돌아다니다가 KiCAD를 MCP를 이용해서 쓴다는 유튜브 영상을 보게됐다.

2.
'드디어 올게 왔는가...' 하고 봤더니 풋프린트랑 심볼 대신 그려주는거였다.(실망)

3.
그런데 그 와중에 날 깜짝 놀래킨 게 있다.
이걸 "카이캐드"라고 발음하는 거였다.

4.
'읭? key랑 같은 발음으로 키캐드로 읽는걸 권한다고 어디서 봤는데 여태 내가 잘못알았던건가?!'
아니 그럴 리는 없는게 몇년전에 해외 유튜버 강의를 봤을 때 대충 화면보고 때려맞추긴 했지만 '카이캐드'라고 발음하는 건 들은 적이 없다.

5.
그럼 대체 저 발음의 근원은 뭘까...
뭐 어차피 알파벳은 발음이 정해진 문자가 아니니 그러려니 해야겠지만 왜 국내에서만 발음이 저런 식으로 변형되었는지 궁금하긴 하다.

6.
검색해보니 '키캐드'가 권장 발음이 맞다.
어쩌다가 '카이캐드'가 됐는지는 대충 예상이 되는데 그냥 짜증만 유발할 듯 하니 그러려니 하고 말아야겠다.

728x90

'궁시렁' 카테고리의 다른 글

Go Lang  (0) 2025.06.01
2025 관광데이터 활용 공모전?  (0) 2025.04.27
블록체인  (0) 2025.02.25
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

1.
Go를 몇 년만에 다시 꺼내서 공부하고 있다.
백엔드 구성을 좀 체계적으로 해야겠다는 필요성을 느껴서 찾다보니 Fiber를 써야 할 것 같았기 때문이다.

2.
그런데 Go도 제대로 안써보다가 갑자기 Fiber부터 쓰면 모든게 낯설어서 다시 파이썬 쪽으로 갈 것 같아서 일단 Go기본부터 써먹어 보기로 했다.
그래서 깔짝거린게 크롤링과 ORM.

3.
써보고 나서 바로 든 생각이 '이건 파이썬 대용품이다' 였다.
진짜 속도차이를 바로 느낄수가 있다니...
테스트로 해본 크롤링에서 같은 내용, 같은 사이트에서의 크롤링 속도가 파이썬보다 거의 4~5배는 빨랐다.
사실 파이썬도 제대로 아는건 아니라 내가 뭔가 잘못 설정하거나 코드를 잘못짜서 그럴수도 있겠지만 일단 html뽑아내는거부터 정말 깔끔하다.
그간 브라우저로 볼때 html하고 크롤링해온 html하고 구조가 달라지는 경우가 많았는데 이건 매우 직관적으로 내가 생각했던 구조를 그대로 뽑아준다.
거기다 에러도 어디서 뭐가 잘못됐는지 명확하게 알려준다.

4.
그만큼 밑바닥부터 하려면 정확한 코드를 짜야하기에 어려울수 있지만 우리에겐 수많은 LLM들이 있다.
이러한 상황에서 '명확한 에러'는 명확한 해답을 찾는데 매우 강력한 길잡이가 된다.


5.
ORM은 예전에 한 번 써보고 '이게 편하자고 만든 도구가 맞나' 싶을 정도로 설정도 거지같고 마이그레이션도 애매해서 그냥 직접 쿼리문 날려서 사용했었다.
다시 생각해보면 그때는 처음 배우는 시기기도 했고, ORM 이외의 다른 것들도 복합적으로 구성을 했기 때문에 굉장히(=쓸데없이) 복잡해졌었던 것 같다.
여튼 머리 속에 남은 ORM에 대한 기억은 '아주 가끔 쓸데있으며 비효율적인 무언가'였다.
동시에 내가 생각한 ORM의 필요성 및 개념과 현실은 다르구나 하고 느꼈었다.

6.
지금은 내가 직접 프로젝트를 구성하고 코드를 짜고 하다보니 매우 직관적이고 가급적 단순화시킨 구조로 만들고 있다.
그래서 그럴지 모르겠으나 이번에 Go ORM인 GORM을 써 본 느낌은, 내가 생각했던 ORM 시스템 그 자체였다.
그간 노가다 열심히 뛰었는데 갑자기 너무 딸깍으로 되는 느낌이라 살짝 어안이 벙벙하기도 하다.

7.
요며칠 스트레스성 폭면으로 몸은 과하게 잘 쉬었으니 이제 Go로 좀 달려봐야겠다.

728x90

'궁시렁' 카테고리의 다른 글

KiCAD 이야기  (2) 2025.06.07
2025 관광데이터 활용 공모전?  (0) 2025.04.27
블록체인  (0) 2025.02.25
728x90

1.
웹코딩을 배울 때 잠깐 사용해 봤던 TourAPI라는 게 있었다.
한국관광공사(무려 공사)에서 제공하는 국내 관광에 관한 데이터들을 제공해주는 API인데 이걸로 뭘 좀 해보려다가 데이터 정리도 제대로 안된 느낌이고 각잡고 쓰기엔 데이터가 너무 부실한지라 그냥 신경껐던 기억이 있다.
근데 그게 카카오랑 공모전을 이미 몇 년전부터 해왔던 걸 알게됐다.
사실 올해 하는걸 보고 검색을 해보다가 가장 '읭?'스러운 부분을 알게됐는데, 수상작에 대한 데이터가 거의 없다는 거다.
대충 찾아보니 이것도 예산 끌어다가 쓰긴 하는데 말그대로 그냥 소모성으로 하는거 아닌가 의심스러울 정도로 결과에 대한 공표나 정확한 정보공개가 안되어 있다.
2024년도 수상작에 대한 어떠한 정보도 웹에서 찾을수 없다.


2.
그리고 언급했듯 데이터 자체가 총체적으로 부실해서 이걸로 뭘 써먹을수가 없다는 게 가장 큰 문제였다.
어차피 돈들여서 하는 걸텐데 왜 데이터가 이딴 식일까.
데이터 자체가 부실하면 통일성이이라도 있어야지 정말 엉망이다.
예로 상세데이터에 있는 홈페이지 데이터도 어떤 데는 그냥 홈페이지 링크만 있고 어디는 <a>태그로 html태그로 들어가 있다.
음식점 데이터를 지역 리스트로 찾으면 전화번호 없는게 있는 것보다 더 많고 가끔 음식점의 상세 정보로 들어가면 또 있는 경우도 있다.
애초에 지역 리스트에 나오는 정보랑 상세 정보에 나오는 정보를 중복으로 표기하면서 이미 쓸데없는 API호출 낭비가 발생한다.
속도 느려지는 건 당연한 거고 서버 부하만 가중된다.

3.
제일 어이가 없는 부분은 카카오맵 API랑 같이 쓰라는데 그냥 카카오맵 API쓰면 다 된다.
두 API의 교집합만 뽑아내면 그게 TourAPI다.
여러번 언급하지만 심지어 TourAPI의 정보는 매우 부실하고 부정확하다.
이 상황에 TourAPI를 반드시 활용하라는 전제가 매우 어처구니가 없다.
예로 같은 음식점을 TourAPI에서 찾으면 데이터가 한 방에 안오고 어느 동네에 있는지 찾아서 리스트를 뽑고 그 리스트에서 음식점 고유 코드를 찾아서 그 고유 코드로 상세 데이터 검색 API로 요청을 하면 음식점의 데이터가 온다.
그냥 카카오맵 API에서 동네에 가게 이름으로 검색하면 한 방에 그 음식점 데이터가 나온다.
주문하기랑 후기도 다 나온다.
이 모양인데 TourAPI를 왜 써야 하나?
얼기설기 누벼놨지만 어떻게 해서든 활용방안을 찾아내서 이미 개판된 데이터에 산소호흡기 좀 붙여줘~ 하는 것 같다.
솔직히 그럴 예산으로 그냥 있던 DB나 정리하고 데이터 새로 업데이트 하는데 쓰는게 맞을거다.

728x90

'궁시렁' 카테고리의 다른 글

KiCAD 이야기  (2) 2025.06.07
Go Lang  (0) 2025.06.01
블록체인  (0) 2025.02.25

+ Recent posts