프레임워크 있는 프론트 개발 #3 todo on any framework - Svelte 편

봉승우·2023년 3월 30일
1
post-thumbnail

vue-todo에 이은 3번째 투두 만들기 프로젝트입니다.

해당 포스팅도 vueJS와 동일한 목차로 정리해보고자 합니다.
1. Svelt의 특징을 알아봅니다.
2. Svelt의 기초적인 활용법을 알아봅니다.
3. Svelt를 활용하여 TODO 앱을 제작해봅니다.
4. 타 프레임워크와 차이점을 비교해봅니다.

📌 Svelt의 특징

Svelt는 약 1~2년 전부터 주목을 받았던 프레임워크 컴파일러입니다.
공식 홈페이지

Svelte 특징

주요 특징

  • React와 Vue.js와 같은 선언적인 프레임워크와는 달리,
    HTML, CSS, JavaScript를 합쳐 런타임에 필요한 코드만 생성하여 작동.

  • 작은 번들 사이즈를 제공하고, 이에따라 초기 렌더링 속도를 비롯한 애니메이션 및 인터랙션 처리가 용이함.

  • Svelte는 React 및 Vue.js와 비교하여 문법이 단순
    (React처럼 JSX 문법 등을 익히지 않아도 됩니다.)

  • 런타임 중 생성되는 가상 DOM을 사용하지 않으면서도 렌더링 성능을 향상시킴

빠름

  • 런타임이 아닌 빌드 타임에 애플리케이션 코드를 해석함.
  • 타 프레임워크는 자체 코드도 클라이언트로 내려야 함.
    하지만, 스벨트는 필요한 순수 자바스크립트만 내림.

가상 돔 X

  • 가상 돔은 변경된 돔을 메모리에 유지하고 이를 실제 돔과 비교하는 것
  • 리액트는 변경사항만을 반영하는 diffing 과정이 있었지만, 리액트는 skip

반응형

  • 리액트는 선언적 언어이며, 100% 반응형이라고 볼 수는 없음.
    변경된 값을 DOM에 반영하기 위해서는 Hook을 사용해야 함.
  • 스벨트는 컴포넌트 안계가 변경되면 DOM 업데이트 진행.
    단, 전에 발생한 변경 사항을 기억하고, 업데이트 명령을 받았을 때 그 변경을 한번에 반영
  • 또한 반응형 선언문과 변수로 인해, 로직과 반응형 변수를 사용할 수 있음.

상태관리

  • 컨택스트 API: React의 Context API와 비슷
  • 스벨트 스토어: 단일 데이터 소스를 추적하고 변경사항을 감지하는데 사용
  • Writable Store: 스토어와 유사, 일부 컴포넌트만 상태값을 변경가능
  • Readable Store: 읽기 전용 상태값을 저장, 스토어에서 상태값을 읽기만 가능

단점

  • 아직 React와 Vue.js와 같은 높은 수준의 커뮤니티가 없음.
  • 일부 프레임워크에서 제공하는 기능과 라이브러리를 지원하지 않음.

📌 Svelte/kit 기초

Svelte 프로젝트는 주로 다양한 기능을 제공하는 Svelte/kit를 활용하여 진행됩니다.

Svelte/kit가 제공하는 추가적인 기능은 다음과 같습니다.

  • SSR, SSG 등 지원
  • 다양한 배포 옵션

라우팅

+page.svelte

  • 초기 요청을 위한 SSR과 이후 네비게이션을 위한 CSR 지원

+page.js

  • js, ts 파일 -> 렌더링 되기 전에 로드해야하는 데이터를 fetching
  • +page.svelte와 함께 SSR 혹은 CSR에서 실행.

+page.server.js

  • 데이터베이스등의 접속이 필요하여 서버에서만 작동해야만 할 때.

+error.svelte

  • 가장 가까운 에러바운더리로 올라감.

+layout.svelte

  • 일반적으로 네비게이트시에, 스벨트는 파일 하나를 컴포넌트 하나로 다룸.
  • 페이지 이동 시 기존의 스벨트 페이지가 완전히 사라지고 새로 대체 됨.
  • 푸터나 헤더같은 녀석을 유지할 수 있음.

+layout.js, +layout.server.js

  • +page.svelte+page.js 관계와 유사.

데이터 로딩

  • +page.js에서 +page.svelte가 필요한 데이터를 로드할 수 있음.
// +page.js
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
  return {
    post: {
      title: `Title for ${params.slug} goes here`,
      content: `Content for ${params.slug} goes here`
    }
  };
}

// +page.svelte
<script>
  /** @type {import('./$types').PageData} */
  export let data;
</script>

<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>

렌더링

  • svelte/kit는 서버에서 렌더링(pre렌더링)하고 클라이언트에 HTML 형태로 내림
  • 내려받은 컴포는트를 인터렉티브 하게 브라우저가 변경함 (하이드레이션)
  • 그래서 컴포넌트가 서버, 클라이언트 둘 다에서 작동해야 함.
  • 페이지마다 해당 세팅을 설정할 수 있음.

prerender

  • 빌드 시에 HTML 파일 형태로 생성될 수 있는 페이지들.
  • js, ts에서 export const prerender = true;

ssr

  • SvelteKit는 하이드레이트된 클라이언트에 렌더링이 된 HTML을 보낼 수 있음.
  • js, ts 에서 export const ssr = false;

