Why Rust

Before we get into the formal sharing, let’s talk about why we should learn Rust, a language that broadly belongs to the back end, what it can bring us and what it holds for the future

  1. Syntax that is partially similar to JavaScript should not be difficult to get started with (probably)
  2. A secure and efficient new language, Rust gives you a basic understanding of how the underlying workings of a computer work
  3. Built on WebAssembly, Rust runs in a browser and provides excellent performance in certain scenarios such as live video or computation-intensive scenarios, such as figma, which we use a lot
  4. Mastering at least one back-end language will help with subsequent improvements, and Node.js is also right, but for the underlying computer compared to CPP and RUST boxes
  5. Rust’s design philosophy is worth a look

Rust

The Rust language is an efficient and reliable general-purpose high-level language. Its efficiency is not limited to development efficiency, but its execution efficiency is also commendable, it is a rare language that has both development efficiency and execution efficiency. Rust is an Ahead-of-time compiled language, which means you can compile programs and send executables to other people who don’t even need to install Rust to run them. If you give someone a.rb,.py, or.js file, they will need to install Ruby, Python, and JavaScript implementations (runtime environment, VM) respectively


Instead of introducing the syntax and compilation methods of Rust one by one, I will introduce what I think are some interesting features and design ideas of Rust

  1. Variables in Rust are immutable by default. Immutable variables are a specification that helps us intuitively track the changing state of data. For example, the React PureComponent or Memo will only compare the old and new data in a shallow way. Due to the JS reference assignment, this method is only applicable to stateless components or components with very simple state data. For a large number of application components, it cannot do anything. Therefore, we will consider using immutable + Memo shallow comparison when writing.

Let’s take the simplest example

// variable, arR new
arr.push(item)  
/ / the immutable
arr = [...arr,item] 
Copy the code
  1. A full-fledged type system (very similar to Typescript), but much finer than Typescript in some respects, such as unsigned, signed 8-bit, 16-bit, 32-bit, 64-bit, and 128-bit.
// Unsigned 32-bit integer
let guess: u32 = "42".parse().expect("Not a number!"); 
Copy the code
  1. Language integration, both Javascript flexibility, and C/C++ compiler support

Give an example of its flexibility

let x = 5; 
let y = {    
    let x = 3;    
    x + 1 
}; 
println!("The value of y is: {}", y); 
Copy the code

In the example above Rust uses **; ** determines whether the sentence is an expression or a statement

  1. Rigorous, flexible control flow
/ / complains
fn main() {     
    let number = 3;  
    
    if number {         
        println!("number was three"); }}// Assignment statements like the following are fully valid
let condition = true;     
let number = if condition {         
    5     
} else {
    6     
}; 
Copy the code
  1. Distinct from garbage collection (javascript) and personally allocating and freeing memory (C/C++),Rust takes another approach to managing operating system memory: it manages memory through an ownership system that compilers check against a set of rules at compile time. None of the features of the ownership system slows down the program at run time.

If the memory operation is divided into the following two parts

  • Memory must be requested from the operating system at runtime.
  • We need a way to return memory to the operating system when we’re done with the String.

The first step is more or less the same, but the second step is more or less the same, for Rust

  1. Every value in Rust has one called itsThe owner of the(owner).
  2. Values have one and only one owner at any time.
  3. This value is discarded when the owner (variable) leaves scope.

To keep the runtime efficient, Rust never automatically creates “deep copies” of data. Therefore, any automatic replication can be considered to have little impact on runtime performance. For this reason, Rust has adopted a rule against changing stack space variables that reference heap space (value types on stack space can be directly referenced), because Rust does not need to clean up anything after the variable that was first allocated space has left scope

let s1 = String::from("hello"); 
let s2 = s1; 
println!("{}, world!", s1); 
/ / complains
let s1 = String::from("hello"); 
let s2 = s1.clone(); 
println!("s1 = {}, s2 = {}", s1, s2); 
// Manual cloning is required
Copy the code

When the owner (variable) leaves scope, the value is discarded. If you look at the picture below, this operation is neitherShallow copy(shallow copy) andDeep copy(deep copy), copying Pointers, length, and capacity without copying data may sound like a shallow copy. But because Rust also invalidates the first variable, this operation is calledmobile(move), but note that Rust copies value types rather than moving them, so value types (integers, etc.) can still be used after a function calls them

