wasm을 하기에는 pyodide는 아닌 것 같고, rust로 방향을 틀었다.

여러 가지 방법을 시도해 보았으나 가장 좋은 방법은 wasm-pack을 사용하는 것으로 결론지었다. *.wasm 파일을 바로 만들어 javascript 로 로딩하는 방법을 써 보았지만 application-wasm에 대한 등록 문제 등 생각치도 못한 문제들을 많이 만나게 되었다.

이 글은 wasm-pack에 대한 공식 홈 페이지

https://rustwasm.github.io/docs/book/introduction.html

를 따라 한 것이며, 중간에 발생하는 문제점들을 추가하였다.

내가 테스트한 환경은 다음과 같다.

  • ubuntu 20.04 LTS
  • 2CPU mem 4G

Setup

1. Rust 설치

  • Rust 를 설치한다. 여기서는 ubuntu용 rust를 사용했다.

2. wasm-pack 설치

  • 그 다음에 wasm-pack을 설치한다. wasm-pack은

    https://rustwasm.github.io/wasm-pack/installer/ 를 참조하기 바란다.

3. cargo-generate 설치

  • github 에 있는 여러 rust관련 프로젝트 템플릿을 참조하여 빠르게 Rust 프로젝트를 구성해주는 것이다. 다음 명령으로 설치를 시도했다.

    cargo install cargo-generate

  • openSSL관련 오류가 뜨면서 설치가 안되는 경우가 있다. pkg-config가 없어서 발생하는 문제이므로 이를 설치해 준 후에 재시도 한다.

    sudo apt install pkg-config

  • 이 과정은 시간이 좀 오래 걸린다.

4. npm 설치

  • 웹에서 보여주기 위해 node 도 필요하다.

    npm install npm@latest -g

이제 Hello World를 찍어보도록 하겠다.

Hello World

1. clone Project Templete

  • cargo-generate를 사용해 Project Templete를 복제한다.

    cargo generate --git https://github.com/rustwasm/wasm-pack-template

  • 진행하다 보면 프로젝트 명을 입력하는 부분이 있는데 공식 홈페이지에서는 wasm-game-of-life를 사용했으나 여기서는 wasm-example로 하겠다.

2. 프로젝트 폴더

  • 프로젝트 폴더에는 다음과 같은 구조로 되어 있다.
wasm-example/
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
└── src
    ├── lib.rs
    └── utils.rs
  • 각 파일에 대한 설명은 공식 홈페이지에 잘 나와 있으니 참조하기 바란다.
  • wasm 수행 코드는 lib.rs에 반영시키면 된다.

3. 프로젝트 빌드

  • 프로젝트빌드는 wasm-pack 명령으로 수행한다.

    wasm-pack build

  • 그러면 pkg 폴더가 생성되고 거기에 빌드 결과물이 들어있을 것이다.

pkg
├── README.md
├── package.json
├── wasm_example.d.ts
├── wasm_example.js
├── wasm_example_bg.js
├── wasm_example_bg.wasm
└── wasm_example_bg.wasm.d.ts

4. 연결되는 웹 프로젝트 생성

  • wasm_example폴더에서 npm으로 웹 프로젝트 생성 명령을 실행한다.

    npm init wasm-app www

  • 상황에 따라 다음과 같은 오류가 뜨면서 www 가 생성안되는 경우가 있다.

    opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
      library: 'digital envelope routines',
      reason: 'unsupported',
      code: 'ERR_OSSL_EVP_UNSUPPORTED'
    

    이는 node 버전이 너무 높아 발생하는 경우이다. node 16.x 이하로 낮추어 재시도 한다.

  • 정상적으로 완료되면 www폴더가 생성되며 다음과 같은 파일들이 생성된다

    wasm-example/www/
    ├── bootstrap.js
    ├── index.html
    ├── index.js
    ├── LICENSE-APACHE
    ├── LICENSE-MIT
    ├── package.json
    ├── README.md
    └── webpack.config.js
      
    

5. 웹 프로젝트와 wasm의 연결

  • 웹 프로젝트와 위 wasm프로젝트의 연결 포인트는 index.js 파일이다. 여기의 소스코드는 다음과 같다

    import * as wasm from "hello-wasm-pack";
      
    wasm.greet();
    
  • 현재는 디폴트로 hello-wasm-pack을 import하고 있는데 우리는 위에서 pkg로 wasm_example로 만들었으므로 이를 wasm_example로 바꾸어 준다.

    import * as wasm from "wasm_example";
      
    wasm.greet();
    
  • 웹 프로젝트의 package.json파일에서 위에서 만든 pkg폴더에 종속 관계(dependencies)를 추가해 준다.

      "devDependencies": {
        "copy-webpack-plugin": "^5.0.0",
        ...
      },
      "dependencies": {
        "wasm_example": "file:../pkg"
      }
    

6. 개발 실행

  • npm install로 필요 패키지를 다운로드
  • npm run start로 실행하여 정상적으로 alert()이 수행되면 성공

image-20231221124831961

  • npm run build를 실행하면 /www밑에 /dist 폴더가 생성되며, 배포 버전이 wasm파일과 함께 있는 것을 알 수 있다.

    .
    ├── 0.bootstrap.js
    ├── 83ae667d8fb6fa92a993.module.wasm
    ├── 8e8fa9289c240ac706a1.module.wasm
    ├── bootstrap.js
    └── index.html
    

Rust로 Web Assembly를 그냥 하면 어렵지만 wasm-pack을 이용하면 큰 설정 없이 쉽게 할 수 있다고 해서 시도를 해 보았지만, 이 역시 여러가지 환경적 문제들(pkg관리자, node버전 등)을 해결해야 했었다.

하지만 vue나 react와 같은 개발 구조를 제공하므로서 좀 더 Web Assembly를 개발하기 쉽게 만들었다는 점은 높이 살 만 하겠다.