csr

  • 보통, SvelteKit는 server-rendered HTML을 interactive client-side-rendered (CSR) page으로 하이드레이트 함.
  • 몇몇 페이지는 JS를 전혀 필요로 하지 않기도 하는데, 이 경우 CSR 옵션을 꺼버려도 돼
    export const csr = false;

Props

  • 기본적인 값 전달 방법
<script>
import Item from './item.svelte'
</script>

<Item carryValue = { 12 } >
<Item {carryValue} >
  
<script>
	export let id
</script>

<p> { id } </p>
  • 함수 전달
// App.svelte
<script>
import Item from './components/item.svelte'

function alertSum(x, y) {
	alert(x + y)
}

</script>

<Item {alertSum} />

// child.svelte
<script>
	export let alertSum
</script>

<button on:click={(_) => alertSum(5,10)} >alert</button>

스벨트 스토어(Svelte Store)

  • Writable, Readable, derived 등의 함수로 생성될 수 있음.

Writable Store

<script>
  import { writable } from 'svelte/store';

  const name = writable('John');

  function changeName() {
    name.set('Jane');
  }
</script>

<button on:click={changeName}>Change Name to Jane</button>

Readable Store

<script>
  import { readable } from 'svelte/store';

  const users = readable([
    { name: 'John', age: 30 },
    { name: 'Jane', age: 25 }
  ]);
</script>

{#each $users as user}
  <p>{user.name} ({user.age})</p>
{/each}

Context

참고링크

// 값을 기록하는 부분
<script>
import {setContext} from 'svelte'

const setValues = {
	a: 1,
	b: 2
}

setContext('setKey', setValue)
...


// 값을 받아쓰는 부분
<script>
import { getContext } from 'svelte'

const getValue = getContext('setKey')

</script>

a: { getValue.a }
b: { getValue.b } 

📌 Svelte Todo

  • 완성된 Svelte Todo
    완성본

Store 세팅

  • 투두 타입 및 스벨트 스토어 활용
src/store/index.ts
import { writable } from 'svelte/store';

export interface TodoType {
	id: number;
	text: string;
	completed: boolean;
}

// 스토어 생성 관련
// 구독 관련 작업도 다 해줌
export const todoData = writable<TodoType[]>([]);

route 세팅

  • 단일 페이지이기에 파일은 하나
// src/routes/+page.svelte
<script>
	import TodoInput from "../component/TodoInput.svelte";
	import TodoList from "../component/TodoList.svelte";
	import Total from "../component/Total.svelte";

</script>

<section>
  <header>TODO</header>
  <TodoInput />
  <TodoList />
  <Total />
</section>

Store 값 활용

  • $: Reactive Declaration 문법 활용
  • $를 사용하지 않으면, 일반적인 자바스크립트 표현식으로 값 변화 반영 X
<script lang="ts">
  import {todoData} from "../store"
  import Barcode from "./Barcode.svelte";
  $: completedTodo = $todoData.filter(todo => todo.completed).length;
  $: ratio = $todoData.length > 0 ? Number(completedTodo/$todoData.length*100).toFixed(2) : 0;
</script>

each 블록

<div>
  {#each $todoData as todo (todo.id)}
    <TodoItem {todo} />
  {/each}
</div>
  • $todoData는 writable store.
  • (todo.id)는 Svelte의 keyed each 블록 구문 (React JSX의 Key)

bind

  • state값과 form 값이 서로 유기적으로 반영
  <label>
    <input type="checkbox" bind:checked={completed} on:click={(e) => handleCompleteTodo(id)}/>
    {text}
  </label>

전체코드: 깃허브링크

📌 타 프레임워크와의 차이 및 DX

간편, 쉬움, 빠름

리액트에서 가장 학습이 많이 필요한 곳인 전역상태 관리가
스벨트에서는 학습할 것(?)이 없습니다.

그냥 Svelte Store와 Context만 활용하면 뚝딱입니다.
리덕스의 복잡한 보일플레이트도 신경쓸 필요가 없습니다.

앵귤려, 뷰에서 언급했던 폼 관리도 매우 쉽습니다.
bind를 활용하여 폼을 매우 쉽게 관리할 수 있습니다.
폼에 붙는 이벤트도 on: 을 활용하면 다양한 처리가 가능합니다.

그리고 요즘에는 어쩌면 필수라고 여겨지는 SSR 관련 지원까지
Svelte(Kit)가 많은 부분을 제공해주고 있습니다.

또한 성능에 관해서는 단순히 투두앱을 만들어 보았기 때문에,
획기적인 성능 개선을 경험해 봤다라고는 못하지만,
적어도 사라지는 프레임워크로 작용하며,
굉장히 적은 번들사이즈를 제공해준 것은 분명합니다.

새로운 프론트엔드 프레임워크를 접할 수록 항상 더 나은 경험을 하고 있는데,
아마도 간결함에 있어서는 최고이지 않을까 싶습니다.

그럼에도 불구하고, 스벨트가 여전히 높은 시장 점유율을 가지지 못하는 것은,
타 프레임워크에 비해 작은 커뮤니티,
아직 보장되지 않은 배포 환경에서의 안정성(?),
FE시장의 리액트 고인물...
정도가 있을 거 같습니다.

스벨트 만세...? 🥹

📌 참고자료들

스벨트 VS 리액트, 누가 더 뛰어날까
만들면서 배우는 스벨트

profile
안녕하세요🙂

0개의 댓글