Deno 1.7 Release Notes
Today we are releasing Deno 1.7.0. This release contains many new features, some stabilizations, and some great improvements to existing APIs and tooling.
- Improvements to
deno compile
: cross compilation, 60% reduction in output size, and more - Support for data URLs: use
data:
URLs in imports and workers - New unstable
Deno.resolveDns
API: query nameservers for DNS records
If you already have Deno installed you can upgrade to 1.7 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
Before reading on, please consider filling out the Deno survey. Even if you’ve never used Deno! It takes only 10 minutes and will help us tremendously in directing our development.
New features and changes
deno compile
Improvements to In the last release we added the ability to compile applications written for
Deno into standalone, self-contained executables. When we initially released
deno compile
in 1.6.0, we had a list of pain points and features we wanted to
address. This release addresses three of these.
We are happy to report that in 1.7 deno compile
can now cross-compile from any
in stable supported architecture (Windows x64, MacOS x64, and Linux x64) to any
other in stable supported architecture. This means you can now create binaries
for Windows and MacOS from a single Linux CI machine.
Additionally, deno compile
now generates binaries that are 40-60% smaller than
those generated by Deno 1.6. To try out this feature, use the --lite
flag when
compiling your application; this tells deno compile
to use a slimmed-down
runtime-only Deno binary instead of the full Deno binary that was used
previously.
Below you can see an example of a simple hello world program being cross compiled for Linux from macOS, then it being run on Linux.
Finally, deno compile
can now create binaries that have built-in CA
certificates, custom V8 flags, locked down Deno permissions, and pre-populated
command line arguments. This should make deno compile
useful to more people.
Here is an example where we create an executable from the std/http/file_server module that listens on port 8080 (instead of default 4507), and has CORS enabled. The permissions that the running code has is also locked down (can only read from current working directory, and can only listen on port 8080).
Support for importing data URLs
Data URLs are a useful tool for executing code generated on the fly. In this release we added support for data URLs in imports (both static and dynamic), as well as in Web Workers. This feature is already supported across all modern browsers and NodeJS.
Here is an example for you to try out:
// main.ts
export const a = "a";
export enum A {
A,
B,
C,
}
Above code can be expressed as following data URL:
"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo="
.
This URL is created by base64 encoding the file contents, and appending it to
data:application/typescript;base64,
. For JavaScript you would append the
contents to data:application/javascript;base64,
.
This import specifier can later be imported like so:
// https://deno.com/blog/v1.7/import_data_url.ts
import * as a from "data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=";
console.log(a.a);
console.log(a.A);
console.log(a.A.A);
Try it:
$ deno run https://deno.com/blog/v1.7/import_data_url.ts
a
{ "0": "A", "1": "B", "2": "C", A: 0, B: 1, C: 2 }
0
Similarly for workers:
// https://deno.com/blog/v1.7/worker_data_url.ts
import { deferred } from "https://deno.land/std@0.83.0/async/deferred.ts";
import { assertEquals } from "https://deno.land/std@0.83.0/testing/asserts.ts";
const promise = deferred();
const tsWorker = new Worker(
`data:application/typescript;base64,${
btoa(`
if (self.name !== "tsWorker") {
throw Error(\`Invalid worker name: \${self.name}, expected tsWorker\`);
}
onmessage = function (e): void {
postMessage(e.data);
close();
};
`)
}`,
{ type: "module", name: "tsWorker" },
);
tsWorker.onmessage = (e): void => {
assertEquals(e.data, "Hello World");
promise.resolve();
};
tsWorker.postMessage("Hello World");
await promise;
tsWorker.terminate();
Deno.resolveDns
API
New unstable This release adds a new Deno.resolveDns
API. It can be used to query DNS
records from a DNS resolver. At the moment only DNS over UDP/TCP is supported
(no DNS over HTTPS nor DNS over TLS). One can specify a custom nameserver (for
example Cloudflare’s 1.1.1.1 or Google’s 8.8.8.8) to use, but by default we will
use the system resolver (e.g. /etc/resolv.conf
on Linux).
The API currently supports A
, AAAA
, ANAME
, CNAME
, MX
, PTR
, SRV
,
and TXT
records. Responses are returned as structured data.
Here is an example for you to try. The example is a very simple version of the
dig
tool on unix. You can pass it a domain name as the first argument, and it
will return the A
records for this domain via stdout.
// https://deno.com/blog/v1.7/dig.ts
const domainName = Deno.args[0];
if (!domainName) {
throw new Error("Domain name not specified in first argument");
}
const records = await Deno.resolveDns(domainName, "A");
for (const ip of records) {
console.log(ip);
}
$ deno run --allow-net --unstable https://deno.com/blog/v1.7/dig.ts deno.land
104.21.18.123
172.67.181.211
Deno.emit
Internal compiler APIs become We have replaced the three unstable APIs (Deno.transpileOnly
, Deno.bundle
,
and Deno.compile
) used to interact with Deno’s built-in TypeScript compiler by
a single improved function (Deno.emit
). You can read all about how to use
Deno.emit
to bundle, transpile, and more in
the TypeScript section of the manual.
deno fmt
Markdown support in deno fmt
now supports formatting markdown files, including formatting of
JavaScript and TypeScript codeblocks in these files.
Additionally a new flag --ext
was added to allow specifying file extension
when formatting code from stdin (deno fmt -
). The available file extensions
are js
, jsx
, ts
, tsx
, and md
. Keep in mind that this flag has no
effect when formatting files on disk.
Here is an example:
# Format files on disk
$ deno fmt docs.md source_code.js source_code2.ts
# Format contents from stdin as Markdown
$ cat docs.md | deno fmt --ext=md -
Align web streams API to spec
This release a lot of effort has gone into aligning our implementations of various web APIs (Text Encoding, URL, Streams, and WASM) to the various specifications for these APIs. This has mostly been internal bug fixes, but in one case specifically there is a rather severe user facing change.
Previously we were implementing Streams API according to the spec from circa
March 2020. In this revision of the spec the ReadableStream
class has a
getIterator
method that can be used to get an async iterator from the
ReadableStream
. In the up-to-date revision the ReadableStream
class is an
async iterator, and the getIterator
method has been removed.
In an effort to move closer to spec, we want to remove the getIterator
method
on ReadableStream
. To give you time to update your usage of this deprecated
API, we have marked the method as deprecated for this release (1.7). We are
planning to remove the deprecated method in Deno 1.8, which is slated to be
released in 6 weeks, on March 2nd 2021.
This deprecated API is used in some std modules (specifically std/async, and
std/http) in versions 0.83.0 or lower. Please upgrade to std version 0.84.0. In
your own code, remove all .getIterator()
calls as shown below:
- for await (const item of body.getIterator()) {
+ for await (const item of body) {
Support for configurable web worker permissions
By default, Deno executes user code in a full sandbox, unless the user passes
--allow-*
flags on the CLI. Unfortunately, those permissions can’t be scoped
to specific modules. Many users have requested this feature, and we are happy to
announce that some progress has been made on this front. Starting with Deno 1.7,
users can spawn Web Workers with custom set of permissions, making it possible
to run untrusted code inside a Deno process.
It is important to know that permissions given to a worker must be a subset of
process permissions, ie. if the process was run without “read” permission then
trying to create worker with “read” permission will result in PermissionDenied
error.
NOTE: This feature is not browser compatible. Browsers will ignore deno
field in the worker option bag.
Here is an example for you to try. It will spawn a worker with the read
permission, which will then try to read the file ./log.txt
and send it back to
the client.
// worker_permissions.ts
const workerUrl = new URL("worker_permissions_worker.ts", import.meta.url).href;
const worker = new Worker(workerUrl, {
type: "module",
deno: {
namespace: true,
permissions: {
read: true,
},
},
});
worker.postMessage({ cmd: "readFile", fileName: "./log.txt" });
// worker_permissions_worker.ts
self.onmessage = async function (e) {
const { cmd, fileName } = e.data;
if (cmd !== "readFile") {
throw new Error("Invalid command");
}
const buf = await Deno.readFile(fileName);
const fileContents = new TextDecoder().decode(buf);
console.log(fileContents);
self.close();
};
Try it:
$ echo "hello world" > ./log.txt
$ deno run --allow-read --unstable https://deno.com/blog/v1.7/worker_permissions.ts
hello world
You can also try run it without the --allow-read
permission. This will cause
an error to be thrown, because you are trying to escalate permissions:
$ deno run --unstable https://deno.com/blog/v1.7/worker_permissions.ts
error: Uncaught PermissionDenied: Can't escalate parent thread permissions
throw new ErrorClass(res.err.message);
^
globalThis.location
and relative fetch
Add support for An unfortunate effect of Deno not having a “document” to run it’s JavaScript in
(a HTML page), is that Deno has never had a good way to determine the origin
of a script. This is important for APIs like window.localstorage
, where the
data you interact with depends on the page (document) you are on. The Local
Storage API is one of many APIs that makes use of the origin, but this one
specifically is one we want to add soon.
This is also very useful for isomorphic code (code that runs on client and
server), for example during server side rendering of React components, because
they can now both make use of globalThis.location
and relative fetch
.
In this release we are addressing this with the addition of the --location
flag that lets you set “document” location for scripts. This location can be any
http
or https
URL (it does not need to exist). If this flag is unset,
window.location
will still be present, but will throw on access. The same goes
for relative URLs in fetch
and new Worker
. They will be relative to the
location if it is set, otherwise they will throw. In workers the location will
always be set to the entrypoint script of the Worker.
$ cat example.ts
console.log(globalThis.location.href);
const res = await fetch("/std/version.ts");
console.log(res.status, res.url);
console.log(await res.text());
$ deno run --location="https://deno.land" --allow-net example.ts
https://deno.land/
200 https://deno.land/std@0.83.0/version.ts
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/** Version of the Deno standard modules
*
* Deno std is versioned differently than Deno cli because it is still unstable;
* the cli's API is stable. In the future when std becomes stable, likely we
* will match versions with cli as we have in the past.
*/
export const VERSION = "0.83.0";
We are aware that some modules use window.location
to determine if they are
running in a browser or not. This is bad practice. Use
typeof Deno !== "undefined"
to determine if you are running in Deno, and use
typeof document !== "undefined"
to determine if the DOM is available or not.
fetch
request body streaming
Support for Next to our support for streaming response bodies in fetch
, we now also
support streaming request bodies. This can be used to upload a large file to a
webserver, without first having to buffer it in memory. This can be done by
passing a ReadableStream
to the body
field in the fetch
options.
import { readableStreamFromAsyncIterator } from "https://deno.land/std@0.84.0/io/streams.ts";
// Open the file we want to upload to the server.
const file = await Deno.open("./large_file_on_disk.txt");
// Construct a `ReadableStream` from the `Deno.Reader` returned by `Deno.open`.
const body = readableStreamFromAsyncIterator(Deno.iter(file));
// Send the body to the server.
const res = await fetch("https://myfileserver.com/upload", {
method: "POST",
body,
});
Currently the only runtimes supporting fetch upload streaming are Chromium and Deno. Both implementations have a limitation where you cannot start receiving the response body until the request body has been fully sent. This is not a limitation in the Fetch specification, rather in the implementations, and will be addressed in the future.
For some more examples and usecases for fetch upload streaming take a look at Jake Archibald’s post on the matter: https://web.dev/fetch-upload-streaming/.
TLS session cache
Some servers require that users reuse existing TLS sessions (for example FTP). Until now Deno has not had the ability to reuse TLS sessions, and instead would re-establish a new TLS session for each connection. In this release we have added a process global TLS session cache that will allow to reuse existing TLS sessions between the connections.
The session cache is an in memory cache with a size of 1024 sessions. Overflow sessions will cause others to be evicted. The TLS session cache is used on a best effort basis.
Changes to Deno APIs
Deno.shutdown()
and Conn#closeWrite()
are stabilized in this release. These
functions are used to gracefully close a connection by signaling to the other
side that you are done sending data. Unlike the unstable version of this API,
the shutdown()
method no longer has a mode
parameter; only the write end of
a socket can be shut down.
Also in this release the signature of the option bag for the unstable
Deno.createHttpClient
API has changed. This API can be used to customize how a
fetch is executed. Instead of being able to specify caFile
(the path to a file
containing a custom CA certificate), you now specify caData
. This means you
can now use in memory certificates for Deno.createHttpClient
.
- const client = Deno.createHttpClient({ caFile: "./my_ca.pem" });
- const res = await fetch("https://my.kubernetes:4443", { client })
+ const client = Deno.createHttpClient({ caData: Deno.readFileSync("./my_ca.pem") });
+ const res = await fetch("https://my.kubernetes:4443", { client })
The unstable Deno.permission
APIs for the net
permission have also changed
slightly. Instead of taking a url
parameter, we now use host
, to match what
the --allow-net
flag supports.
- await Deno.permissions.query({ name: "net", url: "localhost:4000" });
+ await Deno.permissions.query({ name: "net", host: "localhost:4000" });
Improvements to coverage
deno test --coverage
now has the ability to report partially covered lines, as
well as to collect coverage for Deno subprocesses spawned from tests. We will
continue improving coverage capabilities including other report formats in the
upcoming releases.
Tokio 1.0
Deno 1.7 marks the end of long migration from Tokio 0.2 to Tokio 1.0.
Users had previously reported a lot of issue regarding semi-random hangs
occurring in numerous Deno
APIs. After thorough investigation it was
determined that all of them were caused by interaction with the tokio
runtime.
Due to API changes in tokio
1.0 we had to re-architecture significant parts of
deno_core
to cater for those changes. In effect the ResourceTable
, a
structure that holds Rust allocated objects (eg. a file handle, TCP connection)
was rewritten from scratch, adding the ability to queue different “ops” acting
on resources; this means that write
s to the same socket or file are now
guaranteed to happen in the same order as they were started, and so do read
s.
Other news
As mentioned above, we spent a lot of time this release to align our web APIs to the various API specifications. This has been greatly helped by integrating the web platform test suite into our tests. Web platform tests is the test suite that all browser vendors use to test compatibility with the web platform specifications. We have enabled thousands of tests, but we are far from done with this effort (there are still thousands of web platform tests to enable). If you think you can help with this effort, take a look at this issue: https://github.com/denoland/deno/issues/9001.
We would greatly appreciate if you filled out the Deno survey, it takes only 10 minutes and will help us tremendously in further development of Deno.