Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

컴포넌트 가져오기 및 재사용 (Javascript)

Javascript 컴포넌트에서 사용하기 위한 기존 코드 합성

유용한 WebAssembly 컴포넌트를 빌드하는 데 기능을 export하는 것이 핵심인 것처럼, 기능을 import하고 재사용하는 것은 WebAssembly의 강점을 활용하는 데 핵심입니다.

다시 말해, WIT와 컴포넌트 모델은 WebAssembly가 합성할 수 있게 해 줍니다. 이는 이미 존재하는 기능을 기반으로 빌드하고, 기존 기능에 의존하는 새로운 기능을 export할 수 있다는 의미입니다.

(이전 예제에서) 문자열을 뒤집는 것에 더해, 받은 텍스트를 또한 대문자로 변환하는 공유 기능을 빌드하려 한다고 가정해 보겠습니다.

뒤집기 기능을 재사용하는 동시에 뒤집기와 대문자 변환을 수행할 수 있는 새 인터페이스를 익스포트할 수 있습니다.

문자열을 뒤집는 기능과 대문자로 변환하는 기능을 노출하는 string-reverse-upper라는 jco 예제 프로젝트를 살펴보겠습니다.

이 기능을 가능하게 하기 위해 작성할 수 있는 WIT는 다음과 같습니다:

package example:string-reverse-upper@0.1.0;

@since(version = 0.1.0)
interface reversed-upper {
    reverse-and-uppercase: func(s: string) -> string;
}

world revup {
    //
    // NOTE, the import below translates to:
    // <namespace>:<package>/<interface>@<package version>
    //
    import example:string-reverse/reverse@0.1.0;

    export reversed-upper;
}

이번에 빌드하는 revup이라는 이름의 world는 네임스페이스 example의 패키지 string-reverse에 있는 인터페이스 reverse에 의존합니다.

revup 월드를 구현하는 컴포넌트와 그 기능을 합성하기만 하면, 해당 인터페이스와 일치하는 어떤 WebAssembly 컴포넌트든 사용할 수 있습니다.

revup 월드는 reverse-and-uppercase 함수(JavaScript에서는 reverseAndUppercase)를 포함하는 reversed-upper 인터페이스를 export(제공)하기 위해 reverse를 import(하여 사용)합니다.

Note

기능은 world가 아니라 interface를 통해 가져옵니다. world도 포함하거나 사용할 수 있지만, 이를 위한 구문은 약간 다릅니다.

이를 동작하게 하는 JavaScript(jco/examples의 string-reverse-upper.js)는 다음과 같습니다:

/**
 * This module is the JS implementation of the `revup` WIT world
 */

/**
 * The import here is *virtual*. It refers to the `import`ed `reverse` interface in component.wit.
 *
 * These types *do not resolve* when the first `string-reverse-upper` component is built,
 * but the types are relevant for the resulting *composed* component.
 */
import { reverseString } from 'example:string-reverse/reverse@0.1.0';

/**
 * The JavaScript export below represents the export of the `reversed-upper` interface,
 * which which contains `revup` as it's primary exported function.
 */
export const reversedUpper = {
  /**
   * Represents the implementation of the `reverse-and-uppercase` function in the `reversed-upper` interface
   *
   * This function makes use of `reverse-string` which is *imported* from another WebAssembly binary.
   */
  reverseAndUppercase(s) {
    return reverseString(s).toLocaleUpperCase();
  },
};

위의 WIT 파일을 wit 하위 디렉터리에 두는 경우, wit/deps 하위 디렉터리도 생성하고 ../string-reverse/wit/component.wit를 wit/deps에 복사해야 합니다.

jco componentize로 컴포넌트를 빌드할 수 있습니다:

npx jco componentize \
    string-reverse-upper.mjs \
    --wit wit/ \
    --world-name revup \
    --out string-reverse-upper.incomplete.wasm \
    --disable=all

