Type-safe bindings for Node.js with Rust and WebAssembly

Rate this content
Bookmark
Slides

This talk will teach you how to write performance-critical Node.js modules without the burden of distributing platform-dependent artifacts and using the C/C++ toolchain. You will discover how to smoothly integrate Rust code into your Node.js + TypeScript application using WebAssembly. You will also learn how to avoid the typical WebAssembly serialization issues, and understand when other alternatives like Neon or Napi.rs are preferable. Together, we will cross the language bridge between Rust and Node.js while preserving the familiar DX you're used to.

FAQ

WebAssembly, or WASM, is a low-level bytecode format optimized for near-native speed, fast startup time, and small memory footprint. It serves as a portable binary format for a virtual machine, allowing code compiled to WASM to run on multiple platforms without performance degradation. This makes it especially valuable for projects like Node.js, where consistent performance across different systems is crucial.

TypeScript Bindings for NodeJS utilizes Rust and WebAssembly to offer an alternative, easier method to create native NodeJS modules while automatically generating types for them. By leveraging Rust's capabilities and the wasm-bindgen tool, developers can compile Rust code into WebAssembly and generate corresponding TypeScript bindings for use in Node.js applications.

wasm-bindgen is a tool that facilitates high-level interactions between WebAssembly modules and JavaScript. It allows developers to write Rust code that is compiled into WebAssembly, and then automatically generate the necessary JavaScript and TypeScript bindings. This tool helps in handling complex data types and ensuring that functions in Rust can be smoothly invoked from JavaScript environments.

WebAssembly simplifies deployment by allowing a single compilation target for multiple platforms, reducing the need for multiple compilations across different system configurations and architectures. This efficiency reduces deployment times and resource consumption, making maintenance and updates easier for developers.

Rust is preferred for WebAssembly because of its memory safety features and performance. It does not have a runtime or garbage collector, making it ideal for creating compact, high-speed WebAssembly binaries. Additionally, Rust's type system and ownership model ensure that WebAssembly applications are secure and efficient.

WebAssembly primarily supports numeric types natively, which presents challenges when dealing with complex or custom data types like strings, structs, or enums. Tools like wasm-bindgen or Serde are used to handle these complex types, but they often require additional code to manage data serialization and deserialization, adding complexity to the development process.

TSFI provides a more type-safe and ergonomic approach to integrate Rust functions and data structures into TypeScript applications using WebAssembly. It supports more complex data types without manual casting and offers stronger type bindings, improving developer experience and reducing the likelihood of runtime errors.

Alberto Schiabel
Alberto Schiabel
22 min
17 Apr, 2023

Comments

Sign in or register to post your comment.

Video Summary and Transcription

This Talk explores TypeScript bindings for NodeJS with Rust and WebAssembly, providing an alternative approach for creating native NodeJS modules and automatically generating types. It delves into the use of WebAssembly and Rust for TypeScript modules, showcasing how Rust functions can be defined and imported using the wasm.bindgen library. The Talk also highlights the challenges of string conversion between Rust and JavaScript, the limitations of supporting Rust data types in JavaScript, and the seamless integration of Rust functions into TypeScript apps using tspy. It concludes with the recommendation of TSFI for type-safe bindings and showcases its usage in a TypeScript-based full-text search engine with WebAssembly support.

1. Introduction

Short description:

This is TypeScript Bindings for NodeJS with Rust and WebAssembly. We'll be looking for an alternative, easier approach for creating native NodeJS modules, while also automatically generating types for them.

Hi, everyone, and thanks to Node Congress for having me. This is TypeScript Bindings for NodeJS with Rust and WebAssembly. We'll be looking for an alternative, easier approach for creating native NodeJS modules, while also automatically generating types for them.

A little bit about me. I'm Alberto Schibel. I'm from Venice, Italy. I'm a software engineer at Prisma where I ported several Rust modules to WebAssembly. I'm also a consultant working with NodeJS, TypeScript, and Rust. You can find me online at j.com.io. You can also find the slides for this talk on my GitHub page.

2. WebAssembly and Rust for TypeScript Modules

Short description:

WebAssembly, or WASM, is a low-level abstraction for the CPU your code is running on. It's a fast, compact bytecode designed for near-native speed and optimized for fast start-up time and small memory footprint. It's a portable compilation target for many languages, including Rust. Rust is consistently voted as the best language for WebAssembly. Let's see how we can create TypeScript modules from it.

