Deno 1.12 Release Notes
Deno 1.12 has been tagged and released with the following features and changes:
- Support
generateKey
,sign
, andverify
web crypto APIs - Websocket support in native HTTP server
- TypeScript support in the REPL
- Support for
MessagePort
andMessageChannel
- Support for WASM threading now available
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/blog/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/blog/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/std@0.101.0/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/std@0.101.0/http/server.ts";
Download https://deno.land/std@0.101.0/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.
MessageChannel
and MessagePort
Support for 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 MessagePort
s 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/blog/v1.12/comlink/main.js
import * as Comlink from "https://cdn.skypack.dev/comlink@4.3.1?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/blog/v1.12/comlink/worker.js
import * as Comlink from "https://cdn.skypack.dev/comlink@4.3.1?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/blog/v1.12/comlink/main.js
.
For more on Comlink + Deno, take a look at this issue: https://github.com/GoogleChromeLabs/comlink/issues/553
WebAssembly
Streaming instantiation and async compilation support for 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, SharedArrayBuffer
s 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.
Chrome Devtools prompt
We’ve improved prompt shown on about://inspect
page to easily distinguish
between multiple running Deno processes.
Before:
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.
fetch
Add custom proxy support to 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.
readFile
AbortSignal support in 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.
Deno.copy
Deprecation of 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/std@0.101.0/io/util.ts.
types
option in TypeScript configuration
Support 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:
deno lint
errors
Quick fix actions to ignore 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.