Deno LandDeno

Deno in 2020

January 15th, 2021
Bartek Iwańczuk, Ryan Dahl

With API stabilizations, several large infrastructure refactors, the 1.0 release, and shipping the single most requested feature, 2020 brought a lot of action to the Deno project.

Please fill out the Deno survey to help guide our development in 2021.

Read on for Deno's review of the year.

January: Goodbye libdeno, hello rusty_v8

libdeno was a C++ library that facilitated an interface between V8 engine and Rust code in Deno. The library was hard to reason about and develop additional functionality. The situation led to the birth of rusty_v8 in fall of 2019. rusty_v8 is a Rust crate that provides API for the V8 engine. By December rusty_v8 had all required bindings to replace libdeno. The effort started at the end of 2019, where the first parts of libdeno were rewritten using rusty_v8. Thanks to the growing test coverage in the Deno codebase we were confident moving forward and wrapped up the effort in a fortnight. libdeno was completely removed in release 0.29.0 and since then rusty_v8 has undergone major refactors to type safety of the bindings.

Releases that month:

February: deno fmt now uses dprint, deno test subcommand

This month we changed deno fmt drastically. Up to this point deno fmt was a simple subcommand that under the hood was only an alias to "deno run" that pointed to prettier. It meant that on the first run of deno fmt and after each upgrade, users had to download the latest version of the prettier module. This situation didn’t feel right as Deno promised to provide these tools out of the box. prettier was also pretty slow and the performance left a lot to be asked.

We got introduced to dprint by David Sherret, a code formatter written in Rust and based on the SWC JavaScript parser by Kang Dong Yun. dprint could format the code the same way the prettier module did but it was orders of magnitude faster. After some preliminary testing we decided to use dprint in deno fmt.

deno test had the same requirement of downloading modules from the standard library on the first run. That led to the addition of a new Deno.test() API and deno test CLI subcommand which made testing in Deno first class citizen.

Releases that month:

March: V8 debugger, deno doc, deno upgrade

Missing Chrome Devtools support was a major blocker for the 1.0 release. A lot of effort was spent adding support for V8 debugger and ability to connect to Deno process using Chrome Devtools.

Two new subcommands were added to the CLI:

We also saw a huge improvement to the build process. Up to this point, V8 was built from source for each and every build of Deno. V8 is a massive C++ project that can easily take over 30 minutes to build. Despite lots of build caches and other tricks, it was continuously a difficulty for us to contend with. We added the ability for rusty_v8 to produce and download a pre-built static lib on Github releases, allowing Deno builds to bypass the V8 build completely. This simplified and sped up the build in CI, but most importantly allowed contributors to build Deno more easily.

Releases that month:

April: Break all the APIs for the grand stabilization

This month was spent on reviewing APIs in Deno global in preparation for the 1.0 release. This led to many breaking changes. We were conservative, so any APIs that we were unsure of were moved behind the --unstable flag.

This was the major commitment for the 1.0 release; the Deno APIs marked as stable won’t have breaking changes until 2.0 release.

This month marked the last 0.x.y release of Deno.

Releases that month:

May: Deno 1.0 released

Beginning of the month marked removal of various features:

The reason for removal was that we didn't want to commit to supporting APIs in the current form either because of: lacking underlying specification in case of JSON/WASM imports; or additional maintenance burden in case of Rust API for deno crate.

Finally on May 13, exactly two years after Ryan's original Deno presentation, we cut the 1.0.

On social media, the release was very well received. Our blog post was shared widely, we gained many new users and contributors.

But the dust had barely settled before we were back to work on another major component of the runtime: the dependency analysis in TypeScript host was rewritten using SWC. This change marked the beginning of efforts to rewrite parts of our TypeScript infrastructure in Rust.

Releases that month:

June: Incremental type checking and deno lint

