Deno: A secure JavaScript/TypeScript runtime – At a glance

In today’s web development world, where Python, PHP, and Node.js are still one of the most popular web programming languages, a new JavaScript/TypeScript runtime called Deno is catching up fast. Deno, created by the original creator of Node.js, Ryan Dahl, is offering a more secure environment and provides ease-of-development like Node.js where both the frontend and the backend can be written same in the popular javascript language without being learning a new language.

Deno addresses the design flaws that Node.js has – Promises, Security, The build System (usage of legacy GYP), NPM, etc…

Overview of Deno Ecosystem

At a high level, there are three pillars in Deno Ecosystem:

1) Deno Namespace and its API

These are maintained by the core team. and built into Deno. APIs which are not web standards are exposed through its global namespace Deno. Deno public-facing APIs are considered stable. In the future, it can be expected no major changes that will break your application. So, if we write an application today using those APIs and it should still work in the future as well.

2) Deno Standard Library

Deno provides a set of standard modules that do not have external dependencies and are reviewed by the core team. This Standard Library contains high-quality code guaranteed to work with all Deno projects without any issue. But, at the moment this Library is considered not stable and may change its features in the future. Updates to this library are versioned to avoid unintended and breaking changes.

Deno standard library is available at https://deno.land/std/

3) Third Party Libraries

These libraries’ codes are not built and maintained by the core team but by the various individual or team members. Each library’s stability depends on the individual library. These libraries provide certain great and useful functionalities to Deno.

Deno’s Architecture

Deno has 3 main separate layers:

1) TypeScript Frontend

This layer is an “unprivileged side” as it is running on the V8 sandboxed environment and doesn’t have access to file system, network, or environment access by default. This layer contains all the public interfaces and APIs. Any syscall requires in this layer will have to pass the buffered data as a message through C++ libdeno middleware synchronously or asynchronously.

2) C++ libdeno Middleware

libdeno which is written mostly in C++ acts as the mediator between the TypeScript Frontend layer and the Rust Backend layer. It exposes send and recv API which allows them to communicate between the two frontend end and Rust backend layers. In these layers, V8 isolate instances are initialized and bind c++ functions. Flatbuffers library is used to serialize data to be sent through the message without the overhead of parsing or unpacking.

Synchronous or Asynchronous execution is determined by the sync parameter value of true or false passed into when calling send API from TypeScript Frontend.

3) Rust Backend

This is a “privileged side” and written in Rust has access to the file system, network, and environment access.

Asynchronous is achieved by using Rust async runtime called Tokio which provides a fast, reliable, and scalable event-driven non-blocking I/O.

Deno vs Node.js

Both Deno and Node.js runs on Google’s open-source high-performance V8 javascript engine. Even though both the languages are created for the same purpose, under the hood Deno is written in Typescript, Rust whereas Node.js in C, C++.

Module System

Deno uses the ES6 module for its module system. Unlike Node.js, Deno does not use NPM (Node Package Manager) but uses modules reference as URLs – relative or absolute path, which defines the version to import without the need for providing any sort of unnecessary information as it is the case for package.json – dependencies list, License, Description, Repository.. etc. Below is how info logger can be imported using ES6 module import.

import * as log from "https://deno.land/x/std/log/mod.ts";

log.info(“Hello World!”);

The above remote URL module reference will be stored under the deps folder as subfolders based on URL schema and the path.

/deps/https/deno.land/x/std/log/mod.ts

This is how Deno caches all Remote URL after it is being fetched for the first time and loads from the cached for the subsequent request of the same. The cached can be updated by passing —reload flag in the CLI while running the application.

Static type system

Deno leverages TypeScript (TS) for static type system which offers ease-of-development and provides productivity. The TypeScript compiler is built-in to the Deno. So, Deno internally handles TypeScript configuration for you, but this can be overridable by creating a tsconfig.json file in the project root folder.

Async

Deno uses Tokio to provide a non-blocking, event-driven I/O, Thread pooling platform, whereas Node.js depends on Libuv library.

Promises

