본문 바로가기
SPA

Rust로 SPA 만들기 - 1. 리스트 만들기

by F.E.D 2021. 7. 3.

아래의 예제는 출처에 포함된 내용을 번역 한 것입니다.

 

WebAssembly(wasm)를 사용하면 JavaScript 이외의 언어로 작성된 코드를 브라우저에서 실행할 수 있습니다.

주요 브라우저들은 wasm을 지원하고 전 세계적으로 90% 이상의 사용자가 wasm을 실행할 수있는 브라우저를 사용하고 있습니다.

Rust를 사용하면 WebAssembly로 컴파일 되기 때문에 순수하게 Rust로 SPA를 빌드할 수 있고 자바스크립트를 한줄도 사용하지 않고도 만들 수 있습니다.

 

https://rustmart-yew.netlify.app/

 

RustMart

 

rustmart-yew.netlify.app

위의 데모 사이트를 한번 방문해보세요

 

설치

https://www.rust-lang.org/tools/install

 

Install Rust

A language empowering everyone to build reliable and efficient software.

www.rust-lang.org

위의 사이트에서 설치해보세요.

설치하시고 나서 해당 패키지들을 설치해보세요.

$ cargo install wasm-pack          # 러스트를 웹어셈블리로 컴파일하고 JS interop code를 생성
$ cargo install cargo-make         # npm과 같은 task runner
$ cargo install simple-http-server # node에서 serve -s build와 같은 빌드 서버
$ cargo new --lib rustmart && cd rustmart

새로운 프로젝트를 만들고 해당 폴더로 진입해주세요.

우리는 Yew UI Components 라이브러리를 사용할 겁니다.

이런식으로 폴더로 진입하게되고 해당 구조로 구성되어있음이 확인 가능하실 겁니다.

 

[package]
name = "rustmart"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
yew = "0.17"
wasm-bindgen = "0.2"

 

생성된 파일에 해당 dependencies들을 설정해주고 lib을 설정해주세요.

Makefile.toml 이라는 파일을 추가하고 해당 내용을 추가해주세요.

[tasks.build]
command = "wasm-pack"
args = ["build", "--dev", "--target", "web", "--out-name", "wasm", "--out-dir", "./static"]
watch = { ignore_pattern = "static/*" }

[tasks.serve]
command = "simple-http-server"
args = ["-i", "./static/", "-p", "3000", "--nocache", "--try-file", "./static/index.html"]

먼저 빌드를 해보세요

$ cargo make build

그럼 target 폴더가 생성될겁니다.

Rust에 대한 추가적인 정보들은 다음 블로그에 있습니다.

http://www.sheshbabu.com/tags/Rust-Beginners/

 

Shesh's blog

 

www.sheshbabu.com

모든 문제의 기본인 Hello World 사용

static/index.html 파일을 생성하고 해당 내용을 추가해보세요.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>RustMart</title>
    <script type="module">
      import init from "/wasm.js";
      init();
    </script>
    <link rel="shortcut icon" href="#" />
  </head>
  <body></body>
</html>

그리고 src/lib.rs 파일에는 다음과 같이 적용해주세요.

// src/lib.rs
use wasm_bindgen::prelude::*;
use yew::prelude::*;

struct Hello {}

impl Component for Hello {
    type Message = ();
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Self {}
    }

    fn update(&mut self, _: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        true
    }

    fn view(&self) -> Html {
        html! { <span>{"Hello World!"}</span> }
    }
}

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Hello>::new().mount_to_body();
}

나중에, Yew 구성 요소에 대해 자세히 알아볼 것입니다. 

우선은 Hello World라는 span태그에 감싸진 엘리먼트를 생성하고 있음을 확인하실 수 있습니다.

서버를 한번 띄워보도록 하죠

cargo make serve

빌드도하고 서버도 띄워서 헬로우월드를 찍었으니 다음으로 구성요소 및 spa의 개념에 대해서 알아보도록 합시다.

 

컴포넌트들에 대한 생각

FLUX와 같이 단방향 컴포넌트에 익숙해지면 명령형으로 DOM 조작하는 것으로 돌아가기는 매우 힘듭니다.

리액트, 뷰, 플러터 등과 같은 컴포넌트 기반 라이브러리들에는 다음과 같은 특징들이 있습니다.

  • 더 큰 컴포넌트로 만들 수 있는 조합
  • props - 컴포넌트들에서 자식 컴포넌트로 데이터 및 콜백 전달
  • state - 컴포넌트의 상태 조작
  • AppState - 글로벌 상태 조작
  • 'Mounted in Dom' 과 같은 라이프사이클에 대한 반응

컴포넌트는 다음과 같은 상황에서 업데이트(리렌더링) 합니다. 

  • 부모 컴포넌트가 리렌더링 되었을 때
  • props가 변경되었을 때
  • state가 변경되었을 때
  • AppState가 변경되었을 때

따라서 사용자 상호작용, 네트워크 요청이 발생할 때 UI를 명령적으로 업데이트하는게 아니라, 데이터를 기반으로 UI를 업데이트 합니다.

 

HomePage

홈페이지 빌드를 해보시죠.

단단히 짜여지도록 하나의 컴포넌트로 빌드하고 더 작은 재사용가능한 컴포넌트 단위들로 나눠봅시다.

home.rs를 만드세요.

// src/pages/home.rs
use yew::prelude::*;

pub struct Home {}

impl Component for Home {
    type Message = ();
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Self {}
    }

    fn update(&mut self, _: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        true
    }

    fn view(&self) -> Html {
        html! { <span>{"Home Sweet Home!"}</span> }
    }
}
// src/pages/mod.rs
mod home;

pub use home::Home;

 src/lib.rs에 HomePage 컴포넌트를 임포트해보세요.

// src/lib.rs
mod pages;
use pages::Home;
use wasm_bindgen::prelude::*;
use yew::prelude::*;

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Home>::new().mount_to_body();
}

이제, Hello World 대신에 Home Sweet Home이 브라우저에 렌더링되게 됩니다.

이 컴포넌트의 상태관리를 디자인해보세요.

  • 우리는 프로덕트 리스트를 서버로부터 뽑아 저장해두어야 합니다.
  • 유저가 카트에 프로덕트들을 저장할 수 있어야 합니다.

우리는 간단하게 Product 라는 struct를 만들어보죠.

struct Product {
    name: String,
    description: String,
    image: String,
    price: f64
}

우리는 이제 products라는 필드를 가진 새로운 State struct를 만들 수 있습니다.

struct State {
    products: Vec<Product>,
}

이제 리스트가 있는 완전한 HomePage 컴포넌트가 만들어졌습니다.

create lifecycle 메소드는 컴포넌트가 생성될 때 호출되며 여기에서 초기 상태를 설정합니다.

당분간 우리는 제품의 모의 목록을 만들고 초기 값으로 2개의 아이템을 할당했습니다.

나중에는 request로 받아올 것입니다.

 

뷰 수명주기 메서드는 구성 요소가 렌더링될 때 호출됩니다.

여기서는 제품 카드를 생성하기 위해 상태 내부의 제품을 반복했습니다.

리액트에 익숙하다면 render메서드는 html 메서드와 같습니다.

 

2부에서는 카트에 제품을 담는 기능을 만들어보도록 하겠습니다.

 

 

출처 : http://www.sheshbabu.com/posts/rust-wasm-yew-single-page-application/

'SPA' 카테고리의 다른 글

Rust로 SPA 만들기 - 2. 카트에 물건 담기  (0) 2021.07.04

댓글