fn main() {
    let s = String::from("hello");  // s enters scope
    takes_ownership(s);             // move the value of s to the function...
                                    / /... So it's no longer valid up here
    let x = 5;                      // x goes into scope
    makes_copy(x);                  // x should move in the function,
                                    // I32 is Copy, so we can continue to use x later
} // here, x moves out of scope first, then s. But since the value of s has been removed,
  // There will be no special operations
fn takes_ownership(some_string: String) { // some_string enters scope
    println!("{}", some_string);
} // Here, some_string moves out of scope and calls the 'drop' method. The occupied memory is released. Procedure
fn makes_copy(some_integer: i32) { // some_integer enters the scope
    println!("{}", some_integer);
} // here, some_INTEGER moves out of scope. There will be no special operations

Copy the code

Variable ownership always follows the same pattern: move a value when assigning it to another variable. When a variable holding data values in the heap leaves scope, its value is cleared by DROP, unless the data is moved to another variable

fn main() {
    let s1 = gives_ownership();         // Gives_ownership will return a value
                                        / / move to s1
    let s2 = String::from("hello");     // s2 enters scope
    let s3 = takes_and_gives_back(s2);  // s2 is moved to
                                        / / takes_and_gives_back,
                                        // It also moves the return value to s3
} // here, S3 moves out of scope and is discarded. S2 is also out of scope, but has been removed,
  // So nothing happens. S1 moves out of scope and is discarded
fn gives_ownership() - >String {             // gives_ownership moves the return value to
                                             // Call its function
    let some_string = String::from("hello"); // some_string enters scope.
    some_string                              // Returns some_string and moves it out to the calling function
}
// Takes_and_gives_back will pass in the string and return the value
fn takes_and_gives_back(a_string: String) - >String { // a_string goes into scope
    a_string  // Returns a_string and moves it out to the calling function
}

Copy the code

Getting ownership in every function and then returning ownership is a bit verbose. What if we want the function to use a value without taking ownership? This is where references and borrowings are needed.

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) - >usize {
    s.len()
}
// Try to modify, that specified is not possible
fn main() {
    let s = String::from("hello");

    change(&s);
}
fn change(some_string: &String) {
    some_string.push_str(", world");
}
Copy the code

A function calls a reference to a reference type. Using this variable in the body of a function is called borrowing. A new concept needs to be introduced: mutable references

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}
fn change(some_string: &mut String) {
    some_string.push_str(", world");
}
Copy the code

However, mutable references have one major limitation: there can only be one mutable reference for a particular piece of data in a particular scope, and mutable and immutable references should not exist together (the two are mutually exclusive).

/ / complains
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
// Error too
let mut s = String::from("hello");
let r1 = &s; / / no problem
let r2 = &s; / / no problem
let r3 = &mut s; / / big problem
println!("{}, {}, and {}", r1, r2, r3);
Copy the code

The benefit of this limitation is that Rust can avoid data contention at compile time. It can be thought of as something similar to a distributed lock. Data contention leads to undefined behavior that is difficult to trace at run time and difficult to diagnose and fix. Rust prevents this from happening because it does not even compile code with data contention, noting that the scope of a reference starts where it is declared and continues until it is last used. For example, because an immutable reference was last used before a mutable reference was declared, the following code could be compiled:

let mut s = String::from("hello");
let r1 = &s; / / no problem
let r2 = &s; / / no problem
println!("{} and {}", r1, r2);// R1 and R2 are not used after this position
let r3 = &mut s; / / no problem
println!("{}", r3);
Copy the code

But while it can compile, such writing bypassed static type checking !!!!!!

A string is a value type. Why can it be represented as a reference type? String uses the special reference type Slice without ownership, which allows you to refer to a contiguous sequence of elements in a collection rather than the entire collection.

let s = String::from("hello");
let slice = &s[0.2];
let slice = &s[..2];
Copy the code

For “value type” string

let s = "Hello, world!"; 
Copy the code

Here s is of type &str: it is a slice pointing to a specific location in the binary. That’s why string literals are immutable; & STR is an immutable reference.

A dangling reference a dangling pointer is a pointer to memory that may have been allocated to another holder. In Rust, by contrast, the compiler ensures that references never become dangling, as in the following code

