컴포넌트 가져오기 및 재사용 (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)에서 실행했습니다