Deno LandDeno

Deno 1.12 Release Notes

July 13th, 2021
Luca Casonato, Bartek Iwańczuk

Deno 1.12 has been tagged and released with the following features and changes:

If you already have Deno installed, you can upgrade to 1.12 by running

deno upgrade

If you are installing Deno for the first time, you can use one of the methods listed below:

# Using Shell (macOS and Linux):
curl -fsSL https://deno.land/x/install/install.sh | sh

# Using PowerShell (Windows):
iwr https://deno.land/x/install/install.ps1 -useb | iex

# Using Homebrew (macOS):
brew install deno

# Using Scoop (Windows):
scoop install deno

# Using Chocolatey (Windows):
choco install deno

New features

Support for more Web Crypto functions

As announced in the last release blog post this release adds three new capabilities to our web crypto implementation: key generation, signing, and signature verification.

To generate a key:

const keyPair = await crypto.subtle.generateKey(
  {
    name: "RSA-PSS",
    modulusLength: 2048,
    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    hash: { name: "SHA-256" },
  },
  true,
  ["sign", "verify"],
);

Then sign some data:

const data = new TextEncoder().encode("hello world");
const signature = await crypto.subtle.sign(
  { name: "RSA-PSS", saltLength: 32 },
  keyPair.privateKey,
  data,
);

And then verify the signature:

const isValid = await crypto.subtle.verify(
  { name: "RSA-PSS", saltLength: 32 },
  keyPair.publicKey,
  signature,
  data,
);

For more information on the subtle crypto API, view the documentation on MDN.

We are working to enable yet more web crypto APIs in the next release.

Thank you to Divy Srivastava who contributed this feature.

Server side WebSocket support in native HTTP

This release adds support for upgrading incoming HTTP requests on the unstable HTTP server to WebSocket connections. Just like the native HTTP server itself this feature is still unstable and has not yet been thoroughly battle tested. Please report any issues you encounter. Over the last weeks we have fixed all known bugs in the HTTP implementation and are tentatively planning to stabilize the native HTTP API for 1.13.

To upgrade an incoming Request to a WebSocket you use the Deno.upgradeWebSocket function. This returns an object consisting of a Response and a WebSocket object. The returned response should be used to respond to the incoming request using the respondWith method. At this point the WebSocket is activated and can be used.

Because websocket is a symmetrical protocol, the WebSocket object is identical to the one that can be used for client side communication. Documentation for it can be found on MDN. We are aware that this API can be challenging to use, and are planning to switch to WebSocketStream once it is stabilized and ready for use.

Here is an example of how to use the new API:

// https://deno.com/v1.12/ws_server.js

async function handleConn(conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const e of httpConn) {
    e.respondWith(handle(e.request));
  }
}

function handle(req) {
  if (req.headers.get("upgrade") != "websocket") {
    return new Response("not trying to upgrade as websocket.");
  }
  const { websocket, response } = Deno.upgradeWebSocket(req);
  websocket.onopen = () => console.log("socket opened");
  websocket.onmessage = (e) => {
    console.log("socket message:", e.data);
    websocket.send(new Date().toString());
  };
  websocket.onerror = (e) => console.log("socket errored:", e.message);
  websocket.onclose = () => console.log("socket closed");
  return response;
}

const listener = Deno.listen({ port: 8080 });
console.log("listening on http://localhost:8080");
for await (const conn of listener) {
  handleConn(conn);
}

You can run this snippet with deno run --allow-net --unstable https://deno.com/v1.12/ws_server.js. To connect to the websocket, open a Deno REPL and run the following:

> const ws = new WebSocket("ws://localhost:8080/");
  ws.onmessage = (e) => console.log(e.data);
> ws.send("hi");

Thank you to crowlKats who contributed this feature.

REPL gets support for TypeScript and more improvements

