In a JSConf EU presentation held in 2018, the designer of Node, Ryan Dhal spoke about his journey with Node and the shortcomings of the design of it. The goal when designing Node was to focus on event driven HTTP servers. He spoke about some of the decisions he regrets on taking with regard to the design of Node.
Bugs are never so obvious as when you're the one responsible for them.
During the latter part of the presentation, he introduced his new project, Deno which he has created with the support of Bert Belder, and Bartek Iwańczuk to address some of those shortcomings. Version 1.0.0 of Deno was released on the 13th of May 2020.
Before diving right into the features of Deno, let’s go through some of the features and shortcomings of Node.
Features and shortcomings of Node.
Node does not have a security model built into it. V8 itself is a secure sandbox but according to Dhal, node has built holes in it. In other words, every Node script has access to your file system, network and environment. For an example the linter has complete access to write to your file system.
The module system has been designed with centralized distribution. Package.json is the main component of Node. If you require a module it should be resolved in the package.json file with the version to install it. The node_modules does the module resolution.
Module resolution is complicated with node_modules. In node, the require() module does not require the extension of the file. This has been introduced in order to maintain a cleaner code base. However, according to Ryan, this is not practical. Index.js complicated the module loading system but now it has become unnecessary after require supported package.json.
EventEmitter was used instead on which important APIs such as sockets and HTTP are based on but there was a very big issue with this. If you take a TCP socket for an instance, it would emit data events when it received incoming packets. These callbacks would be emitted in an unlimited manner. Node continues to receive new data events but the socket does not have proper back pressure and the sender has does not have a clue if about the server overload and continues to send data. To overcome this issue, a pause() method was added but that meant it required extra code and many programs were flooded with data as this issue is seen when the process is busy.
The biggest regret of Dhal is the build system as it is an important and difficult part of the system. Node uses something called GYP which is a build automation tool. Chrome used to use GYP too but later on abandoned it and went on to use GN. GN is a meta-build system that generates NinjaBuild files. It’s meant to be faster and simpler than GYP. It has been quite a few years since Chrome abandoned it and now only Node uses GYP. V8 does not support GYP out of the box however it has a GYP wrapper for node.
TypeScript or TS is an open source language which builds on JS. The reason why it was developed was that JS was initially introduced as a client-side language. With time it was discovered that it could be used a server side programming language as well. However due to the growth of JS, it became complex and heavy and could not fulfill object oriented programming. This kept it from achieving as an enterprise level server side language. TS was developed to bridge this gap. Node doesn’t support TS directly, it has to be transpiled.
What is Deno, really?
Features and Improvements of Deno
- Deno is a single executable file.
The executable file is all that is required to run any Deno program. The goal is to keep it compact and independent of system libraries. Deno is supported on Mac, Linux and Windows.
Just as a browser would behave, code is executed in a secure sandbox by default. The user must opt in with a command line flag to access the hard disk, open network connections, sub processes or any environmental variables. For an example the following flag allows the script to read from the ‘tmp’ directory.
Sockets are asynchronous and no extra pausing is required to structure the receiving socket properly but this requires users to explicitly read(). “Ops” are bindings that are the lowest layer to the system which is primarily connected to promises. A promise is returned by every async action.
Deno also implements top-level await. It enables developers to use the
await keyword outside of async functions. It acts like a big async function which causes any other modules who
import them to wait before they start evaluating their functions.
- Module imports.
The node_modules,package.json and index.js will not be a requirement anymore as it makes module resolution complicated. It will not depend on a centralized server. The module system will be simple and browser compatible.
An internet connection is not always required to access the URLs. By doing a simple deno fetch, it will be fetched and cached. This cache will not be updated unless it is missing something or if it is user initiated. This enables one to work offline using the downloaded cache.
Deno will include file extensions for all imports. Modules and files are not the same thing in node but in Deno files and modules are made explicit. It does not use package.json in its module resolution algorithm. It uses ‘ES modules’ and does not support
require(). In simple terms, in Deno, a module is a file which is referenced through absolute or relative URLs.
- TypeScript out of the box.
All of Deno’s standard modules are written in TS and it provides first class TS support. The TS compiler is compiled into Deno itself. V8 snapshots are used to start up the TS compiler fast. The purpose of using V8 snapshots is that it loads the code into the memory and serializes the memory into a file which can be used to start up the scripts fast.
This same function is done with the TS compiler itself and the other code built into Deno. The code that is loaded into the memory and serialized is bundled into the Deno executable which reduces the start up time so the TS compiler does not have to be recompiled every time is starts up.
- Rust Integration.
Deno was originally prototyped in Go but now it has evolved into a solid Rust project. Deno is not monolithic like Node, it is a collection of Rust crates. The developers want to allow the users to build their own executable files.
- In-built utilities.
It has in-built utilities such as a code formatter (deno fmt), a dependency inspector (deno info), unit testing and liniting.
- Browser compatibility
Deno is completely new and this does not mean any production apps in Node should be immediately switched into this. It is still under active development but it can be used in demos or other projects to dive into it and get familiarized with it.
It is also important to note that Deno it a completely new implementation and not a fork or continuation of Node. This also does not mean that node will be discontinued because it is still very much in use with a lot of community support because according to Dhal, Deno will never really affect the success of Node.js
Deno maybe a good choice for some applications while it may not be a good choice for some. It may have a different opinion due to lack of compatibility with JS tooling and it will not be compatible with Node packages but there is a possibility of a compatibility layer being built. The developers want to be very clear on the limitations of Deno so people would make proper choices when considering Deno.