fn main() {
    let reference_to_nothing = dangle();
}
// wrong
fn dangle() - > &String {
    let s = String::from("hello");
    &s
}
//safe
fn safe() - >String {
    let s = String::from("hello");
    s
}
Copy the code

Because s is created inside the Dangle function, s is released when dangle code completes execution. But let’s try to return a reference to it. This means that the reference will point to an invalid String, which is not true! Rust would not allow us to sum up two rules

  • There can be either one mutable reference or multiple immutable references at any given time.
  • A reference must always be valid.

To here and JavaScript related, and the basic share of almost, vaguely remember someone said, if you know a language, understand its basic syntax, can write corresponding simple code to achieve simple functions, then you will get started. The follow-up includes the following parts, just press the table

  • Cargo: Cargo is Rust’s build system and package manager. Most Rustacean use Cargo to manage their Rust projects because it handles many tasks for you, such as building code, downloading dependent libraries, and compiling them. This is similar to NPM/PNPM/YARN used by JS
  • Common collections: Hashmap (similar to MAP in JS), Vector (similar to array in JS), String
  • Error handling: panic(Throw Error completely blocks program execution) Result(similar to warning)
  • .

To conclude, two things I find most remarkable about Rust

  1. Rich and powerful type system
  2. A reliable ownership model

Rust and WebAssembly

Rust is just one of our pig’s feet today. Who else is there today? Yes, WebAssembly. So what exactly is WebAssembly? So before WE get to that, how do we compile JavaScript so we have to talk about two ways to compile it

  • AOT: Ahead-of-Time compilation

It must be a strongly typed language, and compilation directly generates binary files that the CPU can execute before compilation. When executing, the CPU does not need to do any compilation operations and executes directly, which provides the best performance. For example, C/C++,Rust

  • JIT: Just-in-Time compilation

There is no compilation. Binary assembly code is generated according to the context and pumped into the CPU for execution. V8 optimizes JavaScript performance in this way by JIT execution, which can be optimized for code compilation, without having to translate into binary assembly code every time the code is run.

For example, if you declare a variable using var, instead of using Typescript’s type system to qualify a variable, the type of the variable may be different when compiled multiple times, resulting in a recompile every time JavaScript is executed. That’s why the type system is so important. It not only reduces bugs but also makes our code run faster

So, to tell you a little bit more about the process

  1. The code file will be downloaded.
  2. Then it goes to Parser, which converts the code into an AST (abstract syntax tree).
  3. The Bytecode Compiler then generates Bytecode that the engine can read and execute directly from the abstract syntax tree.
  4. Bytecode goes into the translator, which translates bytecode line by line into Machine Code with high efficiency.

Some of you might ask: Isn’t JavaScript static type checking possible using Typescript? Why not compile to an executable binary at compile time? Blind boy, you found the warhol! Typescript literally patches JavaScript, but JavaScript is still JavaScript, and what if we see the entire kernel of JavaScript rewritten in our lifetime? Wasm: So I go?

Back to the point, since the JavaScript kernel doesn’t change much, how can we optimize it? One idea is that you can compile C, C++, Rust, etc. into WebAssembly and run it in a browser, but it’s important to note that using WASM doesn’t eliminate JavaScript altogether. The two actually complement each other. In a real-world application scenario, Rust and JavaScript often call each other’s packages to develop a Web application.WebAssembly is a bytecode standard that relies on virtual machines to run in browsers. The World Wide Web Consortium (W3C) announced on 5 December 2019 thatThe WebAssembly core specificationNow an official Web standard, it releases a powerful new language for the Web. WebAssembly is a secure, portable, low-level format that performs efficiently and compactly in modern processors, including Web browsers. It is also designed to coexist with JavaScript, allowing the two to work together. This may be confusing to you, but another way to think about it is we’re dealing with all kinds of businesses every day, so have you ever wondered what happens when we start writing JavaScript code? Just looking at JavaScript, it looks like this

Business code -> V8 parse -> get compiled results (bytecode) -> Thread communication -> inform GPU to draw -> Render

What is the process if we use WebAssembly

Business code -> Compile -> bytecode -> Thread communication -> Inform GPU draw -> Render

