Svelte 소개 및 설치하기

새로운 자바스크립트 프레임워크

Svelte란?

Svelte는 사용자 인터페이스를 구축하기 위한 자바스크립트 기반의 새로운 프레임워크라고 할 수 있습니다. 물론 Vue.js, React.js와 같이 이미 알려지고 사랑받는 자바스크립트 프레임워크 혹은 라이브러리들이 있지만, Svelte는 이들과는 또 다른 매력이 있는 프레임워크입니다.

Svelte의 가장 큰 매력은 작업의 전환 방식인데, Vue와 React의 경우에는 브라우저에서 대부분의 작업을 수행하는 반면, Svelte는 다른 프레임워크와는 달리 앱을 빌드하는 컴파일 단계에서 작업으로 전환하는 방식으로 동작을 한다는 것이 가장 큰 차이라고 할 수 있습니다.

Svelte는 앱의 상태가 변경될 때 DOM을 외부에서 변경하여 업데이트하는 방식으로 코드가 구현된다고 합니다. 즉 Vue, React에서 사용하는 가상 DOM 비교 알고리즘 같은 기술과는 다른 방식이라고 할 수 있는데, Svelte는 사용법이 쉽고 가벼우면서도 빠른 속도로 개발할 수 있다는 장점 덕분에 최근 개발자들이 가장 선호하는 웹 프레임워크로 뽑히기도 했습니다. 웹 페이지에서 소개하고 있는 Svelte의 특징과 장점은 다음과 같습니다.

Write less code
Svelte는 보일러플레이트 코드 없이 HTML, CSS, JavaScript와 같이 이미 익숙한 언어를 사용하여 더 적은 코드로 빌드할 수 있다.
No virtual DOM
Svelte는 코드를 프레임워크 없이 작은 바닐라 JS로 컴파일하여, 앱이 빠르게 시작되고 빠르게 유지된다.
Truly reactive
Svelte는 JavaScript 자체에 반응성을 제공하기 때문에 복잡한 상태 관리 라이브러리가 필요없다.

Svelt의 특징

Svelte는 Rich Harris가 제작한 새로운 접근 방식의 프론트엔드 프레임워크로 빠른 웹 애플리케이션을 구축하기 위한 도구라고 할 수 있습니다. React와 Vue와 같은 자바스크립트 프레임워크와 비슷하지만, Svelte는 런타임에서 애플리케이션의 코드를 해석하지 않고 빌드 시에 코드를 자바스크립트로 변환하는 방식입니다.

Svelte는 가상 DOM을 사용하지 않기 때문에 프레임워크 추상화에 사용되는 성능의 저하를 막을 수 있다는 장점이 있는데, Svelte는 기본적으로 빌드 단계에서 컴포넌트를 컴파일하기 때문에 페이지에 단일 번들을 로드해 앱을 렌더링할 수 있습니다.

Svelte도 Vue, React와 마찬가지로 전체 앱을 빌드하거나 기존의 코드베이스에 점진적으로 추가할 수 있기 때문에, 앱이 처음 로드될 때도 프레임워크 추상화에 따른 패널티가 발생하지 않고, Svelte로 작성된 앱의 컴포넌트를 기존의 프레임워크에 대한 종속성 오버헤드 현상의 염려없이 어디서나 작동하는 독립형 패키지로 제공할 수 있다고 합니다.

간결한 코드

Svelte는 높은 가독성을 유지하면서 더 적은 코드를 작성할 수 있습니다.

Svelte로 작성한 코드
<script>
  let a = 1;
  let b = 2;
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>

<p>{a} + {b} = {a + b}</p>

대표적인 프론트엔드 프레임워크인 React와 Vue에서 앞의 코드와 동일한 코드를 작성한 것과 비교해보면, Svelte의 코드가 얼마나 간결한지 확실하게 느낄 수 있습니다.

React로 작성한 코드
import React, { useState } from 'react';

export default () => {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);

  function handleChangeA(event) {
    setA(+event.target.value);
  }

  function handleChangeB(event) {
    setB(+event.target.value);
  }

  return (
    <div>
      <input type="number" value={a} onChange={handleChangeA}/>
      <input type="number" value={b} onChange={handleChangeB}/>
      <p>{a} + {b} = {a + b}</p>
    </div>
  );
};
Vue로 작성한 코드
<template>
  <div>
    <input type="number" v-model.number="a">
    <input type="number" v-model.number="b">

    <p>{{a}} + {{b}} = {{a + b}}</p>
  </div>
</template>

<script>
  export default {
    data: function() {
      return {
        a: 1,
        b: 2
      };
    }
  };