This release brings a highly requested feature to the REPL - TypeScript support. Before 1.12, the Deno REPL could only execute JavaScript code. This limited usability of the REPL: if you wanted to copy-paste some TypeScript code in the REPL, it wouldn't work. The only resort was to manually strip out type annotations. With this release, the REPL is able to transpile your TypeScript code (ie. strip types) and execute the resulting JavaScript code on the fly.

Before:

$ deno
Deno 1.11.5
exit using ctrl+d or close()
> function log(message: string) { console.log(message) }
Uncaught SyntaxError: Unexpected token ':'

After:

$ deno
Deno 1.12.0
exit using ctrl+d or close()
> function log(message: string) { console.log(message) }
undefined

Keep in mind that type checking in the REPL is not supported. We are not sure about usability of this feature so if you have some feedback please comment on denoland/deno#11078.

There are also two quality-of-life improvements:

Static import declaration support

Since REPL is run in a "script context" (instead of ES module context) it was not possible to use import ... from ...; syntax there. To further enhance REPL's usability we have added an automatic conversion of static import declarations into dynamic ones.

Before:

$ deno
Deno 1.11.5
exit using ctrl+d or close()
> import { serve } from "https://deno.land/[email protected]/http/server.ts";
Uncaught SyntaxError: Cannot use import statement outside a module

After:

$ deno
Deno 1.12.0
exit using ctrl+d or close()
> import { serve } from "https://deno.land/[email protected]/http/server.ts";
Download https://deno.land/[email protected]/http/server.ts
...
undefined

Tab completion shows a list of possible completions

Tab completions are crucial feature for quick navigation in REPL. Deno has had support for tab completion for several releases, however, candidate completions were shown one-by-one on each tab key press. To improve usability for completion for objects with large number of properties, Deno will now show a list of all possible completions.

Support for MessageChannel and MessagePort

This release once again introduces support for a web platform API: MessageChannel and MessagePort from the Channel Messaging API. This API lets one create two entangled MessagePorts that can be used to copy or transfer complex JavaScript objects between each other. What makes message ports special is that they themselves can be transferred over other message ports and between workers. This allows one to create an arbitrary number of "sockets" between different workers and the main thread that data can be sent and transferred over.

One example of a library that makes use of message ports is comlink. Comlink is a tiny (1.2k gzip’d) library that makes web workers enjoyable by exposing them via a simple RPC interface instead of the rather complicated postMessage API. Here is an example where we expose a simple counter living in a web worker to the main thread using Comlink:

// https://deno.com/v1.12/comlink/main.js

import * as Comlink from "https://cdn.skypack.dev/[email protected]?dts";

// Start a worker with the code in ./worker.js
const url = new URL("./worker.js", import.meta.url);
const worker = new Worker(url, { type: "module" });

// Let comlink wrap this worker to provide a nice API
const obj = Comlink.wrap(worker);

// Call methods and get properties on the object exposed from the worker, as if
// it is a local value.
console.log(`Counter: ${await obj.counter}`);
await obj.inc();
console.log(`Counter: ${await obj.counter}`);

worker.terminate();
// https://deno.com/v1.12/comlink/worker.js

import * as Comlink from "https://cdn.skypack.dev/[email protected]?dts";

// Create the object to expose. It has a counter property, and a method to
// increment that counter.
const obj = {
  counter: 0,
  inc() {
    this.counter++;
  },
};

// Expose the object to the host side using comlink.
Comlink.expose(obj);

You can run this example yourself with deno run --allow-net https://deno.com/v1.12/comlink/main.js.

For more on Comlink + Deno, take a look at this issue: https://github.com/GoogleChromeLabs/comlink/issues/553

Streaming instantiation and async compilation support for WebAssembly

Deno has supported WebAssembly since v1.0.0, however only the buffered instantiation APIs were operational (ie. WebAssembly.compile() and WebAssembly.instantiate()).

