paint-brush
Cách chia sẻ các loại rỉ sét với TypeScript cho WebAssugging trong 30 giây: Hướng dẫn nhanhtừ tác giả@dawchihliou
930 lượt đọc
930 lượt đọc

Cách chia sẻ các loại rỉ sét với TypeScript cho WebAssugging trong 30 giây: Hướng dẫn nhanh

từ tác giả Daw-Chih Liou6m2023/05/29
Read on Terminal Reader

dài quá đọc không nổi

💡 Chúng ta sẽ tìm hiểu lý do tại sao chuỗi công cụ Rust và WebAssugging chính thức không đủ cho TypeScript. 🤹 Tôi sẽ chỉ cho bạn cách tự động tạo định nghĩa TypeScript với ít thay đổi nhất trong mã Rust của bạn. 🧪 Chúng ta sẽ cùng nhau cấu trúc lại một thư viện WebAssembly trong thế giới thực trên npm.
featured image - Cách chia sẻ các loại rỉ sét với TypeScript cho WebAssugging trong 30 giây: Hướng dẫn nhanh
Daw-Chih Liou HackerNoon profile picture

Khám phá trải nghiệm liền mạch nhất dành cho nhà phát triển với Rust và WebAssembly. Đây là cách nhanh nhất để tự động tạo các định nghĩa TypeScript từ mã Rust của bạn.

Trong bài viết này

  • 💡 Chúng ta sẽ tìm hiểu lý do tại sao chuỗi công cụ Rust và WebAssugging chính thức không đủ cho TypeScript.


  • 🤹 Tôi sẽ chỉ cho bạn cách tự động tạo định nghĩa TypeScript với ít thay đổi nhất trong mã Rust của bạn.


  • 🧪 Chúng ta sẽ cùng nhau cấu trúc lại thư viện WebAssugging trong thế giới thực trên npm.


Đi nào.


Vấn đề đánh máy với wasm-bindgen

Tạo các loại TypeScript cho các mô-đun WebAssembly(Wasm) trong Rust không đơn giản.


Tôi gặp sự cố khi đang làm việc trên một công cụ tìm kiếm độ tương tự véc tơ trong Wasm có tên là Voy . Tôi đã xây dựng công cụ Wasm trong Rust để cung cấp cho các kỹ sư JavaScript và TypeScript một con dao Thụy Sĩ để tìm kiếm ngữ nghĩa. Đây là một bản demo cho web:


Bản trình diễn Voy


Bạn có thể tìm thấy kho lưu trữ của Voy trên GitHub ! Cảm thấy thật thanh thản khi từ bỏ.


Kho lưu trữ bao gồm các ví dụ mà bạn có thể xem cách sử dụng Voy trong các khuôn khổ khác nhau.


