paint-brush
WebAssembly için Pas Türlerini TypeScript ile 30 Saniyede Paylaşma: Hızlı Kılavuzile@dawchihliou
930 okumalar
930 okumalar

WebAssembly için Pas Türlerini TypeScript ile 30 Saniyede Paylaşma: Hızlı Kılavuz

ile Daw-Chih Liou6m2023/05/29
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

💡 Resmi Rust ve WebAssembly araç zincirinin TypeScript için neden yeterli olmadığını öğreneceğiz. 🤹 Rust kodunuzda minimum değişiklikle TypeScript tanımını nasıl otomatik olarak oluşturacağınızı göstereceğim. 🧪 Gerçek dünya WebAssembly kütüphanesini npm'de birlikte yeniden düzenleyeceğiz.
featured image - WebAssembly için Pas Türlerini TypeScript ile 30 Saniyede Paylaşma: Hızlı Kılavuz
Daw-Chih Liou HackerNoon profile picture

Rust ve WebAssembly ile en kusursuz geliştirici deneyimini keşfedin. Bu, Rust kodunuzdan TypeScript tanımlarını otomatik olarak oluşturmanın en hızlı yoludur.

Bu makalede

  • 💡 Resmi Rust ve WebAssembly araç zincirinin TypeScript için neden yeterli olmadığını öğreneceğiz.


  • 🤹 Rust kodunuzda minimum değişiklikle TypeScript tanımını nasıl otomatik olarak oluşturacağınızı göstereceğim.


  • 🧪 Gerçek dünyadaki bir WebAssembly kütüphanesini npm'de birlikte yeniden düzenleyeceğiz.


Hadi gidelim.


Wasm-bindgen ile Yazma Sorunu

Rust'ta WebAssembly(Wasm) modülleri için TypeScript türleri oluşturmak kolay değildir.


Wasm'da Voy adında bir vektör benzerlik arama motoru üzerinde çalışırken bu sorunla karşılaştım. Wasm motorunu, JavaScript ve TypeScript mühendislerine anlamsal arama için İsviçre bıçağı sağlamak üzere Rust'ta geliştirdim. İşte web için bir demo:


Voy demosu


Voy'un deposunu GitHub'da bulabilirsiniz! Denemekten çekinmeyin.


Depoda Voy'un farklı çerçevelerde nasıl kullanılacağını görebileceğiniz örnekler yer alıyor.


Rust kodunu oluşturup Wasm'a derlemek için wasm-pack ve wasm-bindgen'i kullandım. Oluşturulan TypeScript tanımları şöyle görünür:


 /* tslint:disable */ /* eslint-disable */ /** * @param {any} input * @returns {string} */ export function index(resource: any): string /** * @param {string} index * @param {any} query * @param {number} k * @returns {any} */ export function search(index: string, query: any, k: number): any


Gördüğünüz gibi çok sayıda "herhangi" türü var ve bu, geliştirici deneyimi için pek yararlı değil. Ne olduğunu öğrenmek için Rust koduna bakalım.


 type NumberOfResult = usize; type Embeddings = Vec<f32>; type SerializedIndex = String; #[derive(Serialize, Deserialize, Debug)] pub struct EmbeddedResource { id: String, title: String, url: String, embeddings: Embeddings, } #[derive(Serialize, Deserialize, Debug)] pub struct Resource { pub embeddings: Vec<EmbeddedResource>, } #[wasm_bindgen] pub fn index(resource: JsValue) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: &str, query: JsValue, k: NumberOfResult) -> JsValue { // snip }


Dize, dilim ve işaretsiz tamsayı TypeScript'te doğru türleri oluşturdu ancak " wasm_bindgen::JsValue " oluşturmadı. JsValue wasm-bindgen'in bir JavaScript nesnesini temsilidir.


JsValue'yu, Wasm aracılığıyla JavaScript ve Rust arasında ileri geri aktarmak için seri hale getiriyoruz ve seri durumdan çıkarıyoruz .


 #[wasm_bindgen] pub fn index(resource: JsValue) -> String { // 💡 Deserialize JsValue in to Resource struct in Rust let resource: Resource = serde_wasm_bindgen:from_value(input).unwrap(); // snip } #[wasm_bindgen] pub fn search(index: &str, query: JsValue, k: usize) -> JsValue { // snip // 💡 Serialize search result into JsValue and pass it to WebAssembly let result = engine::search(&index, &query, k).unwrap(); serde_wasm_bindgen:to_value(&result).unwrap() }


Veri türlerini dönüştürmek resmi yaklaşımdır, ancak açıkça TypeScript'i desteklemek için ekstra yol kat etmemiz gerekiyor.

Tsify ile TypeScript Bağlamayı Otomatik Oluştur

Veri türlerini bir dilden diğerine dönüştürmek aslında Yabancı işlev arayüzü (FFI) adı verilen yaygın bir kalıptır. Rust yapılarından TypeScript tanımlarını otomatik olarak oluşturmak için Typeshare gibi FFI araçlarını araştırdım, ancak bu, çözümün yalnızca yarısıydı.


