Maciej Cieślar A JavaScript developer and a blogger @ https://www.mcieslar.com/

What’s Deno, and how is it different from Node.js?

5 min read 1411

What Is Deno?

Ryan Dahl, creator of Node.js, has spent the last year and a half working on Deno, a new runtime for JavaScript that is supposed to fix all the inherent problems of Node.

Don’t get me wrong, Node is a great server-side JavaScript runtime in its own right, mostly due to its vast ecosystem and the usage of JavaScript. However, Dahl admits there are a few things he should have thought about more — security, modules, and dependencies, to name a few.

In his defense, it’s not like he could envision how much the platform would grow in such a short period of time. Also, back in 2009, JavaScript was still this weird little language that everyone made fun of, and many of its features weren’t there yet.

What is Deno, and what are its main features?

Deno is a secure Typescript runtime built on V8, the Google runtime engine for JavaScript.

It 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)

So let’s see what features Deno offers.

LogRocket Free Trial Banner

Security (permissions)

Among the most important of Deno’s features is its focus on security.

As opposed to Node, 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. 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.

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';

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

What about package versioning?

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 support 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.

Summary

Deno, the new runtime for TypeScript and JavaScript, is an interesting project that has been steadily growing for quite some time now. But it still has a long way to go before it’s considered production-ready.

With it’s decentralized approach, it takes the necessary step of freeing the JavaScript ecosystem from the centralized package registry that is npm.

Dahl says that he expects to release version 1.0 by the end of the summer, so if you are interested in Deno’s future developments, star its repository.


Plug: , a DVR for web apps

LogRocket Dashboard Free Trial Banner

 is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.

Maciej Cieślar A JavaScript developer and a blogger @ https://www.mcieslar.com/

9 Replies to “What’s Deno, and how is it different from Node.js?”

  1. Yes would it be possible to get a citation for the Deno team recommending storing the cache in the project directory?

  2. @alastair
    “Relying on external servers is convenient for development but brittle in production. Production software should always bundle its dependencies. In Deno this is done by checking the $DENO_DIR into your source control system, and specifying that path as the $DENO_DIR environmental variable at runtime.”

  3. @Maciej thanks for the reply; I more meant a link to wherever the Deno team recommended storing the cache in the project directory *over* the system’s default cache directory.

    Great article on the whole btw, really interesting stuff.

  4. This is very surprising, it’s like asking to check-in node_modules to avoid dependency issues. Which actually would avoid a ton of issues but it makes the git repository huge and hard to use.

    There are typically tens of thousands of files in node_modules, that’s why we avoid to commit this folder. I wonder how this will work in practice, I actually wouldn’t mind taking longer to clone a repo if it ensures that no-one will run into versioning issues in the project, due to different machines having installed different versions of some library.

  5. I don’t understand these complaints. How is bundling dependencies and cloning them later any different than doing an `npm install`? You have to download these files one way or another…

  6. I guess the difference will be that in npm you are downloading a lot of garbage with every package like readme files etc. In deno on the other hand you will be caching nothing more than minified javascript.

  7. Well, a package represents a artifact, while a repo should only hold source code and configs.

  8. We don’t like package.json, that’s why we are using map JSON file …., We don’t like node_modules, that’s why we are using folder with a different name and store packages in our own repo …,

Leave a Reply