Deno uses promise for all async related activities.

Security

Deno comes with security by default. No file, network, or environment access, unless explicitly permissions are granted via CLI flags: —allow-net —allow-write. These security levels allow users to run untrusted third-party modules. Deno also simplifies the design by only allowing system calls to be done through messaging with send and recv native functions.

How to Get Started with Deno?

We will create a simple program to check a given number is a prime number or not. So follow the instruction below to install Deno on your system. The instruction is based on Mac platform and VS code, but for other platforms, it will be more or less the same.

1) Deno Installation:

Open Terminal and type below command:

curl -fsSL https://deno.land/x/install/install.sh | sh

If you get a similar message below, you need to define Deno path and it’s installation folder in bash_profile file.

Deno was installed successfully to /Users/***/.deno/bin/deno
Manually add the directory to your $HOME/.bash_profile (or similar)
  export DENO_INSTALL="/Users/***/.deno"
  export PATH="$DENO_INSTALL/bin:$PATH"
Run '/Users/***/.deno/bin/deno --help' to get started

Type nano ~/.bash_profile  which will open the bash_profile file. Add below lines from your above message and save it.

export DENO_INSTALL="/Users/***/.deno"
export PATH="$DENO_INSTALL/bin:$PATH"

To make the change reflect, reload the changes by typing source ~/.bash_profile. Now, verify Deno installation by typing deno —version. If everything goes well, you will get currently installed Deno, V8, and Typescript version similar to this:

deno 1.1.3
v8 8.5.216
typescript 3.9.2

2) Add Deno support for VS code:

Most of the editors will throw error when importing modules as Deno expects file extension and also supports importing from URL. These are not yet supported by most of the editors. For VS code, an extension is available at Visual Studio Market Place.

3) Your First Deno program

Create a new folder called prime-number for the application we are going to create. Add app.ts file and paste below code in it.

import { sprintf } from "https://deno.land/std/fmt/printf.ts";

/**
 * Check the input number is a prime number
 * 
 * @param {number} num number to test for prime number
 * @return {boolean} returns true if it is a prime number, otherwise false
 */
const isPrimeNum = (num: number): boolean => {
    // Chcek the number has any factor other than 1 and itself
    for(let x: number = 2; x < num; x++){
        if(num % x === 0){
            return false;
        } 
    }

    // The number doesn't have any factor
    // If the number itself is not one, it is prime number
    return num > 1;
}

/**
 * Displays a prompt to the user asking for response
 * 
 * @param {string} txt text to be prompted to the user
 * @return {string} returns user input response 
 */
const prompt = async (txt: string): Promise<string> => {
    console.log(sprintf("%s: ", txt));
    const buf = new Uint8Array(1024);
    const n = <number>await Deno.stdin.read(buf);
    return new TextDecoder().decode(buf.subarray(0, n)).trim();
}

/**
 *   main function  
 */
const init = async ()=>{
    const numInput: string = await prompt("Enter a number")
    const num: number = parseInt(numInput, 10);

    if(isPrimeNum(num)){
        console.log(sprintf("%d is a prime number \n", num));
    } else {
        console.log(sprintf("%d is not a prime number \n", num));
    }
    
    const askInput: string = await prompt("Press 'Y' to continue and 'X' to Exit \n");
    let isExit = false;

    switch(askInput.toLowerCase()){
        // 'Y' option, Repeat the program
        case 'y':
            init();
            break;
        // 'x' option, exit it
        case 'x':
            isExit = true;
            break;
        // For unhandled option
        defualt:
            console.log("Entered key not recognized. Try again \n");
    }

    if(isExit){
        return;
    }
}

// Starts the main function
init();

In the terminal navigate to the prime-number folder and run deno run app.ts

Conclusion

Deno is just 2 years old and looks promising with the security sandboxed, TypeScript built-in, and great tooling available out of the box. But it has not been used for production yet. So let’s wait and see…

If you have any questions or something to share, please drop a comment.

Mapu

I am a technology freak with passion for UI technology.

Leave a Reply