As you can see, the biggest difference between the two links is that in the second link, what the browser (V8) gets is already a copy of the bytecode that can be executed. It just needs to execute and is done, instead of using a lot of CPU to compile the potentially complex source code. But pure bytecode specification is not acceptable. C/C++ and Rust may have their own specifications, so they need a set of specifications to be integrated so that everyone can have fun in the browser. This is called WebAssembly. His standard generates files with the suffix. Wasm, which can be delivered directly to the browser for execution. In addition, depending on the nature of WASM, I think wASM will be useful in many ways in the future

In actual combat

As the saying goes, the paper comes zhongjue shallow, must know this to practice, the above simple learning rust+ WASM, then if you don’t practice it is not a waste, then how to practice rust+ WASM? Look at the wASM documentation yourself? That designation won’t do. So what to do? Yew is an advanced Rust framework designed to create multi-threaded front-end Web applications using WebAssembly.

  • Component-based framework that makes it easy to create interactive UIs. Developers with experience with frameworks such as React or Elm will feel comfortable working with Yew.
  • High performance. Front-end developers can easily offload work to the back end to reduce DOM API calls and achieve exceptional performance.
  • Support for interaction with JavaScript, allowing developers to use NPM packages and combine them with existing JavaScript applications.

Make a Yew app run in three steps (sure)

  1. Create a binary project
cargo new --bin yew-app && cd yew-app
Copy the code
  1. Write the code, be careful to write index.html
  2. Start the
cargo install trunk wasm-bindgen-cli
rustup target add wasm32-unknown-unknown
trunk serve
Copy the code

A diagram illustrates the role of WASM-Bindgen

componentization

Page display code

use yew::prelude::*;

enum Msg {
    AddOne,
}

struct Model {
    link: ComponentLink<Self>,
    value: i64,}impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_props: Self::Properties, link: ComponentLink<Self- > >)Self {
        Self {
            link,
            value: 0,}}fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::AddOne => {
                self.value += 1;
                true}}}fn change(&mut self, _props: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html! {
            <div>
                <p>{ "tandake is a Vegetable Chicken"  }</p>
                <button onclick=self.link.callback(|_| Msg::AddOne)>{ "+ 1" }</button>
                <p>{ self.value  }</p>
            </div>
        }
    }
}

fn main() {
    yew::start_app::<Model>();
}

Copy the code

Results demonstrateAs you can see, the file source for this rendering is already WASM. Sharp-eyed students may have noticed the create, update, and change functions above, so what are they used for? A brief description of the lifecycle of components in yew: The Component property defines six lifecycle functions.

  • Create is a constructor that takes items and ComponentLink
  • View renders the component
  • Update Is called when a Message is sent to the component, implementing the logic of Message passing
  • Change re-renders changes to optimize rendering speed
  • Rendered after the View but before the browser update, rendered once to distinguish between a first rendering and a consecutive rendering.
  • Destroy, called when a component is uninstalled and a cleanup operation is required.

If it is analogous to the React class component, create is the constructor constructor, update is the static method registered inside the component, change is the same as shouldComponentUpdate, and other life cycles can also be analogous

Communication in parent and child components

Yew is component-based. How can parent and child components communicate with each other in the simplest way? Declare the parent component

#[derive(Clone, PartialEq, Properties, Default)]
struct Properties {
    name: String,}enum Message {
    ChangeName(String),}struct Model {
    link: ComponentLink<Self>,
    props: Properties,
}

impl Model {
    fn change_name(&mut self, name: String) {
        self.props.name = name; }}impl Component for Model {
    type Message = Message;
    type Properties = Properties;

    fn create(_props: Self::Properties, link: ComponentLink<Self- > >)Self {
        Self {
            link,
            props: Properties {
                name: "tandake".to_string(),
            },
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Message::ChangeName(name) => {
                self.change_name(name); }};true
    }

    fn change(&mut self, _props: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html! {
            <div>
                <p>{ "Hi, I'm Tan Dako, the two-and-a-half-day Rust intern."  }</p>
                <p>{"hello "} {self.props.name.clone()}</p>
            <Button onclick={self.link.callback(|name: String| Message::ChangeName(name))} />
            </div>
        }
    }
}

Copy the code

Declare child components

#[derive(Clone, PartialEq, Properties, Default)]
struct ButtonProperties {
    onclick: Callback<String>,}enum ButtonMessage {
    ChangName,
}