So, elephant in the room, what is WebAssembly and how's that useful? Well, WebAssembly, or WASM, is basically a low-level abstraction for the CPU your code is running on. It's fast, compact bytecode in the sense that it's a portable binary format for a virtual machine that models loads and stores of numbers inside linear memory. It's designed for near-native speed and is also optimized for fast start-up time and small memory footprint. It was created by browser vendors to port C++ code to the web without performance degradation and now it's a portable compilation target for many languages including Rust, Go and many others.

That means you can compile your code to WASM once and then you can run the same compiled artifact on different platforms. For instance Node.js supports WebAssembly since version 8 and now you can import a WASM module exactly like you would import a standard npm package. And why is a single portable compilation target useful? Consider Node.js, a popular NAPI add-on that compiles SAS styles to CSS. To support multiple system configurations, architectures and even Node.js versions this library needs to be compiled separately for each of these configurations. This means 35 different compilation targets and it makes every new deployment a time and resource consuming task. Those of you who use Prisma will probably know that we're on a similar situation with TypeScript CLI and a library that downloads some compiled Rust binaries on demand. This is what made us consider WebAssembly and adopted as much as we to simplify our deployment process. And if you ever tried to write native Node.js add-ons yourself, you probably know that it's not a straightforward process. Sometimes, no jib fails with cryptic error messages and, frankly, the tooling necessary to build and import C++ modules isn't as human friendly as what Node.js developers are accustomed to. So, this is perhaps one of the major reasons why Rust is consistently voted as the best language for WebAssembly.

So, let's see how we can create the TypeScript modules from it. And for those of you new to Rust, let's define some baseline glossary, right? So, anything you use a package of json for, you would put in a cargo.toml file in a Rust project. What you usually call npm packages are crates in Rust and you operate on them via the cargo CLI. For instance, compiling Rust code, you would use the cargo build command and specify the completion target. In our case, it's Wasm 32 unknown, unknown. It uses a 32-bit addressing space and isn't tied to any particular OS vendor or CPU architecture. If we want to move around more than purely numeric data across the WebAssembly bridge, we're going to need a binding tool. It's both a CLI and Rust library. When you install it, you should specify a particular version, because it doesn't yet follow semantic versioning. This means that the version you specify in your cargo.toml file should match the version of Wasm you have installed on your machine. Moreover, to support WebAssembly, you need to mark your create type as c.lib. It will tell Rust to compile your code as a dynamic library that can be loaded by a C-compatible runtime, like Node.js. So, compiling Rust WebAssembly is a two-step process. First, you need to run cargo.build to create a compiled WebAssembly artifact, which will have the dot wasm extension, and then you will add wasm.bindgen to generate the Node.js and TypeScript bindings you will use to import the compiled wasm module. Of course, if wasm.bindgen supported all the commonly used Rust data structures and TypeScript conventions, this talk will already be over, and clearly that's not the case. So let's see how we can work around this.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Utilising Rust from Vue with WebAssembly
Vue.js London Live 2021Vue.js London Live 2021
8 min
Utilising Rust from Vue with WebAssembly
Top Content
Rust is a new language for writing high-performance code, that can be compiled to WebAssembly, and run within the browser. In this talk you will be taken through how you can integrate Rust, within a Vue application, in a way that's painless and easy. With examples on how to interact with Rust from JavaScript, and some of the gotchas to be aware of.
TypeScript and React: Secrets of a Happy Marriage
React Advanced Conference 2022React Advanced Conference 2022
21 min
TypeScript and React: Secrets of a Happy Marriage
Top Content
TypeScript and React are inseparable. What's the secret to their successful union? Quite a lot of surprisingly strange code. Learn why useRef always feels weird, how to wrangle generics in custom hooks, and how union types can transform your components.
Making JavaScript on WebAssembly Fast
JSNation Live 2021JSNation Live 2021
29 min
Making JavaScript on WebAssembly Fast
Top Content
JavaScript in the browser runs many times faster than it did two decades ago. And that happened because the browser vendors spent that time working on intensive performance optimizations in their JavaScript engines.Because of this optimization work, JavaScript is now running in many places besides the browser. But there are still some environments where the JS engines can’t apply those optimizations in the right way to make things fast.We’re working to solve this, beginning a whole new wave of JavaScript optimization work. We’re improving JavaScript performance for entirely different environments, where different rules apply. And this is possible because of WebAssembly. In this talk, I'll explain how this all works and what's coming next.
React's Most Useful Types
React Day Berlin 2023React Day Berlin 2023
21 min
React's Most Useful Types
Top Content
We don't think of React as shipping its own types. But React's types are a core part of the framework - overseen by the React team, and co-ordinated with React's major releases.In this live coding talk, we'll look at all the types you've been missing out on. How do you get the props type from a component? How do you know what ref a component takes? Should you use React.FC? And what's the deal with JSX.Element?You'll walk away with a bunch of exciting ideas to take to your React applications, and hopefully a new appreciation for the wonders of React and TypeScript working together.
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Node Congress 2022Node Congress 2022
26 min
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Top Content
Do you know what’s really going on in your node_modules folder? Software supply chain attacks have exploded over the past 12 months and they’re only accelerating in 2022 and beyond. We’ll dive into examples of recent supply chain attacks and what concrete steps you can take to protect your team from this emerging threat.
You can check the slides for Feross' talk here.
Towards a Standard Library for JavaScript Runtimes
Node Congress 2022Node Congress 2022
34 min
Towards a Standard Library for JavaScript Runtimes
Top Content
You can check the slides for James' talk here.