In v1.12 we were able to pay off some technical debt that made it possible to support the streaming versions of this API that take a Response or Promise<Response>, and we're happy to announce that WebAssembly.compileStreaming() and WebAssembly.instantiateStreaming() are now fully supported as well.

Thank you to Andreu Botella who contributed this change.

Atomics and SharedArrayBuffer sharing between workers

JavaScript is a language designed to run on a single thread. Because of this all objects, primitives, and functions can only ever be accessed from a single thread. This can sometimes be limiting when using the Web Workers API that allows you to create multiple JS contexts on different threads. These can only communicate with each other by passing cloned messages.

In many other languages you have the ability to share data between threads in a way where it can be modified on one thread with the changes reflected on another thread.

With the introduction of SharedArrayBuffer, JavaScript also got the ability to mutably share data between threads. This also brought along the need for a mechanism to synchronize reads and writes to these buffers: Atomics.

This release enables support for passing SharedArrayBuffer between web workers, and enables support for Atomics. This opens a whole world of possibility to compile C, C++, or Rust code to WebAssembly with support for threading. An example of a project that uses this extensively is ffmpeg.wasm. This is a pure WebAssembly / JavaScript port of the popular FFmpeg library that allows you to convert and process different video and audio formats.

To learn more about webassembly threading, view Ingvar Stepanyan's post on web.dev.

Note that in this release of Deno, SharedArrayBuffers and typed arrays backed by these can not be passed to platform APIs (e.g. fetch, Deno.read, TextDecoder). Support for using SABs in certain platform APIs might be added in a future release of Deno.

FinalizationRegistry and WeakRef now work reliably

V8 added support for FinalizationRegistry and WeakRef APIs over two years ago. These APIs were present in Deno, however we had multiple reports that they don't work properly.

Thanks to paying off the same underlying technical debt as in case of WebAssembly APIs, Deno v1.12 has proper support for finalizers and weak references.

Better debugging support in Chrome DevTools

Deno has built-in debugger capabilities that make it possible to use remote debuggers like Chrome Devtools or the VSCode builtin debugger.

These tools are extremely useful when trying to pin-point bugs or profile your application; and ensuring the full-fledged debugging experience is paramount.

In v1.12 we're bringing two quality-of-life improvements to the Chrome Devtools integration:

Pipe console messages between DevTools and terminal

A long standing issue in the debugger functionality was that console output was not printed to the DevTools console. In v1.12 this has been fixed and logs from console are piped between the terminal and DevTools in both ways, ie. all console logging statements used either from your application code or in the DevTools console will be shown in both your terminal and DevTools.

DevTools console

Chrome Devtools prompt

We've improved prompt shown on about://inspect page to easily distinguish between multiple running Deno processes.

Before:

about://inspect prompt before

After:

about://inspect prompt after

The prompt now includes not only PID of the process but also the main module URL.

Improvements to test runner

This release brings two minor improvements to the deno test subcommand:

--shuffle=<SEED>

A new flag called --shuffle has been added. You can use this flag to execute test cases in random order. This flag is useful in catching unintended execution order dependency between tests, which can often mean non-deterministic tests.

Thank you to Casper Beyer who contributed this feature.

--fail-fast=<N>

deno test supports the --fail-fast flag that stops execution of test suite on first failed test. In this release we added an optional parameter to this flag, that allows specifying a threshold for stopping the execution after N failed tests.

Thank you to Yasser A.Idrissi who contributed this feature.

Add custom proxy support to fetch

Sometimes it is necessary to use an HTTP(S) proxy for outbound requests. Previously you have been able to configure this application wide with the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables. This release adds support for configuring proxies on a per fetch basis.

To do this you have to create a Deno.HttpClient using the unstable Deno.createHttpClient function, and pass this client to fetch in the client parameter of the initializer:

const client = Deno.createHttpClient({
  proxy: {
    url: "http://myproxy.com:8080",
    basicAuth: { username: "deno", password: "***" },
  },
});
const response = await fetch("https://myserver.com", { client });