오류 메시지가 표시되면, wit/component.wit 파일이 package example:string-reverse-upper@0.1.0;으로 시작하는지, 그리고 wit/deps/ 디렉터리에 package example:string-reverse@0.1.0;으로 시작하는 파일이 있는지 확인하십시오. 일반적으로 주 패키지는 wit 디렉터리의 최상위에 있어야 하며, 모든 의존성은 해당 디렉터리의 하위 디렉터리(일반적으로 deps)에 있어야 합니다.

WebAssembly 컴포넌트를 성공적으로 빌드했지만, 다른 예제들과 달리 이 컴포넌트는 아직 완성되지 않았습니다.

jco wit를 실행하여 생성된 컴포넌트의 WIT를 출력해 보면 이를 확인할 수 있습니다:

npx jco wit string-reverse-upper.incomplete.wasm

다음과 같은 출력이 표시되어야 합니다:

package root:component;

world root {
  import example:string-reverse/reverse@0.1.0;

  export example:string-reverse-upper/reversed-upper@0.1.0;
}

이는 컴포넌트에 아직 충족되지 않은 import가 있음을 알려 줍니다. reverse에 있는 reverseString 함수가 존재하는 것처럼 사용하고 있지만, 이 함수는 아직 WebAssembly 컴포넌트의 실제 일부가 아닙니다(그래서 이름을 .incomplete.wasm으로 지었습니다).

앞서 빌드한 두 컴포넌트(string-reverse-upper/string-reverse-upper.incomplete.wasm와 string-reverse/string-reverse.wasm)를 합성하려면 WebAssembly 합성 도구(wac)가 필요합니다. wac plug를 사용할 수 있습니다:

wac plug \
    -o string-reverse-upper.wasm \
    --plug ../string-reverse/string-reverse.wasm \
    string-reverse-upper.incomplete.wasm

Note

jco 저장소의 전체 프로젝트를 사용하는 경우, npm run compose로도 이 단계를 실행할 수 있습니다.

이제 “완전한” 컴포넌트인 새 컴포넌트 string-reverse-upper.wasm이 생성되어 있어야 합니다. npx jco wit의 출력을 확인하여 모든 임포트가 충족되었는지 확인할 수 있습니다:

npx jco wit string-reverse-upper.wasm

다음과 같은 출력이 표시되어야 합니다:

package root:component;

world root {
  export example:string-reverse-upper/reversed-upper@0.1.0;
}

마치 아무 기능도 가져오지 않은 것과 같습니다. string-reverse.wasm에 있던 기능이 string-reverse-upper.wasm에 병합되었으며, 이제 이 컴포넌트는 고급 기능을 export하기만 합니다.

트랜스파일된 결과를 사용하면 WebAssembly를 지원하는 모든 네이티브 JavaScript 환경에서 이 완성된 컴포넌트를 실행할 수 있습니다:

npx jco transpile string-reverse-upper.wasm -o dist/transpiled

Note

예제 프로젝트에서는 대신 npm run transpile을 실행할 수 있으며, 이 명령은 dist/transpiled/string-reverse-upper.js의 확장자도 .mjs로 변경합니다.

다음과 같은 출력이 표시되어야 합니다:

  Transpiled JS Component Files:

 - dist/transpiled/interfaces/example-string-reverse-upper-reversed-upper.d.ts  0.12 KiB
 - dist/transpiled/string-reverse-upper.core.wasm                               10.1 MiB
 - dist/transpiled/string-reverse-upper.core2.wasm                              10.1 MiB
 - dist/transpiled/string-reverse-upper.d.ts                                    0.19 KiB
 - dist/transpiled/string-reverse-upper.js                                      6.13 KiB

Tip

두 개의 코어 WebAssembly 파일이 있다는 점에 주목하십시오. 이는 우리에게 필요한 최종 기능을 만드는 데 두 개의 코어 WebAssembly 모듈이 관여했기 때문입니다.

트랜스파일된 컴포넌트를 실행하려면 다음과 같은 코드를 작성할 수 있습니다:

/**
 * If this import listed below is missing, please run
 *
 * ```
 * npm run build && npm run compose && npm run transpile`
 * ```
 */