Tôi đã sử dụng wasm-packwasm-bindgen để xây dựng và biên dịch mã Rust thành Wasm. Các định nghĩa TypeScript được tạo trông như thế này:


 /* 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


Như bạn có thể thấy, có rất nhiều loại "bất kỳ", không hữu ích lắm cho trải nghiệm của nhà phát triển. Hãy xem mã Rust để tìm hiểu điều gì đã xảy ra.


 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 }


Chuỗi, lát cắt và số nguyên không dấu đã tạo ra các loại chính xác trong TypeScript, nhưng " wasm_bindgen::JsValue " thì không. JsValue là đại diện wasm-bindgen của một đối tượng JavaScript.


Chúng tôi tuần tự hóa và giải tuần tự hóa JsValue để chuyển nó qua lại giữa JavaScript và Rust thông qua Wasm.


 #[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() }


Đó là cách tiếp cận chính thức để chuyển đổi các loại dữ liệu, nhưng rõ ràng, chúng tôi cần nỗ lực hơn nữa để hỗ trợ TypeScript.

Tự động tạo liên kết TypeScript với Tsify

Chuyển đổi các loại dữ liệu từ ngôn ngữ này sang ngôn ngữ khác thực sự là một mẫu phổ biến được gọi là Giao diện chức năng nước ngoài (FFI). Tôi đã khám phá các công cụ FFI như Typeshare để tự động tạo các định nghĩa TypeScript từ các cấu trúc Rust, nhưng đó chỉ là một nửa của giải pháp.


Điều chúng ta cần là một cách để khai thác quá trình biên dịch Wasm và tạo định nghĩa kiểu cho API của mô-đun Wasm. Như thế này:


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


May mắn thay, Tsify là một thư viện nguồn mở tuyệt vời cho trường hợp sử dụng. Tất cả những gì chúng ta cần làm là bắt nguồn từ đặc điểm "Tsify" và thêm macro #[tsify] vào các cấu trúc:


 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 }


Đó là nó! Hãy xem các thuộc tính "from_wasm_abi" và "into_wasm_abi".


Wasm ABI


Cả hai thuộc tính đều chuyển đổi kiểu dữ liệu Rust sang định nghĩa TypeScript. Những gì họ làm khác là hướng của luồng dữ liệu với Giao diện nhị phân ứng dụng (ABI) của Wasm.


  • into_wasm_abi : Dữ liệu chuyển từ Rust sang JavaScript. Được sử dụng cho loại trả về.


  • from_wasm_abi : Dữ liệu chuyển từ JavaScript sang Rust. Được sử dụng cho các tham số.


Cả hai thuộc tính đều sử dụng serde-wasm-bindgen để triển khai chuyển đổi dữ liệu giữa Rust và JavaScript.


Chúng tôi đã sẵn sàng để xây dựng mô-đun Wasm. Khi bạn chạy "wasm-pack build", định nghĩa TypeScript được tạo tự động:


 /* 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ất cả các loại "bất kỳ" được thay thế bằng các giao diện mà chúng tôi đã xác định trong mã Rust✨

Suy nghĩ cuối cùng

Các loại được tạo có vẻ tốt, nhưng có một số điểm không nhất quán. Nếu quan sát kỹ, bạn sẽ nhận thấy tham số truy vấn trong hàm tìm kiếm được định nghĩa là Float32Array.


Tham số truy vấn được định nghĩa là cùng loại với "phần nhúng" trong EmbeddedResource, vì vậy tôi hy vọng chúng có cùng loại trong TypeScript.


Nếu bạn biết lý do tại sao chúng được chuyển đổi thành các loại khác nhau, vui lòng liên hệ hoặc mở yêu cầu kéo trong Voy trên GitHub .


Voy là một công cụ tìm kiếm ngữ nghĩa mã nguồn mở trong WebAssugging. Tôi đã tạo nó để trao quyền cho nhiều dự án hơn nhằm xây dựng các tính năng ngữ nghĩa và tạo trải nghiệm người dùng tốt hơn cho mọi người trên khắp thế giới. Voy tuân theo một số nguyên tắc thiết kế:


  • 🤏 Nhỏ bé : Giảm chi phí hoạt động cho các thiết bị hạn chế, chẳng hạn như trình duyệt di động có mạng chậm hoặc IoT.


  • 🚀 Nhanh chóng : Tạo trải nghiệm tìm kiếm tốt nhất cho người dùng.


  • 🌳 Tree Shakable : Tối ưu hóa kích thước gói và kích hoạt khả năng không đồng bộ cho API Web hiện đại, chẳng hạn như Web Worker.


  • 🔋 Có thể tiếp tục : Tạo chỉ mục nhúng di động mọi lúc, mọi nơi.


  • ☁️ Toàn cầu : Chạy tìm kiếm ngữ nghĩa trên các máy chủ biên CDN.


Nó có sẵn trên npm. Bạn có thể chỉ cần cài đặt nó với trình quản lý gói yêu thích của mình và bạn đã sẵn sàng sử dụng.


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


Hãy dùng thử và tôi rất vui khi nhận được phản hồi từ bạn!

Người giới thiệu


Muốn kết nối?

Bài viết này ban đầu được đăng trên Trang web của Daw-Chih .