 Hello, Cloud Native Wasm Day Europe. My name is Pierre Hewan. I'm a software engineer on the WebAssembly team at Fastly. Later in this presentation will be joined by my colleague, Guy Bedford. We're sorry we could not be there in person, but we hope you enjoy this recorded presentation. This presentation will mostly be a demonstration of WebAssembly components. After the demonstration, we hope you are as excited about the potential of WebAssembly components as we are. Before we start the demonstration, I wanted to go over some of the terminology you will hear throughout. First, what is a WebAssembly component? A WebAssembly component is a proposed extension of the existing WebAssembly specification. At the heart of most WebAssembly components will be a WebAssembly module implementing that component. As such, WebAssembly components inherit the properties you know and love about WebAssembly modules, namely their portability, their security, and their performance. However, WebAssembly components aren't limited to just integral and floating-point types. They support high-level types like strings, records, variants, resources, and more. WebAssembly components are composable, meaning you can take multiple WebAssembly components, link them together, and treat it as a single WebAssembly component. They're also adaptable, meaning if you have a WebAssembly component that targets a particular execution environment, you can adapt that component to run in another execution environment by linking in other WebAssembly components. Next, what is a world? A world is a description of imports and exports. We use a text format called wit to declare worlds. On the right-hand side, you will see an example of a WASI standard for defining HTTP proxies. This standard is currently under active development. It exports an interface with a handle function on it that receives the request to handle. The request is a resource type, meaning it can be further inspected for the request body, the headers, the path, etc. Worlds might represent the execution environment of a component, so if you author a component that targets a particular world and you have multiple cloud services that might implement that world, you'll know your component can run in those environments. Last, what is a component registry? A component registry is a federated, distributed namespace of WebAssembly components. WebAssembly component registries natively understand the component model. They can parse the components and break them apart for more efficient storage. Additionally, WebAssembly component registries implement what we call package transparency, which is a cryptographically verifiable log of everything that's happened to every package in the registry. On the right, you'll see a diagram of a few tools that might talk to a component registry. You might have componentizer tools that takes user source code and compile it and publish it to a component registry. You might have composing tools that take WebAssembly components to create new WebAssembly components. And then you might have production run times that simply want to download artifacts from a WebAssembly component registry and run them, much like you would a Docker container image today. With this all in mind, let's start the demonstration. To get us started, I will hand us over to Guy. I want to share with you some of the work that's been going on for the WebAssembly JavaScript tool chain for working with components. And there's two sides to this, the consumer side and the producer side. On the consumer side, that's the ability to take an existing JavaScript application, a JavaScript module, and turn it into a WebAssembly component that can be executed in any environment that supports WebAssembly components. Now the side is being able to take existing WebAssembly components that have been created in different environments and run them in JavaScript environments like the browser, and Node.js, and other JS server run times. So for this demo, we're going to be looking at a Svelte server-side rendering demo. And here I have the Svelte template that I'm going to be rendering, and it's got some HTML, some substitutions of props where we've got these two props defined for the template, a little bit of interaction logic and some styling. And the great thing about Svelte for this demo is it's very much a compiled framework. So you compile this single template into the HTML CSS and JavaScript. And in this case, we're going to go a step further, and we're actually going to compile the SSR renderer itself. So we're going to be compiling the SSR renderer that itself is going to be able to take the props, return the rendered HTML, and do the rehydration on the client. So a full SSR workflow will at least very much a demonstration one. Here's the project I've got, and I've got my template, and I'm going to be working on this compiler. So this Svelte compile file I've already written, and that will do all the SSR stuff for us. But the gist of it is that we're passing in this app.svelte file, and we're getting out a JavaScript module which represents the server-side renderer. So it's actually the compiled template in its server-side rendering form. And I'm going to then write that file. This is running in Node.js. I should have a svelte demo.js file written when I run this, containing the JS render source, the JavaScript module that's going to do the SSR. So if I run this compile function I first need to install svelte, of course. And then I can run this compile function, and that will output this svelte demo.js file. So that's our server-side renderer for this app template. And I'm going to then import this svelte demo.js file, and I'm going to create a Node.js server, a very basic server that's just going to call the render method. So it's an app interface that has a render method on it, and we then pass those props. So I'm going to set initial count, and I'm going to say initial name that I'm rendering into that template. To run that template I can run it in Node.js, and let's have a look at it in the browser. So we can see it's rendered the HTML with the initial props, but it's also hydrated it, so it's dynamic, and we've got the wind conditions applying and everything. So how does this relate to components? Well, you can think of this as something that you could want to run an edge application. So how would I do this? Well, I need to be running JavaScript to the edge. I need to boot a whole JavaScript runtime and all the rest. Wouldn't it be nice if we could just set this whole thing instead of as this JavaScript module as a web assembly component? So let's bring in componentized.js, and this is a by-code lines project, experimental.js componentization, and the way it works is it embeds a spider monkey runtime that is optimized for these kind of workflows where you can associate it with a module that's being executed, and it will actually pre-initialize that module to the point where the execution can actually pick up at the point of the function that you're calling, so the edge function. So it's very much a warm boot. Everything's pre-initialized. There's no global initialization happening, that kind of thing. So componentized is a fully native.js toolchain package that we can install and work with in a JS environment. So instead of writing this JS directly, I'm going to now pass it to componentize, and componentize takes, firstly, the JavaScript source that we want to componentize, and then it takes a world definition, which is the WIT world definition that defines that component interface. And in this case, we've got this app interface with its render methods. So we can create the corresponding world as a WIT file here, and this is how you write WIT for WebAssembly components. So we're going to define this world. We're exporting a single app interface called app, and that app interface has a render function, which takes the argument of the props, which contains a name string and account number, and it returns the rendered HTML at the end. And the output of componentize is going to be the WebAssembly component itself. And now we can write that file to the file system at the end of this compilation. So there's going to be svelte.demo.wasm instead of .js. So let's run that with node compile. And there it's completed, and we can see we've got a svelte.demo.wasm file. And that's it. This is now a full WebAssembly component that represents the exact same execution as that JS file that we started with earlier. So we've actually componentized svelte. In this case, we've gone from a svelte template to the componentized version of its edge render. But I'm a JavaScript developer. I don't want to just assume that this component works and send it off or have to test it in the nature runtime. It would be quite nice if I can still, while I'm working with JavaScript in this JavaScript workflow, test it out in Node.js and see if it's working correctly. And for that, we can explore the other side of the component tool chain, which is this project called jco. This is another byte code lines project. And it's a general purpose tool for working with WebAssembly components in JavaScript. With it installed, there is this transpile command that we can use. I'm going to use jco.transfile. And I'm actually going to take that WebAssembly component that we just created svelte.demo.wasm, and I'm going to transpile it into a directory svelte.demo.transfile. And this will actually convert that whole WebAssembly component back into JavaScript, but it will still be using co-wasm when it executes that SpiderMonkey JavaScript engine and the associated JavaScript that we wrapped in. One of the things the SpiderMonkey engine needs is some native bindings or native host functions like timers to be able to time things and things like that. So it does have some wazy bindings. So I'm going to add this other flag, a wazy shim, that'll tell it to use a js shim for the wazy bindings. And with that done, it's fully transpiled and created all the files along with the typings. I'm now going to install the byte code lines preview2shim. This is the js preview2shim of wazy to allow running the preview2-like APIs in Node.js. Again, this is all very experimental, but we'll get this demo running at least. So with everything there, I can go into my serve file. And instead of loading from the js version, I can now load the js version of the wazm that we created. So it's svelte demo, transpiled, and then svelte demo. And apart from that, everything's exactly the same. So I'm going to get an interface that's exactly the same. It's an app interface with a render method. And I can now run this server running components. And here you can see it's fully hydrated in exactly the same way. And it's a fully functional edge application. So now that I've tested it, I can do my Node.js tests. And as a JS developer, I can know that I'm actually writing a component that works. I'm ready to share that component. So to share it, we can now use the warg registry application. And I'm going to publish this into the registry as a release of this component. So this component is called wazm day svelte demo. And the version is 0.1.0. And I'm just going to point it to the Web assembly component that we created for this edge app. And let's publish that to the registry. With it published, my colleague Peter is now able to work with this component and use it in any other runtime that supports components. I'll pass you back every day. Thanks, guy. And now what I want to demonstrate is using the exact same component that Guy just published a component registry from Rust. To do that, I'll be using a tool called cargo component, which is an extension of cargo that allows you to easily build Web assembly components from Rust. To start, I'll be running a cargo component new command, specifying a name of proxy for our component, and that this component will target the wazzy HTTP proxy world. This world defines an interface that allows our component to receive HTTP requests. So let's run this. And we will see we have a proxy directory created with a cargo.toml file on it. If you're a Rust developer, this should look roughly familiar to you, except it has additional metadata in there regarding which world our component targets and what components our component depends on. Cargo component uses this information to generate source code bindings, allowing us to call the imports provided to the component and assist in defining the exports expected of the component from the target world. Let's take a look at the source code generated for us by cargo component. Because we targeted the wazzy HTTP proxy world, it knew it needed to generate an incoming HTTP implementation for our component. This interface has a single method on it called handle, which receives the request that the component should handle. Now let's add a dependency on guy's component from ours. To do that, I'm going to write a cargo component add command, specifying a bindings name as spelled demo, and a package name of wazenday spelled demo. That's the same package name that guy used to publish his package to the registry. So let's run this command, and we can see it contacted the registry to find out that the latest version of this component was 010. That's because we didn't specify a version on the command line to use. If we look in cargo.toml, we can see that the dependencies table has been updated to include a reference to guy's component. Cargo component will use this information to generate the bindings for that render function exported by the component, so we can call it and render our template. Let's switch back to the source code. I'm going to replace it with some demo source code I wrote previously. At the top, you can see the reference to the bindings create that cargo component generated for us, including that render method and references to HTV and streams coming from wazzy. So now our incoming HTTP implementation for our component has the handle method defined in terms of calling the render function from the JavaScript component, passing it a name and account, and then defining an outgoing response with a content type header of text HTML and a status code of 200. It then writes the HTML rendered for us by the JavaScript component to the response stream. Currently, this uses free functions to create this response object. That's because the bindings generation doesn't yet support resource types from the component model. In the near future, the generated code should look a little bit more natural to Rust developers. You can define a struct with methods on it to set these properties. Now let's build this component. I'm going to run a cargo component build command. And as you can see, it generated a proxy.wazm file for us. This is an actual WebAssembly component that can be used in any environment that supports the HTV proxy world. Now to run this component, I'm going to use a tool called viceroy. Viceroy is Fastly's computed edge local testing application. It allows our customers to test their computed edge applications locally before deploying it out to the edge. Currently, this version of viceroy I'm about to show you is from a development branch that supports components, but does not yet support the wazzy HTV proxy world. So what happens if we try to run this with viceroy? Well, we receive an error coming from wazm time, which is the WebAssembly runtime that viceroy uses. And this error informs us that the HTTP import expected of our component was not provided anything. It means that the host viceroy in this case does not offer us an HTTP interface. So it does not support the HTTP proxy world just yet. So how can we run our component in this environment that doesn't support wazzy HTTP proxy? Well, we can leverage some of the power of the component model to solve this problem. To do that, I'm going to use another tool I've written called wasmbuilder.app. And this is a website that allows you to compose new components from other components. To start, I'm going to add the proxy component that we just built to the component library. I'm going to select a color that's a little different from the others so we can see it a little bit easily. To instantiate these components, I simply just drag them to the design service. Here we now have an instance of that proxy component we just built. It imports a stream instance, an HTTP instance, and a svelte demo app instance, and it exports an incoming HTTP instance. You can think of instances as analogous to interfaces. These are interfaces that are being imported and interfaces being exported from this component. So to resolve the dependency on the svelte demo app, I'm going to instantiate the exact same component that guy published to the component registry. This is the JavaScript component he built. It exports an app instance. So I'm going to wire this app instance to my app instance import on my proxy component. And now that dependency is satisfied. However, we still can't run this component in Viceroy because it's importing the streams to HTTP interfaces from WASI, which Viceroy doesn't support yet. So to solve this, I'm going to drag an instance of the HTTP adapter to the design service. And this is a component I wrote previously that imports a FASI interface and exports streams and HTTP, the same ones coming from WASI. So this allows us to wire up a streams and HTTP implementation for our proxy that is defined in terms of the imported FASI interface. This is adapting the FASI interface provided by Viceroy into WASI compatible implementations that proxy can use. This highlights some of the power of the component model because we can adapt and virtualize dependencies inside of our components. So this implementation of WASI is now vocal to this component. The host doesn't know anything about it. So the last piece of the puzzle here is that Viceroy is expecting a command and not a HTTP proxy. It wants a run function exported by the component to call. So I have one additional adapter here called the command adapter. So I'm going to create an instance of that and this command adapter exports a run function. And that's what Viceroy will call to execute the computed edge application. This adapter instance has an import for HTTP incoming handler. And that's the handler that it wants to call and give the request. So I'm going to wire up our proxy export for incoming HTTP to the import of HTTP incoming handler. Last, I'm going to connect these HTTP imports and exports so that the HTTP implementation is shared between the proxy instance and the component adapter instance. Finally, I'm going to check this checkbox, which is just this UI's way of saying that this component's instance is exports, this run function should be exported from the final component. That allows Viceroy to call that run function. So now what I'm going to do is click the download component button and give it a name of composed.lasm. And what this does is it creates a new component based on how we've wired up all these instances internally for this component. So we have a composed.lasm file that just got downloaded for us. So let's see what happens if we try to run this new composed component with Viceroy. Viceroy now starts up successfully because this component imports fastly and exports a run function. We've erased the dependency on those wazzy interfaces that Viceroy does not yet currently support. So this is some of the flexibility of the component model. We can virtualize requirements of a component in terms of other components. So let's see what happens when I open this link. Now we get the exact same Svelte application that Guy demoed earlier, but now it's running in the context of an edge application on a local testing framework called Viceroy. So I can click this button and we get the same wing condition that we had earlier. So that's really cool. So to recap what we just saw, we had a JavaScript component implemented by Guy that was pushed to a component registry. I defined a component in Rust that could easily call into the JavaScript component. I then adapted that component to run an environment that it normally could not run in all using components. So this concludes my demo. Let's switch back to the slides. Now that you've seen the demonstration, we hope you're as excited about the future of the WebAssembly component model as we are. Here are some links to the tools that were shown in the demonstration. For JavaScript, we have componentized JS and JCO, and for Rust, we have cargo component. These tools can be found under the bytecode alliance organization on GitHub. Additionally, the composing prototype I demonstrated is available at wasmbuilder.app. Thank you so much for listening. You can find us on the CNCF Wasm Day Slack following this presentation, but keep in mind it's around 5.45 in the morning, our time, so we might not be fully awake. You can also find us at the bytecode alliance Zulip chat at bytecode alliance Zulipchat.com. Thank you very much, and I hope you have a great Wasm Day.