import { reversedUpper } from "./dist/transpiled/string-reverse-upper.js";

const result = reversedUpper.reverseAndUppercase("!dlroW olleH");

console.log(`reverseAndUppercase('!dlroW olleH') = ${result}`);

Note

jco 예제 프로젝트에서는 npm run transpiled-js를 실행할 수 있습니다.

다음과 같은 출력이 표시되어야 합니다:

reverseAndUppercase('!dlroW olleH') = HELLO WORLD!

jco transpile을 사용하여 Javsacript에서 컴포넌트 실행하기

재사용 가능한 기능을 WebAssembly 컴포넌트로 패키징하더라도 그 기능을 노출할 방법이 없다면 쓸모가 없습니다. 이 섹션에서는 WebAssembly 컴포넌트에서 WIT를 사용하는 방법을 조금 더 깊이 살펴봅니다.

다른 컴포넌트(또는 WebAssembly 호스트)가 사용할 수 있도록 WIT 인터페이스를 export하는 것은 WebAssembly 프로그램 개발의 기본입니다.

문자열을 뒤집는 기능을 노출하는 string-reverse라는 jco 예제 프로젝트를 살펴보겠습니다.

string-reverse와 같은 프로젝트를 처음부터 빌드하려면 먼저 다음과 같은 WIT로 시작합니다. string-reverse라는 새 디렉터리에서 이 코드를 wit/component.wit라는 파일에 붙여 넣으십시오:

package example:string-reverse@0.1.0;

@since(version = 0.1.0)
interface reverse {
    reverse-string: func(s: string) -> string;
}

world string-reverse {
    export reverse;
}

WIT에 대한 조금 더 깊이 있는 속성 강좌로서, 위 코드가 설명하는 내용은 다음과 같습니다:

  • example이라는 네임스페이스를 정의했습니다.
  • example 네임스페이스 안에 string-reverse라는 패키지를 정의했습니다.
  • 이 WIT 파일은 example:string-reverse 패키지의 0.1.0 버전에 해당합니다.
  • reverse-string이라는 함수 하나를 포함하는 reverse라는 인터페이스를 정의했습니다.
  • reverse 인터페이스가 0.1.0 버전부터 존재했음을 명시합니다.
  • reverse-string 함수(정규화된 전체 이름은 example:string-reverse/reverse.reverse-string)는 문자열을 받아 문자열을 반환합니다.
  • reverse 인터페이스가 제공하는 기능을 익스포트하는 string-reverse라는 world를 정의했습니다.

Warning

reverse가 실제로 문자열을 뒤집는다는 것을 어떻게 알 수 있을까요?

안타깝게도 이 문제는 이 수준에서는 사실상 해결할 수 없습니다. 이는 여러분과 해당 WIT 인터페이스를 구현하는 컴포넌트 작성자 사이의 문제입니다.

물론 WebAssembly에서는 원한다면 어떤 바이너리든 실행하기 전에 정적 검사를 강제할 수 있습니다.

이제 component 월드를 구현하는 JS 코드가 어떤 모습인지 살펴보겠습니다. 다음 코드를 string-reverse.mjs라는 파일에 붙여 넣으십시오:

/**
 * This module is the JS implementation of the `string-reverse` WIT world
 */

/**
 * The JavaScript export below represents the export of the `reverse` interface,
 * which which contains `reverse-string` as its primary exported function.
 */
export const reverse = {
/**
 * This JavaScript will be interpreted by `jco` and turned into a
 * WebAssembly binary with a single export (this `reverse` function).
 */
 reverseString(s) {
    return s.split("")
      .reverse()
      .join("");
  }
};

JavaScript에는 내장된 문자열 뒤집기 메서드가 없으므로, 이 코드는 split()을 사용해 문자열을 문자 배열로 변환하고, 배열을 뒤집은 다음, join()을 사용해 배열을 다시 문자열로 변환합니다.

Note

설명과 함께 전체 코드 목록을 보려면 examples/tutorials/jco/string-reverse 폴더를 참조하십시오.