One of major complaints received from community after 1.0 release was that TypeScript compilation and type-checking are extremely slow. There we set our eyes on improving out TSC integration to support incremental typechecking. After a few trial and error PRs we were able to get functionality working and significantly improvement development loop time. Even though we managed to improvement type checking speed by leveraging TSC's incremental APIs we were still relying on it to emit transpiled sources. One of the great design principles of TypeScript is that it's just JavaScript with additional syntax, so stripping out the type information (transpiling to JavaScript) is a relatively easy operation. So we set the goal of being able to use SWC in Rust to do transpilation, while continuing to use TSC for type checking.

After a few months of development out of sight, in a separate repository, a new deno lint subcommand was added. It's yet another project that is built on top of the SWC JavaScript parser.

Releases that month:

July: Converting internal runtime code from TypeScript to JavaScript

This month we made a hard decision to convert our internal runtime code from TypeScript to JavaScript. There were several factors that led us to this decision: Complicated and slow build process on each build of the Deno internal runtime code was typechecked and bundled before being snapshotted. We had two separate implementations of TypeScript compiler host. One just for the build step, which was called the deno_typescript crate. The other one included in the deno binary. Additionally the whole process had a significant impact on the build times: 2 minutes incremental rebuilds! By using plain old JavaScript we were able to vastly simplify the internal build dependencies and overall complexity. Because the actual JavaScript code was produced by TypeScript compiler as a single file bundle, we had very little control of what the output code would look like. ES modules were transformed to use SystemJS loader in the bundle which added significant amount of code to the final bundle.

Releases that month:

August: New registry released

Original post: https://deno.com/blog/registry2

August 3, we released a new deno.land/x registry that uses webhooks to integrate with GitHub. When a module is updated our system downloads and forever preserves the source code, so that we can rely on immutable source code links.

Due to some non-public work happening to use the Deno infrastructure, we began the effort to break the Deno system up into smaller "op crates" which could be mixed and matched to produce custom V8 runtimes. First steps were taken towards this in August, and the deno_web crate was released providing some basic web APIs like Event, TextEncoder, TextDecoder.

This month the benchmark system was rewritten in Rust; which marked the start of tedious efforts of reducing the number of build dependencies for the Deno project.

Releases that month:

September: WebSocket API, CSS styling in console, file watcher, test coverage

This month we shipped our biggest feature release since 1.0. More details in the 1.4.0 blog post.

There was another important change on the maintenance part of the project. The release schedule was changed, from monthly minor release, to shipping new minor release every six weeks, matching the Rust and Chrome projects.

Releases that month:

October: REPL revamp, improved bundling, isolatedModules by default

1.5.0 blog post

The biggest change that happened in this month was enabling isolatedModules option in TypeScript compiler host by default. This setting changes the behavior of TypeScript in such a way that ensures that each file can be transpiled in isolation (without knowledge of types and/or other modules) by tools other than TSC like SWC and Babel. This change had a significant impact on the module ecosystem, making some popular modules unusable until maintainers adjusted the code to work with isolatedModules.

This month we also adopted the new bundle feature in SWC, yet another step in the direction of using Rust over the original TypeScript compiler.

Releases that month:

November: Grand rewrite of TSC compiler infrastructure

This month we saw a conclusion to Kitson Kelly's weeks-long project of rewrite compilation pipeline. It improved the speed of TypeScript transpilation even more, but most importantly paid off a lot of technical debt.

The deno_crypto op crate was added.

Releases that month: 1.5.2, 1.5.3, 1.5.4

December: Self-contained binaries and LSP

1.6.0 blog post

In December we released version 1.6 containing two milestone features: self-contained binaries and the language server. deno compile was single most requested feature in Deno’s bug tracker.

Providing built-in language server allows to provide great development experience to all editors that can talk LSP protocol. It leads to third revamp of vscode_code that is still work-in-progress.

Releases that month:

2021

We've seen a lot of growth in the project and community in 2020. Going into 2021 we feel strongly about momentum behind Deno. Stay tuned for some exciting announcements coming soon!

If you're interested in contributing to Deno or just want to follow our progress please look into the following: