Web Assembly (Wasm) Importing Wasm into the Browser
Transcript from the "Importing Wasm into the Browser" Lesson
>> Thing to note, and because I ran into this issue. Actually, let me just demonstrate the issue because you will probably have the same issue. So I'm gonna run a very, very simple server. I have Python installed, I'm using OSX, it has Python installed, most people do. Let me say python-m.
[00:00:16] So load the module, I believe, and I always get this wrong, simpleHTTPserver. Is it a capital? Yeah. Thank you, every single time, I've never once been able to type that out and it's so simple. So let's check this out. Let's fire up in our browser. Let's go to local host 8000.
[00:00:39] It's not really doing anything, because. We forgot to create an actual file to load. So by default, browsers load index.html, in case you didn't know that. So let's create that file, so you have something to look at not just directory of our files. So I'm gonna touch index.html.
[00:01:01] Oops, wrong directory. And we're just gonna create this in a project root touch. Okay, I'll jump back to the Python example because I will make an important point of something you're probably gonna run into because I know I did. But for now, I'm gonna scroll down the notes, I'm jumping ahead a little bit.
[00:01:30] But let's go out here and let's use our WasmLoader class that we just created. And we're gonna try to load this function, and we'll see if it works, it should work, right? I'm definitely not making a point here. But we're gonna need this index.html, and this is how we're gonna load the file, the actual Wasm code.
[00:01:52] So in index.html, I'm just gonna say html. We give it a lots of spaces, we give it a body, no groundbreaking stuff here. All right, so let's load that script. Let's load the script of the loader we just wrote. So we're gonna say the src, the source is /js/loader, cool.
>> Missing an equal sign.
>> Thank you. And add a quote. Yeah, thanks. And let's create a script tag. That's where we're gonna do, most of the heavy lifting. Again, this isn't the most efficient way of doing it, it's just the simplest way. And when all else fails, I prefer the simple way.
[00:02:48] And I'm just gonna call that WasmLoader, We're gonna instantiate our class, which is loaded on this global scope now. And then remember what was the name of our method to install or fetch the wasm file? Was that Wasm, right? Yes, WL.wasm. Then we're gonna give it a path.
[00:03:10] The path is the path of the actual wasm folder and that's our wasm file that's in the build directory. So I'm gonna say /build, and we're gonna load optimize.wasm for now. And that is a promise we can use a wait but I'm just gonna use standard promise syntax, I'm gonna save then.
[00:03:35] And we got an instance out of it. From that instance, we're going to do our magic there. And the instance in this case is the exports from our web assembly. So I'm gonna pull out the function that we wrote, that was called minusOne. And that's from the instance.
[00:04:03] So at this point, minusOne is a call into web assembly itself, and we're gonna run that file. I'm gonna use document.write. Again, don't judge me, you generally don't wanna use document.write for anything. But in this case, because I don't like reading console log all the time, I like to see on page, call it person semantics.
[00:04:27] So I'm gonna use document.write, your browser's probably throw some warnings at you, but it's fine. So I'm gonna say minusOne and I'll say 44, okay? Now we can start the server. And now let's see if we can load this file up. And let me switch over. So we're in local hosts now, and we're just gonna open the inspector to see what's going on.
[00:05:01] This is something you will run into if you're running a basic app. Because if you could look at the docs, and you look on MDM, you look at blogs, everybody is gonna say, You wanna use instantiate streaming. It's the fastest, most efficient way of compiling your web assembly module.
[00:05:20] What a lot of people don't tell you is that instantiate streaming has to return an application type or the content header of application/wasm. Now because we're using a very simple Python HB server, it will just serve out files, it has no idea about application type or content type.
[00:05:39] We can't use instantiate streaming at all, which is kind of frustrating. So instead of doing that, and this is why we're gonna run from a server, we're not just gonna run from the file system directly is because we need to serve out the proper response type. So what we're gonna do, I'm gonna stop this server.
[00:05:57] I'm gonna jump back up, just let you know where I am. We're coming back up here. We're gonna create a server and we're gonna use Express, which is awesome because Express automatically adds the appropriate header when you're serving out Wasms files. So I'm gonna install Express, so npm i -- save express.
[00:06:22] For those who don't know or not familiar, Express is probably one of the more popular servers in NodeJS. It's been around for many years, pretty mature, lots of organizations use it, I use it in most of my projects. So yeah, that's expressed, you're probably familiar with it. I'm sure there's a Frontend Masters Course on Express cuz Frontend Masters has literally a course on everything, it's pretty great.
[00:06:45] All right, so let's create just a very, very basic server. Again, I'm gonna say touchserver.js. And in my server.js, this is the simplest server that I can think of. Shout out if you can create a even smaller server than this, I would give you a lot of props.
[00:07:07] This is five lines, so it's pretty good. So I'm gonna say express and then we're gonna require. The Express Library in, and then we get the app from that. And I wanna make a note that you should not do this in production code, this is extremely dangerous to do.
[00:07:37] But because this is a learning course, we're gonna take some shortcuts. But again, [LAUGH] please if this is the first course you've ever taken, you're like, I learned this from Jim Young, do not do what we're about to do in production, because it is unsafe. So I'm gonna say app.use, and I'm gonna use the Express static plugin that is built-in.
[00:07:58] And I'm gonna use that. Oops, go. And I'm gonna use that to just serve out our file system. So, And then I'm gonna say app.listen, this will start up the server. We're gonna listen on port 3000, it doesn't have to be 3000, just 3000 is usually a default in these cases.
[00:08:27] And I'm just gonna say console.log that the server is running on port 3000. Okay, so what we're doing here is we just created a very, very simple server, and we are serving, sorry, typo there. We're just serving static files from the file system. Now the reason why I said don't do this in production is because you're now exposing all of your files to the Internet.
[00:09:03] So if you had some sort of secrets, or I don't know, some configs that aren't necessarily supposed to be shared out, you'd be sharing them now. We're doing this now for the simplicity of not having to go through pathing and things like that. The paths we're gonna fetch from are just a path from the file system.
[00:09:17] But again, do not use this in production code, is unsafe. Next, because I am lazy, and I don't wanna run node, and this is just a faster way. Let's add a quick script in our package JSON. So we're gonna say server, and then we're gonna say that is the equivalent of node server.js.
[00:09:42] I know we're not, [LAUGH] we're not actually saving that many keystrokes by running npm run server versus node server, it's just for consistency in my scripts. So now if I did everything correctly, I can say npm run server. Cool, and we should see a server running up on port 3000.
[00:10:02] So let's jump back here to our local hosts and 3000. There we go. And now we're using instantiate streaming, which means it's fetching and compiling in streaming form. So versus instantiate, which instantiate has to import the entire file, convert it into a byte array and into an array buffer, and then you can actually instantiate the code.
[00:10:27] Versus doing it this way, it's gonna be much faster. In our case, it doesn't make too much difference because the file we're serving is so small, but Wasm that files are very large because they have a lot of glue code. They do a lot of complex operations. So you want that to load as quickly as possible, so you want to use instantiate streaming wherever possible.
[00:10:47] Again, the caveat is you have to serve it out with a server that understands the application type, otherwise, it won't work. And just because I like to be on the same level, if we look in here, I'm gonna restart the page, we can see it's fetching, and we see the, And the response header, the content type is application/wasm.
[00:11:15] Just you know, we're on the same page.