struct Button {
    props: ButtonProperties,
    link: ComponentLink<Self>,}impl Button {
    fn change_name(&mut self) {
        self.props.onclick.emit("is a vegetableChicken".to_string()); }}impl Component for Button {
    type Message = ButtonMessage;
    type Properties = ButtonProperties;

    fn create(props: Self::Properties, link: ComponentLink<Self- > >)Self {
        Self { props, link }
    }

    fn update(&mut self, msg: Self::Message) -> bool {
        match msg {
            ButtonMessage::ChangName => {
                self.change_name(); }};true
    }

    fn change(&mut self, props: Self::Properties) -> bool {
        if self.props ! = props {self.props = props;
            true
        } else {
            false}}fn view(&self) -> Html {
        html! {
        <button onclick={self.link.callback(|_| ButtonMessage::ChangName)}>{"click me"}</button>
        }
    }
}

Copy the code

Demonstration effectWhat does it take to declare a component? From the simple demo above you can see a general idea

  1. Defining the property structure
#[derive(Clone, PartialEq, Properties, Default)]
Copy the code
  1. Attach the property to the state
struct Button {
    props: ButtonProperties,
    link: ComponentLink<Self>,}Copy the code
  1. Initialize the state of the component
fn create(props: Self::Properties, link: ComponentLink<Self- > >)Self {
        Self { props, link }
    }
Copy the code
  1. Initialize the life cycle, accept events in update, and re-render in change
fn update(&mut self, msg: Self::Message) -> bool {
        match msg {
            ButtonMessage::ChangName => {
                self.change_name(); }};true
    }

    fn change(&mut self, props: Self::Properties) -> bool {
        if self.props ! = props {self.props = props;
            true
        } else {
            false}}fn view(&self) -> Html {
        html! {
        <button onclick={self.link.callback(|_| ButtonMessage::ChangName)}>{"click me"}</button>
        }
    }
Copy the code
  1. Custom events need to be registered interactively
impl Button {
    fn change_name(&mut self) {
        self.props.onclick.emit("is a vegetableChicken".to_string()); }}Copy the code

This is similar to the react method we use today (we can also use the EMIT method from vue).

Functional component

Yew’s components are more or less like class components. could yew use a functional component approach? Even using hooks? Sure, let’s implement a simple click counter.

#[derive(Properties, Clone, PartialEq)]
pub struct RenderedAtProps {
    pub time: String,}#[function_component(App)]
fn app() -> Html {
    let (counter, set_counter) = use_state(|| 0);

    let onclick = {
        let counter = Rc::clone(&counter);
        Callback::from(move |_| set_counter(*counter + 1))}; html! { <div> <button onclick=onclick>{"Increment value" }</button>
            <p>
                <b>{ "Current value: " }</b>
                { counter }
            </p>
        </div>
    }
}

#[function_component(RenderedAt)]
pub fn rendered_at(props: &RenderedAtProps) -> Html {
    html! {
        <p>
            <b>{ "Rendered at: " }</b>
            { props.time.clone() }
        </p>
    }
}
Copy the code

Yew can also use various hooks that come with functions in yew, including, but not limited to, the following hooks

  • use_state
  • use_ref
  • use_reducer
  • use_reducer_with_init
  • use_effect
  • use_effect_with_deps

Yew is a Rust framework, but it has very little to do with Rust. Most of the time, we see vue and React in it. It is not very expensive to use, just like we use JavaScript to develop. Everyone knows that JavaScript is based on V8, but don’t we just focus on V8 when programming? The same is true for this framework, which is based on WebAssembly and Rust, but is much smoother to use than we expected

WebAssembly and Javascript

The yew framework was mentioned above, but the question arises again, is it not Rust to learn? I can’t Rust, but I just want to use WebAssembly! I just want to use JavaScript! So what to do? It’s okay. If you can think of it, we all have. There’s another pig’s foot down there

AssemblyScript: Uses Javascript to write webAssemblies

Remember when I introduced Rust above that rust is richer than Typescript? Is the heart itching to see? AssemblyScript Rust’s type system is great, but next thing you know, it’s mine

AssemblyScript Compiles a variant of TypeScript(a typed superset of JavaScript) to WebAssembly using Binaryen, It generates lean and mean WebAssembly modules while being just an npm install away