jco를 사용하여 이 컴포넌트를 컴파일하려면 string-reverse 디렉터리 안에서 다음을 실행할 수 있습니다:

npx jco componentize \
    --wit wit/component.wit \
    --world-name string-reverse \
    --out string-reverse.wasm \
    --disable=all \
    string-reverse.mjs

다음과 같은 출력이 표시되어야 합니다:

OK Successfully written string-reverse.wasm.

Note

이전 예제와 마찬가지로 고급 WebAssembly 시스템 인터페이스 기능을 전혀 사용하지 않으므로 모두 --disable합니다.

string-reverse 폴더의 코드를 사용하는 경우, jco componentize 명령을 직접 입력하는 대신 npm run build로 빌드 명령을 실행할 수도 있습니다.

이제 WebAssembly 바이너리가 있으므로, (어디에서 왔든 상관없는!) WebAssembly 바이너리를 JavaScript 모듈로 트랜스파일하여 jco로 네이티브 JavaScript 컨텍스트에서 실행할 수도 있습니다.

npx jco transpile string-reverse.wasm -o dist/transpiled

다음과 같은 출력이 표시되어야 합니다:

  Transpiled JS Component Files:

 - dist/transpiled/interfaces/example-string-reverse-reverse.d.ts   0.1 KiB
 - dist/transpiled/string-reverse.core.wasm                        10.1 MiB
 - dist/transpiled/string-reverse.d.ts                             0.15 KiB
 - dist/transpiled/string-reverse.js                               2.55 KiB

Tip

참고로, 트랜스파일은 TypeScript 프로젝트에서 사용할 수 있는 TypeScript 선언 파일을 실제로 생성합니다.

이제 트랜스파일된 모듈이 있으므로, 코어 WebAssembly를 지원하는 모든 JavaScript 환경(Node.js든 브라우저든)에서 이를 실행할 수 있습니다.

Node.js의 경우 다음과 같은 코드를 사용할 수 있습니다. 다음 코드를 string-reverse 디렉터리의 run.js라는 파일에 붙여 넣으십시오:

// If this import listed below is missing, please run `npm run transpile`
import { reverse } from "./dist/transpiled/string-reverse.js";

const reversed = reverse.reverseString("!dlroW olleH");

console.log(`reverseString('!dlroW olleH') = ${reversed}`);

Note

jco 예제 프로젝트에서는 npm run transpiled-js를 실행하여 기존 코드를 빌드할 수 있습니다.

이전과 마찬가지로 package.json 파일도 필요합니다:

{
  "name": "string-reverse",
  "description": "Simple codebase for compiling a string reversing interface to WebAssembly with jco",
  "type": "module"
}

그런 다음 다음을 실행하십시오:

node run.js

(이전 단계에서 jco transpile을 실행하여) dist/transpiled 폴더가 채워져 있다고 가정하면, 다음과 같은 출력이 표시되어야 합니다:

reverseString('!dlrow olleh') = hello world!

이 맥락에서는 다소 중복되지만, NodeJS에서 수행한 작업은 WebAssembly와 jco 툴체인의 유용성을 보여 줍니다. jco의 도움으로 다음을 수행했습니다:

  • WIT로 정의된 인터페이스를 준수하여 JavaScript를 WebAssembly 모듈로 컴파일했습니다(jco compile)
  • 컴파일된 WebAssembly 모듈(어떤 언어로 작성된 것이든 가능)을 호환되는 모든 JS 런타임에서 사용할 수 있는 모듈로 변환했습니다(jco transpile)
  • 트랜스파일된 WebAssembly 컴포넌트를 JavaScript 네이티브 런타임(NodeJS)에서 실행했습니다

원문 © 2023 The Bytecode Alliance Contributors · WebAssembly Components Documentation · CC BY 4.0
Yeokja 한국어 번역·편집 · Anthropic 사의 claude-sonnet-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다 · 이 번역은 원문을 수정한 문서이며 CC BY 4.0으로 제공합니다.