Node.js reigned the world of front-end development for a long time. Is its domination about to come to an end? Deno has come to prove that, it is not only possible but probable, that Node will not hold the monopoly of front-end apps.
Of course, Node.js is still a great server-side JavaScript runtime, and will continue to be for a long time. Ryan Dahl, founder of both Node.js and Deno, admits that he has no intention of replacing Node with Deno. His target, in fact, is tackling known issues that Node never addressed, or didn’t address in a timely manner — mainly because of its community. Important factors such as security, modules and dependency management are a bit difficult to deal with in Node. Here are a few ways in which Deno can shine:
- Ships a single executable (
deno).
- Has built-in utilities like a dependency inspector (
deno info
) and a code formatter (deno fmt
). - Has a set of reviewed (audited) standard modules that are guaranteed to work with Deno.
- Scripts can be bundled into a single JavaScript file.
In fact, it was hard to predict such things would be necessary at the time Node was conceived. It was 2009 and JavaScript was far from being what it is today.
Regrets aside, Deno is also a runtime. It’s made on top of Google V8, and 100% TypeScript. It’s written in Rust (against C++ of Node), as well as its event loop (Tokyo, made with Rust too). Despite its inherent TypeScript nature, you can choose if you want just JavaScript and you’ll be fine.
Some of its goals include:
- Only ship a single executable (deno).
- Provide Secure Defaults
- Unless specifically allowed, scripts can’t access files, the environment, or the network.
- Browser compatible: The subset of Deno programs that are written completely in JavaScript and do not use the global
Deno
namespace (or feature test for it), ought to also be able to be run in a modern web browser without change. - Provide built-in tooling such as unit testing, code formatting, and linting to improve the developer experience.
- It does not leak V8 concepts into userland.
- Be able to serve HTTP efficiently
But, in order for you to understand further the pros of Deno, you need to dive into its mains features.
Security
Let’s start with security, one of the main concerns of the big defenders of Deno. Do you remember every time you needed to access a file somewhere or get any information from the current network, etc.? In Node, can do all this with no limitations with no problems at all.
There’s a lot of risks involved in such operations. Anyone with bad intentions could be sniffing out of your network and implant malicious code to steal information from that line of code you forgot in the final project.
With Deno, everything is protected by default. The file system, network, your environment variables and even the execution of other scripts.
Every time you try to access a file from another one, for example, you’d be gently prompted to give permission for such an action. A message like that would appear in your console:
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)]
And this is going to happen for each of your calls unless you select the option “a” (always allow), of course.
In case you select to deny it, an error PermissionDenied would be prompted, terminating the process since Deno identifies it as dangerous action.
If you still want to take the risk, you can disable all that checking through the following command:
deno run --allow-write you-js-file.js
For each of the security treatments, you have a different flag for disabling it:
- –allow-net
- –allow-run
- –allow-write
- –allow-net
Modules
This is one of the main differences. Node developers are used to dealing with a package.json file along with preset dependencies that will be stored in a huge node_modules folder at the root of the project. With Deno, there’s no need for any of this.
Deno works with dependencies the same way browsers do. It loads the modules by URLs.
Take a look at the following code snippet:
import { serve } from "https://deno.land/std@v0.30.0/http/server.ts"; const s = serve({ port: 8000 }); console.log("http://localhost:8000/"); for await (const req of s) { req.respond({ body: "Hello Worldn" }); }
You import directly from the Deno URL and the dependency will be downloaded when the project starts up. This only needs to be done once, since Deno stores it into the global cache.
The rest of the code is just a single JavaScript code (or TypeScript, as you prefer).
With that mechanism, there’s no need for registries and the worries they bring. This way, you can also create and maintain your own packages as you wish and serve them to anyone who wants to consume.
What if we’re offline? Remember that Deno stores the downloaded dependencies in a local cache. Since you’re specifying the version of the dependency (or, at least, stating that you always want the latest), you’ll be safe in case there’s no connection available.
Just to be safer, you can version control your cache too. This way, the dependencies will always be ready to use, with or without the internet. Deno works with a cache directory registered at the $DENO_DIR env variable. You can decide to change it or leave it blank, then Deno will use the default cache system of your OS.
To maintain the list of dependencies in case you don’t want to import them every time in each file, you can create your own map of dependencies:
{ "imports": { "http/": "https://deno.land/std/http/" } }
Then, your import code in the files would be:
import{ serve } from"http/server.ts";
And, finally, Deno needs to know that you’re using a map:
deno run --importmap=my_map.json my_js_file.ts
Simple, isn’t it?
Browser Compatibility
Deno uses the same mechanism of ES modules loading, so it is fully compatible with browsers. When it comes to older versions of browsers that do not support these features, it’s up to you to decide what’s more important.
You won’t have tools like Babel to transpile code to a boilerplate and heavy output, just to make sure it works in old-old browsers. If this is your case, maybe Deno is not for you at this time.
Hello World
Let’s create a simple hello world, just for you to check how Deno works. First, install it properly (again, no need for Node, npm or any other tool):
Using Shell:
curl -fsSL https://deno.land/x/install/install.sh | sh
Using PowerShell:
iwr https://deno.land/x/install/install.ps1 -useb | iex
Using Scoop (Windows):
scoop install deno
Using Chocolatey (Windows):
choco install deno
Using Homebrew (Mac):
brew install deno
Using Cargo:
cargo install deno
Then, inside of your project root folder, create a file called hello.js and place the following content:
console.log('Hello world!')
Then issue the following command at the prompt:
deno -A hello.js
Look at your console, you’ll see how the “Hello world!” message is printed.
Conclusion
Deno is interesting and promising, despite the fact is at the very beginning of its life. Its decentralized nature promises to be disruptive and will certainly increase productivity, and especially decrease conflicts related to package management.
Don’t forget read the official documentation. Also, check out the GitHub repository, which already counts more than 45k stars at the moment of this writing.
About the Author
Diogo Souza works as a Java Developer at PagSeguro and has worked for companies such as Indra Company, Atlantic Institute and Ebix LA. He is also an Android trainer, speaker at events on Java and mobile world.