Typescript is a variant of Typescript that enriches the Typescript type system and can be compiled into WASM files for execution. AssemblyScript can be seen as a mixture of TypeScript’s high-level syntax and C’s low-level features (yes, you can use AssemblyScript to manipulate memory!!). Having said what jit is, a complete and strict type system can make jit much faster. To ensure jit compilation optimizations, and to provide static guarantees for WebAssembly, it is important to avoid JavaScript’s inability to compile dynamically ahead of time. In other words, untyped state does not exist!

/ / 😢
var a = {}
a.prop = "hello world"
/ / 😊
var a = new Map<string,string>()
a.set("prop"."hello world")
/ / 😢
function foo(a?) {
  var b = a + 1
  return b
}

/ / 😊
function foo(a: i32 = 0) :i32 {
  var b = a + 1
  return b
}
/ / 😢
function foo(a: i32 | string): void {
}

/ / 😊
function foo<T>(a: T): void {
}
Copy the code

, of course, at present the language also has many drawbacks, the corresponding ecological also not mature, the language of the target is to be a language for web developers to fit the threshold is very low, but at the same time he is also a need to compile it into WebAssembly as language, which requires it in support there are, on the basis of the characteristics of the development of language, But not in still retain some features of language compiler efficiency under or is blind superstitious binary way more walk more far, it can be said to be the language philosophy, also can saying is the direction of the language Specific usage is not much said, everyone interested can go to study the formation (manual) AssemblyScript official documents in English

Integrated WebAssembly + Javascript + Vite + Vue/React + Rust

How can I use WebAssembly in Vue/React? To go too far, I even used the next generation package build tool, Vite? There is only one answer: yes. Let’s take Vue3 as an example of the technical terms used

  • Vite: Next-generation front-end tool
  • Rust: A language that empowers everyone to build reliable and efficient software
  • WebAssembly: WebAssembly (abbreviated as Wasm) is a binary instruction format for stack-based virtual machines. Wasm is designed as a portable compilation target for programming languages that can be deployed on the Web for both client and server applications.
  • Wasm – Pack: Rust→ WASM Workflow tools!
  • Vite-plugin-rsw: A vite plugin that integrates with the CLI of WASM-pack and generates THE NPM package of WASM to implement file changes, automatic build and hot update.

Step 1: Install the dependencies and configure Vite

# install rsw
npm i -D vite-plugin-rsw
# or
yarn add -D vite-plugin-rsw
Copy the code
// vite.config.ts
import { defineConfig } from 'vite';
import ViteRsw from 'vite-plugin-rsw';
export default defineConfig({
  plugins: [
    ViteRsw({
      crates: [
        '@rsw/hey'.'rsw-test'.// https://github.com/lencx/vite-plugin-rsw/issues/8#issuecomment-820281861
        // outDir: use `path.resolve` or relative path.
        { name: '@rsw/hello'.outDir: 'custom/path'},],}),],});Copy the code

The second step

  1. Configuration of rust
use wasm_bindgen::prelude::*;

// Import the `window.alert` function from the Web.
#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

// Export a `greet` function from Rust to JavaScript, that alerts a
// hello message.
#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
Copy the code
  1. Referenced in a JavaScript module
<template>
  <button @click="greet('webAssembly')">hello wasm</button>
  <button @click="greet2('wasm')">hi wasm</button>
</template>

<script lang="ts">
import init, { greet } from '@rsw/hey';
import init2, { greet as greet2 } from 'rsw-test';
import { ref, defineComponent } from 'vue'

// init wasm
init();
init2();

export default defineComponent({
  name: 'HelloWasm'.setup: () = > {
    return { greet, greet2 }
  }
})
</script>
Copy the code

Of course, this is essentially just writing rust in a Vite +vue3 environment. Using WASM-Bindgen to make rust and JavaScript call each other is not as good as JavaScript, but it is also another development idea

conclusion

It can’t be said that the future will be full of WebAssembly, but it will definitely play an extremely important role in the future. There are various ideas of WebAssembly now, but one thing remains unchanged, the development of WebAssembly must follow the trend of the future. GitHub repositories for WebAssembly, build packaging tools, and development frameworks for WebAssembly are springing up. Rust is the same, and I’m sure these two brothers will shine in the future.