Workshops on related topic

React, TypeScript, and TDD
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
Best Practices and Advanced TypeScript Tips for React Developers
React Advanced Conference 2022React Advanced Conference 2022
148 min
Best Practices and Advanced TypeScript Tips for React Developers
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
Are you a React developer trying to get the most benefits from TypeScript? Then this is the workshop for you.In this interactive workshop, we will start at the basics and examine the pros and cons of different ways you can declare React components using TypeScript. After that we will move to more advanced concepts where we will go beyond the strict setting of TypeScript. You will learn when to use types like any, unknown and never. We will explore the use of type predicates, guards and exhaustive checking. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.
Deep TypeScript Tips & Tricks
Node Congress 2024Node Congress 2024
83 min
Deep TypeScript Tips & Tricks
Top Content
Workshop
Josh Goldberg
Josh Goldberg
TypeScript has a powerful type system with all sorts of fancy features for representing wild and wacky JavaScript states. But the syntax to do so isn't always straightforward, and the error messages aren't always precise in telling you what's wrong. Let's dive into how many of TypeScript's more powerful features really work, what kinds of real-world problems they solve, and how to wrestle the type system into submission so you can write truly excellent TypeScript code.
Node.js Masterclass
Node Congress 2023Node Congress 2023
109 min
Node.js Masterclass
Top Content
Workshop
Matteo Collina
Matteo Collina
Have you ever struggled with designing and structuring your Node.js applications? Building applications that are well organised, testable and extendable is not always easy. It can often turn out to be a lot more complicated than you expect it to be. In this live event Matteo will show you how he builds Node.js applications from scratch. You’ll learn how he approaches application design, and the philosophies that he applies to create modular, maintainable and effective applications.

Level: intermediate
Build and Deploy a Backend With Fastify & Platformatic
JSNation 2023JSNation 2023
104 min
Build and Deploy a Backend With Fastify & Platformatic
WorkshopFree
Matteo Collina
Matteo Collina
Platformatic allows you to rapidly develop GraphQL and REST APIs with minimal effort. The best part is that it also allows you to unleash the full potential of Node.js and Fastify whenever you need to. You can fully customise a Platformatic application by writing your own additional features and plugins. In the workshop, we’ll cover both our Open Source modules and our Cloud offering:- Platformatic OSS (open-source software) — Tools and libraries for rapidly building robust applications with Node.js (https://oss.platformatic.dev/).- Platformatic Cloud (currently in beta) — Our hosting platform that includes features such as preview apps, built-in metrics and integration with your Git flow (https://platformatic.dev/). 
In this workshop you'll learn how to develop APIs with Fastify and deploy them to the Platformatic Cloud.
0 to Auth in an Hour Using NodeJS SDK
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
WorkshopFree
Asaf Shen
Asaf Shen
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents- A quick intro to core authentication concepts- Coding- Why passwordless matters
Prerequisites- IDE for your choice- Node 18 or higher