Thank you to Tomofumi Chiba who contributed this feature.

AbortSignal support in readFile

This release adds support for specifying an abort signal in readFile. This allows you to terminate the reading of a file if it turns out that the file is too large, or takes too long to read.

const aborter = new AbortController();
Deno.readFile("./super_large_file.txt", { signal: aborter.signal })
  .then((data) => console.log("File read:", data.length))
  .catch((err) => console.error("File read failed:", err));
setTimeout(() => aborter.abort(), 1000);

Support for aborting in other APIs may be added in the future.

Thank you to Benjamin Gruenbaum who contributed this feature.

Deprecation of Deno.copy

This release deprecates the Deno.copy utility function in the Deno namespace. The linter will now warn of any uses of this API.

As a replacement you can use the identical copy function from https://deno.land/[email protected]/io/util.ts.

Support types option in TypeScript configuration

Deno supports a limited set of TypeScript options.

This release adds support for the types property, that can be used to include arbitrary type definitions when checking the program.

This option is supported in type checking before program execution, the language server and the unstable Deno.emit() runtime API.

New JavaScript language features

This release upgrades the V8 JavaScript engine Deno builds on to 9.2. This adds support for the following new language features:

at() method on Array, String, and TypedArrays

The at() method returns the value at the given index. The specialty is that at() supports indexing with negative indices:

let arr = [1, 2, 3, 4];
arr.at(-1); // Returns 4

Add dayPeriod option for Intl.DateTimeFormat

A dayPeriod option (part of ECMA402 2021) has been added to the Intl.DateTimeFormat() method so the caller can format times such as "7 in the morning", "11 in the morning", "12 noon", "1 in the afternoon", "6 in the evening", "10 at night" (or in Chinese, "清晨7時", "上午11時", "中午12時", "下午1時", "下午6時", "晚上10時").

Improvements to the language server

This release brings another bag of stability improvements and features to the built-in Deno language server, most notably:

Quick fix actions to ignore deno lint errors

Dependency hover information

Dependency hover information

Deno namespace is now unfrozen and configurable

Prior to this release any changes to the Deno global namespace were not possible as the object was "frozen" after the runtime was bootstrapped.

Starting with v1.12, the Deno global namespace is no longer frozen and is configurable. You can change or delete existing properties or even add new ones:

Before:

$ deno
Deno 1.11.5
exit using ctrl+d or close()
> Deno.someProperty = "foo";
Uncaught TypeError: Cannot add property someProperty, object is not extensible
    at <anonymous>:2:8

After:

$ deno
Deno 1.12.0
exit using ctrl+d or close()
> Deno.someProperty = "foo";
"foo"

This ability shouldn't be over-used, but might come in handy during testing when you find yourself in need of for example mocking a return value from one of net API calls.

Fix concurrent dynamic imports with circular dependencies

This release fixes a long standanding issue in the implementation of ES module loading that could cause hangs or crashes if a user were to try to concurrently dynamically import code with circular dependencies. The exact cases that triggered this failure were very specific, so the bug was likely rarely seen in the wild.

If you interested in more details visit denoland/deno#3736.

Thank you to Nayeem Rahman who contributed this fix.

Web platform compatibility status update

Over the past few months we have been working to closely integrate more and more of the cross browser web platform tests suite into Deno. This test suite is used by Chrome, Firefox and Safari to verify that all engines implement web APIs in the same standardized way.

Every release we are running and passing more and more web platform tests - for example in the url suite we now have better spec compatibility than the latest versions of Chrome and Firefox. You can view our current status and compare compatibility on wpt.fyi.

A huge thanks goes out to Andreu Botella who has contributed many compatibility fixes and WPT runner improvements over the last few weeks.

Q3 2021 roadmap

We outlined planned features and release schedule for Q3 of 2021 in the roadmap issue. Feedback is appreciated.