</script>

불필요한 가상 DOM

사실 Vue나 React에서 사용하는 가상 DOM은 충분히 빠르고 유용하지만 이는 기능이 아닌 수단에 불과하기 때문에, Svelte는 가상 DOM을 사용하지 않는다고 합니다. 가상 DOM 방식은 새로운 가상 DOM을 이전의 스냅샷과 비교하거나, 상태 변화에 따른 새로운 가상 요소 생성 등에 많은 오버헤드가 발생할 수 있고, 최종적으로는 실제의 DOM을 업데이트하는 방식으로 이루어지기 때문에 이런 불필요한 과정을 생략하는 것이 더욱 빠를 수 있다는 것이죠.

기존의 UI 프레임워크와는 달리 Svelte는 가상 DOM을 사용하지 않고도 유사한 프로그래밍 모델을 얻을 수 있는데, 이것이 가능한 이유는 런타임에서 작업을 기다리는 방식이 아닌, 빌드 과정을 통해 앱에서 어떤 변경 사항이 발생하는지 확인하는 컴파일러 방식이기 때문입니다.

반응성

반응성은 변경된 값이 DOM에 자동으로 반영되는 것을 되는 것을 뜻하는데, Svelte는 별도의 Setter없이 값의 할당만으로도 업데이트를 실행할 수 있습니다.

app.svelte
<script>
  let count = 0;
</script>

<button on:click={() => count += 1}>
  {count}
</button>
자바스크립트로 변환된 결과
function instance($$self, $$props, $$invalidate) {
  let count = 0;
  const click_handler = () => $$invalidate(0, count += 1);
  return [count, click_handler];
}

위 코드는 컴파일 결과가 할당을 계측하고 DOM을 갱신하는데, 이는 다음과 같이 store 사용 방식에도 굉장한 이점을 부여해 줍니다. countwritable()에서 반환된 쓰기용 객체 데이터이기 때문에, $count와 같이 접두사 $를 사용해 store를 참조하겠다는 의미로 사용할 수 있습니다.

store.js
import { writable } from 'svelte/store';
export const count = writable(0); // similar to `count = 0`
app.svelte
<script>
  import { count } from './store.js';
</script>

<button on:click={() => $count += 1}>
  {$count}
</button>

Svelte 기본 문법

데이터 추가하기

Svelte를 이해하려면 HTML, CSS, JavaScript에 대한 기본적인 지식이 필요한데, Svelte에서 애플리케이션은 하나 이상의 컴포넌트로 구성되어 있습니다. 여기서 컴포넌트란 .svelte 파일로 작성되어 HTML, CSS, JavaScript를 캡슐화한 재사용 가능한 코드 블록을 말하는데, 다음과 같이 일반적인 HTML로 구성될 수 있습니다.

app.svelte
<h1>Hello world!</h1>

하지만 단순히 정적인 마크업을 렌더링하는 경우라면 Svelte를 사용할 필요가 없겠죠? 다음과 같이 컴포넌트에 스크립트 태그를 추가하고 name이라는 변수를 선언하면 HTML의 마크업에서 name을 참조할 수 있습니다.

app.svelte
<script>
  let name = 'world';
</script>

<h1>Hello {name}!</h1>

Svelte는 변수를 참조할 때 중괄호{}를 사용하는데, 중괄호안에서는 다음과 같이 자바스크립트를 직접 사용할 수도 있습니다.

app.svelte
<script>
  let name = 'world';
</script>

<h1>Hello {name.toUpperCase()}!</h1>

동적 속성 추가하기

Svelte는 중괄호로 데이터를 연결하는 것처럼 DOM 엘리먼트의 속성도 제어할 수 있는데, 다음과 같이 중괄호를 사용하면 img 엘리먼트의 src 속성을 바인딩하는 작업도 간단하게 할 수 있습니다.

속성 바인딩
App.svelte
<script>
  let src = 'image.jpg';
</script>

<img src={src}>

img 요소의 경우에는 꼭 함께 추가해줘야 하는 속성이 있는데, 바로 alt 속성입니다. 만약 이 속성을 추가하지 않고 컴파일을 하게 되면 Svelte는 다음과 같은 경고를 보여줍니다.

A11y: <img> element should have an alt attribute

alt와 같은 속성을 웹 접근성 코딩을 위해 반드시 필요한 속성인데, Svelte는 이렇게 웹 접근성에 맞지 않는 마크업으로 코드를 작성하는 경우에 경고를 보여주기 때문에 웹 접근성에 따르는 코딩을 하는데에 도움이 되고, alt 속성 역시 중괄호를 사용하여 동적으로 데이터를 바인딩할 수 있습니다.

