Deno¶
Ryan Dahl, creator of Node.js, officially released Deno in May 2018. This new runtime for JavaScript was designed to fix a long list of inherent problems in Node.js.
Deno is build on:
- Rust (Deno’s core was written in Rust, Node’s in C++)
- Tokio (the event loop written in Rust)
- TypeScript (Deno supports both JavaScript and TypeScript out of the box)
- V8 (Google’s JavaScript runtime used in Chrome and Node, among others)
Deno changed a lot of things in favor for more security and another module and dependency system. It is incompatible in some cases with NodeJS. And at the moment you are better of to build new modules as trying to cross compile them for both.
Security (permissions) in Deno¶
Among the most important of Deno’s features is its focus on security. *As opposed to Node.js, Deno by default executes the code in a sandbox, which means that runtime has no access to:
- The file system
- The network
- Execution of other scripts
- The environment variables
Let’s take a look at how the permission system works.
(async () => {
const encoder = new TextEncoder();
const data = encoder.encode('Hello world\n');
await Deno.writeFile('hello.txt', data);
await Deno.writeFile('hello2.txt', data);
})();
The script creates two text files called hello.txt and hello2.txt with a Hello world message within. The code is being executed inside a sandbox, so it has no access to the file system.
Also note that we are using the Deno namespace instead of the fs module, as we would in Node.js. The Deno namespace provides many fundamental helper functions. By using the namespace, we are losing the browser compatibility, which will be discussed later on.
When we run it by executing:
$ deno run write-hello.ts
⚠️Deno requests write access to "/Users/user/folder/hello.txt". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]
⚠️Deno requests write access to "/Users/user/folder/hello2.txt". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]
We are actually prompted twice since each call from the sandbox must ask for permission. Of course, if we chose the allow always option, we would only get asked once.
If we choose the deny option, the PermissionDenied error will be thrown, and the process will be terminated since we don’t have any error-handling logic.
If we execute the script with the following command:
deno run --allow-write write-hello.ts
There are no prompts and both files are created.
Aside from the --allow-write flag for the file system, there are also --allow-net, --allow-env, and --allow-run flags to enable network requests, access the environment, and for running subprocesses, respectively.
Deno modules¶
Deno, just like browsers, loads modules by URLs.
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
By using URLs, Deno packages can be distributed without a centralized registry such as npm. By importing code via URL, we make it possible for package creators to host their code wherever they see fit — decentralization at its finest. No more package.json and node_modules.
When we start the application, Deno downloads all the imported modules and caches them. Once they are cached, Deno will not download them again until we specifically ask for it with the --reload flag.
Hint
Since it’s not a centralized registry, the website that hosts the module may be taken down for many reasons. Depending on its being up during development — or, even worse, during production — is risky.
As we mentioned before, Deno caches the downloaded modules. Since the cache is stored on our local disk, the creators of Deno recommend checking the cache in your version control system (i.e., git) and keeping it in the repository. This way, even when the website goes down, all the developers retain access to the downloaded version.
Deno stores the cache in the directory specified under the $DENO_DIR environmental variable. If we don’t set the variable ourselves, it will be set to the system’s default cache directory. We can set the $DENO_DIR somewhere in our local repository and check it into the version control system.
Alternatives to URL imports¶
Constantly typing URLs would be very tedious. Thankfully, Deno presents us with two options to avoid doing that.
The first option is to re-export the imported module from a local file, like so:
export { test, assertEquals } from "https://deno.land/std/testing/mod.ts";
Let’s say the file above is called local-test-utils.ts. Now, if we want to again make use of either test or assertEquals functions, we can just reference it like this:
import { test, assertEquals } from './local-test-utils.ts';
So it doesn’t really matter if it’s loaded from a URL or not.
The second option is to create an imports map, which we specify in a JSON file:
{
"imports": {
"http/": "https://deno.land/std/http/"
}
}
And then import it as such:
import { serve } from "http/server.ts";
In order for it to work, we have to tell Deno about the imports map by including the --importmap flag:
deno run --importmap=import_map.json hello_server.ts
Package versioning in Deno¶
Versioning has to be supported by the package provider, but from the client side it comes down to just setting the version number in the URL like so:
https://unpkg.com/liltest@0.0.5/dist/liltest.js
Browser compatibility¶
Deno aims to be browser-compatible. Technically speaking, when using the ES modules, we don’t have to use any build tools like webpack to make our application ready to use in a browser.
However, tools like Babel will transpile the code to the ES5 version of JavaScript, and as a result, the code can be run even in older browsers that don’t support all the newest features of the language. But that also comes at the price of including a lot of unnecessary code in the final file and bloating the output file.
It is up to us to decide what our main goal is and choose accordingly.
TypeScript¶
Deno makes it easy to use TypeScript without the need for any config files. Still, it is possible to write programs in plain JavaScript and execute them with Deno without any trouble.
Compilation¶
Deno has an integrated compiler which makes a single executable with included security settings. It can also cross compile but at the moment won'T support dynamic imports or web worker.
Deno vs. NodeJS¶
g
Performance¶
Comparing the performance of Node.js and Deno is hard due to Deno’s relatively young age. Most of the available benchmarks are very simple, such as logging a message to the console, so we can’t just assume that the performance will stay the same as the application grows.
Because both use the same JavaScript engine, Google’s V8, so there won’t be any difference in performance when it comes to running the JavaScript itself. The only difference that could potentially impact performance is the fact that Deno is built on Rust and Node.js on C++. Deno’s team publishes a set of benchmarks for each release that presents Deno’s performance, in many cases in comparison to Node. As of March 2021, it seems that Node.js performs better when it comes to HTTP throughput and Deno when it comes to lower latency. Overall, the performance is very similar.
Resume¶
At the moment (Mai 2021) Deno shows that it is great, the way is correct but it is not easy to switch large projects to it. So at the moment better stick to NodeJS for applications already working. New applications or modules may be already made for Deno.
It looks like Deno will neither replace NodeJS but be an alternative.