Deno 1.40: Temporal API
We are excited to announce the release of Deno 1.40, a significant step forward in the evolution of Deno. This new version is packed with features that enhance the Deno experience, introducing the powerful Temporal API for advanced date and time operations, and embracing the latest decorator syntax for more expressive code. Alongside these advancements, we’ve implemented a series of deprecations, stabilizations, and removals aimed at streamlining Deno’s capabilities and preparing for Deno 2.
If you already have Deno installed, upgrade to version 1.40 in your terminal with:
deno upgrade
If you don’t yet have Deno installed, you can install it with one of the following commands, or many other ways.
MacOS / Linux Install
curl -fsSL https://deno.land/install.sh | sh
Windows Install
irm https://deno.land/install.ps1 | iex
Here’s an overview of what’s new in Deno 1.40:
Temporal
APIimport.meta.filename
andimport.meta.dirname
- Decorators
- Simpler
imports
indeno.json
- Deprecations, stabilizations, and removals
- Web API:
rejectionhandled
event - WebGPU windowing / “Bring your own Window”
- Node.js API updates
- LSP improvements
- Better looking diagnostics
deno lint
updates- Changes to how we handle unstable features
Temporal
API
The Temporal
API is designed to
address some of the shortcomings and complexities associated with the existing
Date
object in JavaScript.
Temporal
proposal is actively implemented by all major JavaScript engines and
we’re happy to announce it’s now available in Deno with the
--unstable-temporal
flag.
It’s unlikely that Temporal
API will be changed and we aim to stabilize it in
Deno 2. We encourage you to explore the
Temporal
API docs.
import.meta.filename
and import.meta.dirname
Deno now supports import.meta.filename
and import.meta.dirname
properties.
These properties mirror __filename
and __dirname
properties from the
CommonJS module system:
import.meta.filename
provides the absolute path to the current module fileimport.meta.dirname
provides the absolute path to the directory containing the current module file
Both of these properties are aware of the OS specific path separator and provide proper separators for the current platform:
console.log(import.meta.filename);
console.log(import.meta.dirname);
In Unix:
$ deno run /dev/my_module.ts
/dev/my_module.ts
/dev/
And in Windows:
$ deno run C:\dev\my_module.ts
C:\dev\my_module.ts
C:\dev\
These properties are available only for local modules (ie. modules loaded from
the file system) and are undefined
for remote modules (modules imported from
http://
or https://
).
Decorators
Deno now supports the TC39 stage 3 Decorators proposal, which will soon be implemented in all browsers.
Decorators are a proposal for extending JavaScript classes which is widely adopted among developers in transpiler environments, with broad interest in standardization. TC39 has been iterating on decorators proposals for over five years. This document describes a new proposal for decorators based on elements from all past proposals.
This feature is available in .ts
, .jsx
and .tsx
files. Support in pure
JavaScript is waiting on implementation in V8.
Here is an example of an @trace
decorator that logs out whenever a function is
called, and when it returns:
function trace(fn: any, ctx: ClassMethodDecoratorContext) {
return function (...args: unknown[]) {
console.log("ENTERED", ctx.name);
const v = fn(...args);
console.log("EXITED", ctx.name);
return v;
};
}
class App {
@trace
static start() {
console.log("Hello World!");
}
}
App.start();
If you rely on the legacy “experimental TypeScript decorators”, you can still use them with the following configuration:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Note: There was a bug discovered after v1.40.0 was cut that TypeScript’s
experimentalDecorators
was still turned on in the LSP. Please upgrade to
v1.40.1.
imports
in deno.json
Simpler The imports
field in deno.json
now supports a simpler syntax for specifying
dependencies that have subpath exports. Previously, when wanting to use preact
from npm
, you had to add this to your imports
object in your deno.json
:
{
"imports": {
"preact": "npm:preact@10.5.13",
"preact/": "npm:/preact@10.5.13/"
}
}
This allowed you to import both preact
, and subpath exports, like
preact/hooks
.
In this release we have simplified this, so that you can now just do:
{
"imports": {
"preact": "npm:preact@10.5.13"
}
}
In Deno 1.40.0, this will allow you to import both preact
and preact/hooks
from npm.
Previously Deno considered the imports
field in deno.json
to just be a
regular
import map.
Now, we pre-process the imports
field in deno.json
and expand any entries
with a npm:
prefix on the right hand side into two entries in an internal
import map that we use for resolution.
Deprecations, stabilizations, and removals
As we gear up for Deno 2, we’re committed to refining the runtime while ensuring a smooth transition from Deno 1. While most Deno 1 code will remain compatible, we’re streamlining certain APIs for the platform’s long-term health.
Deprecations
We’re introducing deprecations to phase out older APIs, alongside warnings to assist your migration:
window
– The global variablewindow
is used often across the JavaScript ecosystem to test if code is running in a browser. It is an easy fix to useglobalThis
orself
instead. There is no runtime warning for this deprecation yet, but it will show up indeno lint
in starting this release.Deno.run()
– This is the old and error-prone subprocess API. We have since introduced the much more versatileDeno.Command
API which was stabilized a year ago.Deno.serveHttp()
– Replaced by the faster and simplerDeno.serve()
. Documentation here.Deno.metrics()
– To focus on performance, we’re shifting towards more targeted command-line flags and APIs. Custom metrics implementations are available via op_metrics_factory_fn and a new--strace-ops
flag for runtime ops tracing.Stream-related Functions: Transitioning to Web Streams, we’re deprecating several
Deno.Reader
/Deno.Writer
stream functions. The deprecated functions are still accessible via the Deno standard library:Deno.iter()
andDeno.iterSync()
Deno.copy()
– available at https://deno.land/std/io/copy.tsDeno.readAll()
andDeno.readAllSync()
– available at https://deno.land/std/io/read_all.tsDeno.writeAll()
andDeno.writeAllSync()
– available at https://deno.land/std/io/write_all.tsDeno.Buffer
– available at https://deno.land/std/io/buffer.ts
Deno.FsWatcher.return()
– To align with other async iterators, we’re deprecating this in favor of explicit close methods.Deno.customInspect
– To encourage browser-compatible code, we’ve switched toSymbol.for("Deno.customInspect")
.
In Deno 2, we are removing the concept of “resource ids”. Resource ids are integer references to sockets, files, or other resources managed outside of JavaScript. They’re analogous to file descriptors. However most users do not touch these directly, and we’d like to start introducing resources reference by native JavaScript objects. For this reason we’re deprecating these APIs:
Deno.isatty()
– instead use theisTerminal()
method, for exampleDeno.stdout.isTerminal()
.Deno.close()
– this API also operates onrid
. Users are encouraged to use.close()
method on relevant objects instead. For example,file.close()
rather thanDeno.close(file.rid)
.Deno.resources()
– This API also exposes resource ids and has little utility.Deno.ftruncate()
andDeno.ftruncateSync()
– These function are now avaiable onDeno.FsFile
astruncate()
andtruncateSync()
.
All rid
properties are now deprecated and will be removed in Deno 2.0:
Deno.Conn.rid
Deno.FsWatcher.rid
Deno.TcpConn.rid
Deno.TlsConn.rid
Deno.UnixConn.rid
Deno.Listener.rid
Loading certificates from files is now deprecated, read them yourself instead:
Deno.ListenTlsOptions.certFile
- UseDeno.ListenTlsOptions.cert
andDeno.readTextFile
instead.Deno.ListenTlsOptions.keyFile
- UseDeno.ListenTlsOptions.key
andDeno.readTextFile
instead.Deno.ConnectTlsOptions.certFile
-UseDeno.ConnectTlsOptions.cert
andDeno.readTextFile
instead.
Stabilizations
Following Deno
APIs have been stabilized and un-flagged:
Deno.Conn.ref()
Deno.Conn.unref()
Deno.connect()
forunix
transportDeno.connectTls
Deno.stderr.isTerminal()
Deno.stdin.isTerminal()
Deno.stdout.isTerminal()
Deno.TlsConn.handshake()
Removals
Finally, the unstable API Deno.upgradeHttp
has been removed. This API was
error prone and easy to misuse. We encourage everyone to use
Deno.serve()
and
Deno.upgradeWebsocket()
.
rejectionhandled
event
Web API: We’ve added support for the
rejectionhandled
event,
which is emitted anytime a .catch()
handler is attached to a promise that has
already been rejected. Also, this event will only emitted if you have a
unhandledrejection
event listener that calls event.preventDefault()
(otherwise the promise will be rejected and the process will exit with an
error).
globalThis.addEventListener("unhandledrejection", (event) => {
// Call `preventDefault()` to prevent the process from exiting.
event.preventDefault();
console.log("unhandledrejection", event.reason);
});
globalThis.addEventListener("rejectionhandled", (event) => {
console.log(
"A .catch() handler was added to the promise after it has already rejected.",
event.reason,
);
});
// Create a rejected promise...
const a = Promise.reject(new Error("boom!"));
// ...then attach a `.catch()` handler to after a timeout.
setTimeout(async () => {
a.catch(() => console.log("Added catch handler to the promise"));
}, 10);
$ deno run main.js
unhandledrejection Error: boom!
at file:///dev/main.js:12:26
Added catch handler to the promise
A .catch() handler was added to the promise after it has already rejected. Error: boom!
at file:///dev/main.js:12:26
WebGPU windowing / “Bring your own Window”
We’re introducing a new unstable Deno.UnsafeWindowSurface
API to address
windowing in Deno. Our goal is to provide a windowing solution for WebGPU
without linking to native windowing systems like X11.
This is a low level API that can be used by FFI windowing libraries like
sdl2
, glfw
,
raylib
, winit
and more to
create a WebGPU surface using native window and display handles.
Here’s an example using deno.land/x/sdl2
:
import {
EventType,
WindowBuilder,
} from "https://deno.land/x/sdl2@0.8.0/mod.ts";
const win = new WindowBuilder("Hello, World!", 800, 600).build();
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
/* Returns a Deno.UnsafeWindowSurface */
const surface = win.windowSurface();
/* Returns a WebGPU GPUCanvasContext */
const context = surface.getContext("webgpu");
context.configure({/* ... */});
for (const event of win.events()) {
if (event.type == EventType.Quit) break;
// Sine wave
const r = Math.sin(Date.now() / 1000) / 2 + 0.5;
const g = Math.sin(Date.now() / 1000 + 2) / 2 + 0.5;
const b = Math.sin(Date.now() / 1000 + 4) / 2 + 0.5;
const textureView = context.getCurrentTexture().createView();
const renderPassDescriptor = {
colorAttachments: [
{
view: textureView,
clearValue: { r, g, b, a: 1.0 },
loadOp: "clear",
storeOp: "store",
},
],
};
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
surface.present();
}
Running with deno run --allow-ffi --unstable-webgpu --unstable-ffi
:
Here’s a demo music player app built using this API: https://github.com/littledivy/wgui
For more details on low level use, check out the PR: https://github.com/denoland/deno/pull/21835
Read more about GPUCanvasContext
here.
Node.js API updates
The following built-in Node APIs are now available:
crypto.pseudoRandomBytes()
fs.contants
fs.cp()
fs.cpSync()
fs.promises.cp()
net.ClientRequest.setNoDelay()
net.UdpSocket.ref()
andnet.UdpSocket.unref()
net.WriteStream.isTTY
os.cpus()
os.machine()
process.abort()
process.on("rejectionHandled")
Additionally we fixed several bugs in already supported Node.js APIs:
child_process.ChildProcess.send()
on Windowscrypto.createDeciperiv()
now supportsaes-192-ecb
andaes-256-ecb
fs.promises.readFile()
http.ClientRequest.socket.remoteAddress
http.ClientRequest.socket.remotePort
querystring.stringify()
test
module supports nested testszlib.brotliCompress()
zlib.brotliCompressSync()
zlib.gzipSync()
zlib.unzipSync()
LSP improvements
Since v1.39.0, we’ve strengthened integration with our embedded instance of TypeScript’s Language Service API to achieve significant performance boosts and some bug fixes. Data is exchanged between Rust and the TypeScript isolate more efficiently and less frequently, owing to smarter project-state synchronization and caching.
Quality-of-life improvement for users of the jsxImportSource
compiler option:
The specified remote resource will be cached automatically when the containing
deno.json
file is saved. This was necessary because unlike an uncached import,
the diagnostics resulting from this missing resource were vague and did not
point to the cause of the problem (neither from the perspective of the user nor
the language server’s quick-fix generator).
Auto-import completions will work more consistently. Some cases where the completion resolution would silently error are fixed, due to better state preservation in the TypeScript isolate. Import-mapped NPM specifiers with subpaths are correctly substituted with the expected alias.
Better looking diagnostics
There is a new diagnostic printer in for deno lint
and deno doc
. We’ll be
expanding this to other subcommands in the coming release.
deno lint
updates
Three new rules are available in deno lint
:
no-console
no-self-compare
no-window
The no-window
rule is enabled by default, while the other two are opt-in and
you need to enable them in your configuration file:
{
"lint": {
"rules": ["no-console", "no-self-compare"]
}
}
Maintaining code quality is paramount to the success of your project and we all found ourselves in a situation where we need to suppress a warning from a linter.
In most instances we just ignore a warning and move on, but this approach doesn’t help out team members or future self in understanding why a particular warning was suppressed.
deno lint
now supports additional explanation in // deno-lint-ignore
and
// deno-lint-ignore-file
directives:
// deno-lint-ignore-file -- This file is autogenerated, no need to lint it.
var __global$ = globalThis || (typeof window !== "undefined" ? window : self);
var cu=Object.create;var R=Object.defineProperty;var lu=Object.getOwnPropertyDescriptor;var iu=Object.getOwnPropertyNames;var nu=Object.getPrototypeOf...
// deno-lint-ignore no-empty -- I really need this fn have no body
export function noop() {}
Changes to how we handle unstable features
We’re evolving our approach to managing unstable features. The --unstable
flag, while useful, has been somewhat imprecise, activating all unstable
features simultaneously. In Deno 1.38, we introduced more
granular flags to give you finer
control over specific unstable features, for example --unstable-webgpu
enables
the new WebGPU API. Building on this, Deno 1.40 marks the beginning of the
deprecation phase for the broad --unstable
flag, setting the stage for its
removal in Deno 2.
Additionally, we’ve improved type checking with respect to unstable APIs in
deno check
and the LSP. Now, type definitions for both stable and unstable
APIs are automatically included during type checking. This eliminates the need
to specify --unstable
for accessing unstable API type definitions. However,
remember to enable the specific unstable feature flags when running your
program. Omitting these flags will still lead to errors, ensuring you’re aware
of the unstable features in use.
This change streamlines development, offering more clarity and control over the use of Deno’s feature set.
Thank you to our contributors!
We couldn’t build Deno without the help of our community! Whether by answering questions in our community Discord server or reporting bugs, we are incredibly grateful for your support. In particular, we’d like to thank the following people for their contributions to Deno 1.40: Anwesh, Dean Srebnik, Joel Walker, Jovi De Croock, Julien Cayzac, Jérôme Benoit, Kenta Moriuchi, Kitson Kelly, Lino Le Van, Raashid Anwar, cions, king8fisher, nokazn, 林炳权.
Would you like to join the ranks of Deno contributors? Check out our contribution docs here, and we’ll see you on the list next time.
Believe it or not, the changes listed above still don’t tell you everything that got better in 1.40. You can view the full list of pull requests merged in Deno 1.40 on GitHub here.
Thank you for catching up with our 1.40 release, and we hope you love building with Deno!
🍋 Fresh 1.6 is out.
Fresh v1.6 apps have expanded plugin APIs, faster route matching, and official Tailwind CSS support.