An Introduction to Deno for Node.js Developers

Bookmark

Deno and Node.js have a lot in common. They are both non-browser JavaScript runtimes built on the V8 engine. Deno and Node.js are also different in a lot of ways: TypeScript, CommonJS, package management, permission systems, tooling, native addons, browser compatibility. This talk will compare and contrast the two runtimes, focusing on what experienced Node.js developers need to know in order to succeed with Deno.

by



Transcription


Hi, everybody. Thanks for coming to my talk. Today, I'm going to be talking about getting started with Deno if you are a Node.js developer. So a little bit of personal background on myself. I've been using Node for about 10 years and just recently started working at Deno. So it's been a learning experience trying to switch between these two environments. So I was hoping that this talk could help somebody else who was in my shoes with moving over to Deno. So I guess a little bit of background on both run times. They're both JavaScript run times. They're both built on the V8 engine. Node.js has been around significantly longer since around 2009. And then Deno came out around 10 years after that. The interesting thing about Node.js is that it predates a lot of what we consider to be modern JavaScript. So for example, it still supports CommonJS even though it has ES modules. It still has its legacy callback APIs, even though it now has support for a lot of promise-based APIs. Node has also historically, although it has changed a lot in recent years, taken a kind of defer everything to user land approach. So the idea was that core would be very minimal and that user land would implement MPM modules for a lot of other functionality. I would say that Deno has kind of taken a different approach. It's much more batteries included. It has an integrated tool chain and a number of other things, which I'll talk about later in these slides. Another thing is that Node.js has a huge ecosystem with a lot of legacy code. This can be good and bad. So having a huge ecosystem is nice, but having to support so much legacy code can actually slow down a lot of progress and actually kind of hinder Node's ability to have standards compliance, which is something else I'll get into later in the slides. So the timeline for Deno is roughly shown here. So in June of 2018, Deno was first introduced at JSConf EU. Later that year in August, Deno 0.1.0 was released and it was rewritten in Rust. So initially the native parts of Deno were written in Golang and they were kind of moved over to Rust because there was kind of concern about having multiple languages with garbage collectors running in the same process. So then in May of 2020, Deno 1.0.0 was finally released. So then in March of 2021, the Deno company was announced. So this is nice because having a company backing a project can really help because you can lay out a roadmap, you can allocate workers to work on specific things and just generally have better control of how the project is going to be developed. On the other hand, Node.js is run by almost all volunteers. So we can't really on the Node side control who's going to work on what, we can't tell volunteers to spend their time on certain features. And we've even had initiatives like Node's Benchmarking Working Group, which is doing a lot of useful work have to be wound down because there just was nobody that was working on them at the time. So having a company backing the project is huge in my opinion. So then in June of 2021, Deno Deploy was announced. So Deno Deploy is a very similar runtime to the open source Deno project, except it's meant to be deployed in the cloud. It's more or less a globally distributed JavaScript VM that lets you run JavaScript programs at the edge all over the world. So there's currently 32 different edge locations that are supported. And we're constantly adding more. And it's nice because you can write your code and have it deployed in less than 10 seconds globally. And then in Q3 of this year, we are aiming to get Deno Deploy to general availability. Right now it's still in a public beta. So I wanted to talk quickly about the growth here. So this graph shows GitHub stars for the Deno CLI as well as Node.js. The graph would only generate back to around 2015, even though Node actually goes back to 2009. So that arrow shown there should actually be wider. But GitHub stars are kind of a proxy metric for adoption. Anyone can star a GitHub repository without actually using the project. But we do have some internal metrics that indicate that this growth is real and not just fluff on GitHub. So I think based on the 10 year age difference in the two projects, the difference in stars is really something that is worth kind of noting. Next I want to talk about the core technologies that are under the two projects. So as I said earlier, both of these projects are JavaScript runtimes that are built on top of V8. But that is kind of where the architectural similarities stop. So Deno, their native language is written in Rust, whereas Node.js is written in C++, which makes for an easy wrapping around V8 since V8 is also a C++ project. But Rust is, you know, it's the new hotness and it provides things like memory safety and things like that, that languages like C++ don't. So it's really nice to be able to work in Rust. But it also dictates what some of the other dependencies are going to look like in the project. So for example, Node.js uses libuv for its asynchronous IO and event loop, whereas Deno uses Tokyo. Node.js also uses OpenSSL, whereas Deno uses a project called Rust TLS. On the HTTP side, Node.js uses a project called LLHTTP, whereas Deno uses a couple projects, Typer and Requests, depending on if you're on the client or server side. And then at the DNS level, it's TrustDNS in Deno versus C-ARES in Node.js. So looking a little closer at the Deno architecture. So you can see here we have the V8 project wrapped in something called Rusty V8. So Rusty V8 are the Rust bindings to V8. This is what kind of isolates the C++ code of V8 from all of the other Rust code that's inside of Deno. Everything outside of V8 is going to be in Rust. Rusty V8 also allows you to ship pre-compiled V8s so that you don't have to compile it on your machine from source, which can take a significant amount of time. And then there is something else inside of the Deno core library called DenoOps, which kind of provide an API for interacting with the isolate and the underlying runtime. So all of this is wrapped up in the Deno core crate. All of these crates are available so that you can actually take and mix and match and create your own runtime if you really wanted to. I mentioned Deno deploy earlier. It actually builds off of all of the open source crates, but it does so in a way that the runtime is slightly different because when you're running your local CLI versus running something in the cloud, there are going to be different requirements. And so having a modular approach like this allows you to kind of take advantage of code reuse while still having the different runtimes. So the core project is kind of a minimal JS runtime, but probably not something that you would want to actually use. The core is then wrapped into another crate called the Deno runtime. So the Deno runtime is a much more complete JavaScript runtime. It's more fun to interact with. It includes the core. It includes the Tokyo for the asynchronous IO. And then it also includes a number of other crates that implement various APIs. So some of them are shown here. Deno fetch is used to implement fetch API. Deno crypto does crypto stuff. Deno web is for a lot of web platform compatibility and so on and so forth. And so then once you have the Deno runtime, it goes one step further and that is to the actual CLI itself. So this is the executable that you're going to download and run. Deno is distributed as a single executable. You can go get the crates from the Rust package manager if you really wanted to, but most people are just going to download and install this executable. And you can always rely on that executable being the preferred way to kind of download and install Deno. So the CLI includes the runtime, which I talked about in the previous slide, but it also includes an integrated tool chain. So Deno, as I said earlier, is much more batteries included than Node.js. So you're going to get things out of the box like a linter, a formatter, a test runner, a whole bunch of other things, which I'll talk about later in the slides. And so the idea is that this CLI will have everything that you need to develop and run Deno applications. And this runs on Linux, Mac OS, and Windows. And I have a link here to the getting started docs if you wanted to kind of step through and download and install Deno on your machine. So Deno also has a standard library. So these are going to be JavaScript and TypeScript modules that are kind of built and maintained by the core team. So they're audited and guaranteed to not be stale, not be malware, be maintained and just generally audited to make sure that they work well with Deno. I would say that these are on the Node.js side, similar to Node's core modules, such as FS, HTTP, et cetera. The only difference is that these live outside of the core repository. So they can be versioned independently, released independently, although now they're at the time, currently, they are released when the core runtime is released as well. And so there's a lot of different modules there, things like FS, HTTP, streams, things you'd be used to having in Node, UUIDs, Wazzy, a whole bunch of other stuff. And so you can, there's not really a package manager for Deno, but these modules are hosted on the internet. So if you go to this deno.land slash std, you'll get the latest version of the standard library. And then you can also version these, which is recommended as shown in the example at the bottom here. So if I wanted to import the copy function from the FS library, this is an example of how I would do that while also ensuring that I'm getting version 0.141.0, so that if there is a breaking change or anything else, as the library evolves, you're guaranteed to get a version that you know works with your code. And so talking about general dependency management, it works a lot like a browser. So there's no NPM. We only support ESM. There's no support for CommonJS. There are CDNs like ESM.sh, where you can upload CommonJS modules and they will be transpiled for you so you can import them from there. You're not going to have a package.json file. There's not going to be a node modules. There is no index.js file. So when you do a require, you have to actually specify the file name and not the kind of magical index behavior. And so if you ever use something like Rust, I feel like Deno is kind of similar in the fact that when you run your code, it will actually fetch the code. It'll cache it locally so that you don't have to keep installing it. You can even do some work from an airplane if you need to. And it will compile those things automatically for you. So especially if you're downloading TypeScript, it has to be transpiled and whatnot. But Deno does all of these things for you kind of behind the scenes. And then for production apps, we recommend that you use a command called deno vendor, which will basically download all of your dependencies locally, and then you can add them to source control or manage them however you want, rather than trying to install things at deploy time and production. And as I said, there's no NPM, but there is package hosting at a site called deno.land slash X. So here I'm still showing the example from the previous slide, but if you replace that STD at portion of the URL with X, then you would be kind of using, I guess, the Deno equivalent of NPM. And there's a web interface as well. So you can browse there and see all of the different third party modules that people have created and uploaded. So there is a release schedule. Patch releases come out every week. SEMVer minor releases come out monthly. These releases usually happen on Thursday. There's not a SEMVer major release cadence yet like Node.js has. And there's also not an LTS schedule yet like Node.js has, but I do think that those things will come in time as the project gets more and more mature. So I wanted to quickly look at a Hello World application. So this is only a few lines of code and you can run a full fledged HTTP server. So what I'm doing is I'm importing the serve function from Deno's HTTP standard library module, and then creating a handler that the serve function uses every time it receives a request. So you can see here we have the request as an input parameter. It's prefixed with an underscore because we're not actually using it. And then this function will return a response. And then all we're returning is a very basic Hello World. And then we call the serve function. When we call serve, it'll actually print to the console what port it's listening on. I believe that's 8000 by default. And then the command here, denorun allownet server.ts is all you need to actually run this. And I'll talk about what that allownet is in a second. So some notable features from Deno, focus on web platform compatibility, integrated tool chain as I already mentioned, TypeScript support is provided out of the box. There's a permission system and there is an actual compatibility mode for Node.js code, which I'll get into in a few slides here. So as far as web platform compatibility goes, Deno almost always I would say prefers web platform APIs when possible over rolling their own. So I have a list of some of the web platform APIs that Deno supports here. There are actually even more than this, but they wouldn't fit nicely on a slide. And then on the right side here I have a screenshot of the MDN compatibility web compatibility tables. So this one in particular is for set timeout. And you can kind of see on the far right here, the last two columns are Deno and Node.js. You can see Deno has supported this since version one. Node.js supports set timeout obviously, but it's not really spec compliant. So it returns a timeout object instead of a timeout ID. It doesn't support passing a code string and just different things like that. So web platform compatibility is one of the primary design tenants of Deno and somewhere where I think it really shines. Tooling comparisons. So there are a lot of tools built into Deno. You can run deno dash dash help to see a list of all of the sub commands. But just here I have a comparison of some of the very common ones. So for example, the linter, there's Deno lint as opposed to installing ES lint. Same with prettier, MVM. All these things are just built into Deno. With the exception of the test runner, which Node does have a built in one, but it's only in the latest version of Node. I think Node is starting to come around more to more batteries included. But as of right now, this is kind of what the tooling landscape looks like. TypeScript, as I mentioned, is supported out of the box. The TypeScript compiler is actually snapshotted into the Deno binary. And then SWC, which is the speedy web compiler, it's a JS and TypeScript tool written in Rust that's supposed to be 20 times faster for single threaded applications than Babel is. And I think it's like 70 times faster for multi-threaded. But yeah, all of this stuff is built into the executable. We use that to transpile and bundle and everything like that. You can configure the TypeScript compiler by passing a config file from the CLI. That's typically not needed, so we don't really recommend it. It's just nice to have an out of the box experience that just works. Deno's permission system is by default, Deno is kind of locked down. It can't really access any of the outside world, so it can't talk to the file system, the network, things like that. So we have a list of CLI flags here on the right, which you can use to grant permissions. So if you want to access environment variables, HR time, so high resolution time is behind a CLI flag because it can kind of subject you to timing attacks and things like that. Net for the accessing the network, FFI if you want to load dynamic libraries, read and write or for reading and writing the file system. Run allows you to run child processes. And if you're just testing and you want to grant all of the permissions, then you have the dash dash allow all, which is aliased as dash A. So you have to explicitly grant these permissions as needed. If something is not granted, Deno will actually prompt you for it and ask it at runtime if you want to allow it. One thing to note is if you're running subprocesses or FFI, these things are not going to be restricted using the same sandboxing. So do that with caution. And then some of these flags can actually be further configured. So if I want to read from the file system, but I only want to allow access to a specific directory, I can do that. Or if I want to run a subprocess, but only allow running a specific subprocess, I can do that as well. And these permissions apply to the whole process and not to individual modules. So node compatibility, I took a snippet from the docs here. Basically shows how you can create your own require function and then use that require function just like you would in Node.js. So there is no require in Deno by default, but you can do this using the dash dash compat flag. You also have to specify dash dash unstable because this is still considered an unstable feature. And if you want to use common JS, which is what require is, then you have to actually specify allow read as well. Then I have a bunch of what I think are important links or things that people can go as references and look at. The first link is to the primary documentation site. The second link is for Deno standard library if you want to browse those. Third party modules, the Deno land slash X that I had mentioned earlier is there. The source code for the standard library and the CLI are included at Deno land slash Deno STD and Deno land slash Deno. There is a community discord that's pretty active. So I have the link here if you want to join that. And then Deno deploy, the product, which is also a different runtime and the globally distributed VM, all the things I mentioned earlier. Currently in beta. There's a link here if you want to try it out. It does have a pretty generous free tier. So I would encourage playing around with it. I think it's a pretty nice project. But yeah, that's everything I had. So if you have any questions, feel free to reach out to me on Twitter, GitHub or whatever. My handle is here. Thanks again for coming to my talk.
22 min
20 Jun, 2022

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

Workshops on related topic