alt 속성 바인딩
App.svelte
<script>
  let src = 'image.jpg';
  let alt = 'imgge description';
</script>

<img src={src} alt={alt}>
속성 단축 문법

src={src} 처럼 속성의 이름과 바인딩하는 변수의 이름이 같은 경우에는 다음과 같이 간단하고 편리한 방식으로 단축된 코드로 작성할 수 있습니다.

속성 단축 문법
<img {src} {alt}>

스타일 추가하기

Svelte는 HTML과 마찬가지로 컴포넌트에 <style> 태그를 추가할 수 있는데, 하나의 컴포넌트의 내부에서 적용된 <style>은 앱의 다른 컴포넌트에 같은 선택자를 가진 엘리먼트가 존재해도 해당 엘리먼트에는 CSS가 적용되지 않습니다.

스타일 추가
App.svelte
<p>This is a paragraph.</p>

<style>
  p {
    color: purple;
    font-family: 'Comic Sans MS', cursive;
    font-size: 2em;
  }
</style>
Nested Components

일반적으로 앱을 개발하는 과정에서 모든 컴포넌트를 하나의 단일 컴포넌트에 집어넣는 것은 매우 비효율적인 작업이 될 수 밖에 없습니다. 그래서 많은 자바스크립트 프레임워크에서는 컴포넌트화라는 추상적인 개념을 도입해서 다른 파일에서 컴포넌트를 가져오는 방식을 사용합니다.

Svelte도 각각의 컴포넌트를 컴포넌트화 할 수 있는데, .svelte 파일은 하나의 파일 안에 정의되어 있는 HTML, CSS, 자바스크립트를 캡슐화하기 때문에, 다른 파일에서 불러온 컴포넌트에는 CSS와 같이 부모 컴포넌트에 적용된 정의가 동일하게 적용되지는 않습니다.

App.svelte
<p>This is a paragraph.</p>
<Nested/>

<style>
  p {
    color: purple;
    font-family: 'Comic Sans MS', cursive;
    font-size: 2em;
  }
</style>

<script>
  import Nested from './Nested.svelte'; // 컴포넌트 불러오기
</script>
Nested.svelte
<p>This is another paragraph.</p>

HTML 렌더링

일반적으로 HTML 마크업은 일반 텍스트의 형태로 삽입되는데, HTML로 화면을 구성하다보면 HTML 컴포넌트를 직접 렌더링해야 하는 경우가 생기기도 합니다. 그래서 Svelte는 HTML의 내부에 직접 HTML 요소를 렌더링하는 경우를 위한 태그를 제공하고 있는데, 다음과 같이 @html의 뒤에 렌더링 할 HTML 태그를 넣어주면 됩니다.

HTML 렌더링 코드
App.svelte
<script>
  let string = `this string contains some <strong>HTML!!!</strong>`;
</script>

<p>{string}</p>

Svelte는 DOM에 삽입되기 전에 {@html …} 내부의 표현식을 삭제하지 않는데, 이 기능을 사용하는 경우에는 신뢰할 수 없는 소스에서 HTML을 가져온 경우라면 사용자가 XSS 피싱 공격에 노출될 위험이 있기 때문에, HTML을 수동으로 적용하는 것이 좋습니다.

빌드 통합

Svelte는 빌드 도구와 통합하여 사용해야 하는데, 많은 빌드 도구에서 Svelte와 통합할 수 있는 플러그인을 지원하고 있습니다. 다음의 플러그인들은 Vite, Rollup, webpack에서 공식적으로 유지 관리되는 대표적인 플러그인들입니다.

최근에는 Svelte와 함께 Snowpack이라는 빌드 시스템도 선호되고 있는데, 해당 빌드 시스템에서도 Svelte와 통합된 공식 템플릿을 제공해주고 있습니다.

Snowpack과 Snowpack Svelte 템플릿 설치에 대해 자세히 알고 싶다면 ‘Snowpack, 더 빠른 웹개발을 위한 빌드 시스템‘ 포스트를 참고해 보세요.

Svelte 공식 템플릿 설치하기
npx create-snowpack-app {new-dir} --template @snowpack/app-template-svelte

프로젝트 설정이 완료되면 Svelte 컴포넌트를 쉽게 사용할 수 있는데, 컴파일러는 .svelte로 구성된 각각의 요소를 일반 자바스크립트 클래스로 변환하여 앱에 적용하게 됩니다.

index.js
import App from './App.svelte';

const app = new App({
  target: document.body,
  props: {
    // we'll learn about props later
    answer: 42
  }
});

답글 남기기