İhtiyacımız olan şey, Wasm derlemesinden yararlanmanın ve Wasm modülünün API'si için tür tanımını oluşturmanın bir yoludur. Bunun gibi:


 #[wasm_bindgen] pub fn index(resource: Resource) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: SerializedIndex, query: Embeddings, k: NumberOfResult) -> SearchResult { // snip }


Neyse ki Tsify , kullanım durumu için harika bir açık kaynaklı kütüphanedir. Tek yapmamız gereken "Tsify" özelliğinden türetmek ve yapılara bir #[tsify] makrosu eklemek:


 type NumberOfResult = usize; type Embeddings = Vec<f32>; type SerializedIndex = String; #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(from_wasm_abi)] pub struct EmbeddedResource { pub id: String, pub title: String, pub url: String, pub embeddings: Embeddings, } #[derive(Serialize, Deserialize, Debug, Tsify)] #[tsify(from_wasm_abi)] pub struct Resource { pub embeddings: Vec<EmbeddedResource>, } #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(into_wasm_abi)] pub struct Neighbor { pub id: String, pub title: String, pub url: String, } #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(into_wasm_abi)] pub struct SearchResult { neighbors: Vec<Neighbor>, } #[wasm_bindgen] pub fn index(resource: Resource) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: SerializedIndex, query: Embeddings, k: NumberOfResult) -> SearchResult { // snip }


Bu kadar! "from_wasm_abi" ve "into_wasm_abi" niteliklerine bir göz atalım.


Wasm ABI


Her iki özellik de Rust veri türünü TypeScript tanımına dönüştürür. Farklı yaptıkları şey, Wasm'ın Uygulama İkili Arayüzü (ABI) ile veri akışının yönüdür.


  • into_wasm_abi : Veriler Rust'tan JavaScript'e akar. Dönüş türü için kullanılır.


  • from_wasm_abi : Veriler JavaScript'ten Rust'a akar. Parametreler için kullanılır.


Her iki özellik de Rust ve JavaScript arasındaki veri dönüşümünü uygulamak için serde-wasm-bindgen'i kullanır.


Wasm modülünü oluşturmaya hazırız. "Wasm-pack build"i çalıştırdığınızda, otomatik olarak oluşturulan TypeScript tanımı:


 /* tslint:disable */ /* eslint-disable */ /** * @param {Resource} resource * @returns {string} */ export function index(resource: Resource): string /** * @param {string} index * @param {Float32Array} query * @param {number} k * @returns {SearchResult} */ export function search( index: string, query: Float32Array, k: number ): SearchResult export interface EmbeddedResource { id: string title: string url: string embeddings: number[] } export interface Resource { embeddings: EmbeddedResource[] } export interface Neighbor { id: string title: string url: string } export interface SearchResult { neighbors: Neighbor[] }


Tüm "herhangi" türler, Rust kodunda tanımladığımız arayüzlerle değiştirilir✨

Son düşünceler

Oluşturulan türler iyi görünüyor ancak bazı tutarsızlıklar var. Yakından bakarsanız, arama fonksiyonundaki sorgu parametresinin Float32Array olarak tanımlandığını fark edeceksiniz.


Sorgu parametresi EmbeddedResource'ta "gömmeler" ile aynı türde tanımlandığından TypeScript'te de aynı türe sahip olmalarını bekliyorum.


Neden farklı türlere dönüştürüldüklerini biliyorsanız, lütfen GitHub'daki Voy'a ulaşmaktan veya bir çekme isteği açmaktan çekinmeyin.


Voy , WebAssembly'deki açık kaynaklı bir anlamsal arama motorudur. Bunu, anlamsal özellikler geliştirmek ve dünyanın her yerindeki insanlar için daha iyi kullanıcı deneyimleri yaratmak amacıyla daha fazla projeye güç vermek için oluşturdum. Voy çeşitli tasarım ilkelerini takip eder:


  • 🤏 Minik : Yavaş ağlara veya IoT'ye sahip mobil tarayıcılar gibi sınırlı cihazlar için yükü azaltın.


  • 🚀 Hızlı : Kullanıcılar için en iyi arama deneyimini yaratın.


  • 🌳 Sarsılabilir Ağaç : Paket boyutunu optimize edin ve Web Çalışanları gibi modern Web API'leri için eşzamansız yetenekleri etkinleştirin.


  • 🔋 Devam Edilebilir : İstediğiniz zaman, istediğiniz yerde taşınabilir yerleştirme dizini oluşturun.


  • ☁️ Dünya çapında : CDN uç sunucularında anlamsal bir arama çalıştırın.


Npm'de mevcuttur. Favori paket yöneticinizle kolayca kurabilirsiniz ve artık hazırsınız.


 # with npm npm i voy-search # with Yarn yarn add voy-search # with pnpm pnpm add voy-search


Bir deneyin, sizden haber almaktan mutluluk duyuyorum!

Referanslar


Bağlanmak mı istiyorsunuz?

Bu makale ilk olarak Daw-Chih'in Web Sitesinde yayınlanmıştır.