About Deno
Introduction
Deno is a JavaScript/TypeScript runtime with secure defaults and a great developer experience.
Deno was built with:
- 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)
Feature highlights
- Web compatible where possible, for example through usage of ES modules, and support for
fetch
. - Secure by default. No file, network, or environment access (unless explicitly enabled).
- Supports TypeScript out of the box.
- Ships a single executable (
deno
). - Has built-in utilities like a code formatter (
deno fmt
), a linter (deno lint
), and a test runner (deno test
). - Has a set of reviewed (audited) standard library that are guaranteed to work with Deno.
- Can bundle scripts into a single JavaScript file.
Philosophy
Deno aims to be a productive and secure scripting environment for the modern programmer.
Deno will always be distributed as a single executable. Given a URL to a Deno program, it is runnable with nothing more than the ~25 megabyte zipped executable. Deno explicitly takes on the role of both runtime and package manager. It uses a standard browser-compatible protocol for loading modules: URLs.
Among other things, Deno is a great replacement for utility scripts that may have been historically written with Bash or Python.
Goals
- Ship as just a single executable (
deno
). - Provide secure defaults.
- Unless specifically allowed, scripts can't access files, the environment, or the network.
- Be browser-compatible.
- The subset of Deno programs which 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.
- The subset of Deno programs which are written completely in JavaScript and do not use the global
- Provide built-in tooling to improve developer experience.
- E.g. unit testing, code formatting, and linting.
- Keep V8 concepts out of user land.
- Serve HTTP efficiently.
Why use Deno?
Deno's features are designed to improve upon the capabilities of Node.js. Let's take a closer look at some of the main features that make Deno a compelling alternative to Node.
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
We are prompted with the following:
⚠️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)]
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. Many people got confused at first when they saw an import statement with a URL on the server side, but it actually makes sense --- just bear with me:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
What's the big deal with importing packages by their URLs, you may ask? The answer is simple: by using URLs, Deno packages can be distributed without a centralized registry such as npm
, which recently has had a lot of problems, all of them explained here.
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.
There are a few important questions to be asked here:
What if a website goes down?
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 it in our 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.
Do I have to import it by the URL all the time?
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';
</pre></code>
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
Deno 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.
Deno supports TypeScript out of the box
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.
Is Deno production-ready?
Deno has been steadily growing for quite some time now. Deno v1.0 was officially released on May 13 to much fanfare and has been growing steadily ever since.
The most recent stable release at the time of writing is Deno v1.7.0, published on Jan. 19, 2021. The latest version of Deno features improved compilation and data URL capabilities. Highlights of the new release include the ability to cross-compile from anything in stable, supported architecture (including Windows x64, MacOS x64, and Linux x64) with deno compile
. In addition, deno compile
now generates binaries that are 40--60 percent smaller than those generated by Deno v. 1.6, as well as binaries that have built-in CA certificates, custom V8 flags, locked-down permissions, and more.
Other notable features in Deno v.1.7 include support for data URLs, support for formatting Markdown files with deno fmt
, and a --location
flag to set document location for scripts. Learn more about the most recent updates to Deno.
With its decentralized approach, Deno takes the necessary step of freeing the JavaScript ecosystem from the centralized package registry that is npm.
Comparison to Node.js
Deno does not use
npm
.- It uses modules referenced as URLs or file paths.
Deno does not use
package.json
in its module resolution algorithm.All async actions in Deno return a promise. Thus Deno provides different APIs than Node.
Deno requires explicit permissions for file, network, and environment access.
Deno always dies on uncaught errors.
Deno uses "ES Modules" and does not support
require()
. Third party modules are imported via URLs:import * as log from "https://deno.land/std@0.108.0/log/mod.ts";
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.
One thing we know for sure is that both Node.js and Deno 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.
A common misconception about Deno’s first-class TypeScript support is that it somehow affects runtime performance due to type checking. I couldn’t find where that misconception originated, but, as anyone who knows the first thing about how TypeScript works will tell you, TypeScript only checks types during transpilation. Therefore, there’s no way it could negatively impact any kind of runtime performance. Once we use the bundle command, the output is a single JavaScript file.
All in all, both runtimes are extremely fast and make use of heavy optimizations to deliver the best possible performance. I don’t think either Deno or Node.js will be able to significantly outperform the other.
Should you use Deno instead of Node.js?
Deno's goal is not to be a Node replacement, but an alternative. I would say that the majority of developers are happy with the way Node.js is evolving and aren't really looking to switch things up.
Deno's focus on security and the possibility of bundling the entire codebase into a single file presents a great opportunity for Deno to become the go-to tool for JavaScript developers when it comes to creating utility scripts that may have otherwise been written in languages such as Bash or Python.
If you're trying to decide which one to choose, I would stick with Node. It is mature and stable, so there won't be any unexpected behaviors that could negatively impact the development of an application.
Other key behaviors
- Fetch and cache remote code upon first execution, and never update it until the code is run with the
--reload
flag. (So, this will still work on an airplane.) - Modules/files loaded from remote URLs are intended to be immutable and cacheable.
So that was all you need to know about Deno to get started with Deno. If you need further guidance about installation and other info about Deno you can visit the official site using this link.