Deno 1.31: package.json support
Deno 1.31 has been tagged and released with the following new features and changes:
package.json
support- Stabilization of Node-API
- Compatibility layer is now part of the runtime
- npm specifiers are supported in remote modules
- Breaking change in FFI API
- Changes to
Deno
APIs - Changes to the command line interface
- Changes to the standard library
- V8 11.0
If you already have Deno installed, you can upgrade to 1.31 by running:
deno upgrade
If you are installing Deno for the first time:
# MacOS and Linux
curl -fsSL https://deno.land/x/install/install.sh | sh
# Windows
iwr https://deno.land/x/install/install.ps1 -useb | iex
Click here for more installation options.
package.json
support
This release brings an exciting new feature - package.json
support. Deno is
now even more accessible, enabling developers to transition from existing Node
projects with ease.
Deno will now automatically detect a package.json
and use it to install and
resolve the dependencies used (ex. import express from "express"
).
Additionally, this enables the ability to run project specific scripts defined
in the scripts
section with deno task
.
Note: currently support for “scripts” is limited to simple scripts. Programs like
rimraf
orcross-env
will not work; we will add support for such programs in an upcoming release.
For an example, say we have the following package.json
:
{
"name": "@deno/my-example-app",
"description": "An example app created with Deno",
"type": "module",
"scripts": {
"say-hello": "cowsay 'Hello from deno!'"
},
"dependencies": {
"chalk": "^5.2"
},
"devDependencies": {
"cowsay": "^1.5"
}
}
With the following script that references chalk via a bare specifier:
// main.ts
import chalk from "chalk";
console.log(chalk.green("Hello from Deno!"));
We can run this script:
> deno run --allow-env --allow-sys main.ts
Hello from Deno!
Or execute package.json scripts via deno task
:
> deno task say-hello
Task say-hello cowsay 'Hello from deno!'
__________________
< Hello from deno! >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
For a more complex example, you can try it yourself by running an example Vite project:
$ deno run -A npm:create-vite vite-project --template vue
$ cd vite-project
$ deno task dev
It is important to note that Deno still supports web-standard import maps, which remain the preferred way to map bare specifiers in Deno.
As always, Deno is committed to making development as smooth and efficient as possible. We are thrilled by the possibilities this feature brings and eagerly await feedback from the community.
Stabilization of Node-API
Deno 1.31 stabilizes the Node-API (aka N-API), which means that the --unstable
flag is no longer needed when using npm packages that rely on Node-API.
Additionally many bug fixes were applied to Node-API and many more packages can now be used without issue. We plan to address remaining bugs in the coming weeks.
Compatibility layer is now part of the runtime
Deno 1.31 brings a significant improvement to the runtime by moving the
compatibility layer for Node.js directly into the Deno runtime itself. In
previous releases, the compatibility for Node.js was provided using
https://deno.land/std/node
- a collection of polyfills implemented in userland
code in Deno’s standard library. With each Deno release, the dependency on
https://deno.land/std
had to be bumped, which resulted in having to download
the compatibility layer after each upgrade. Moreover, this layer is sizeable
(around 1.5Mb), leading to further slowdowns on startup when repeatedly
executing this code.
To address these issues, the Deno team has taken radical steps to improve the situation for users relying on npm packages - either via npm: specifiers or on the newly added package.json auto-discovery. The whole compatibility layer is now embedded in the Deno runtime itself, and V8 snapshots are used to drastically reduce the startup time. This tighter integration enables easier polyfilling of missing APIs, and enhances the performance of already supported built-in Node.js modules.
To use the embedded Node polyfills now, you can import from node: specifiers. For example, to import Node’s fs module, import from node:fs. This change will significantly improve the performance of Deno applications and enable the Deno team to more easily support and enhance the runtime’s compatibility with Node.js.
npm specifiers are supported in remote modules
Previously importing a remote module that depended on an npm package would
require the --unstable
flag. This is no longer necessary.
Try it yourself:
deno run --allow-env --allow-sys https://gist.githubusercontent.com/dsherret/2273fbf9eb3c3ac73b4862cf6633c4cf/raw/442c6cea52f5a292359963a22fdab7fd7e4133ff/main.ts
Breaking change in FFI API
Pointers in Deno have been represented by a pointer number (number or BigInt)
since 1.24, and a custom Deno.PointerValue
type was provided for this. The
type was also used as the type for 64-bit integers.
Starting in Deno 1.31 pointers are now represented as plain objects, or null for
null pointers. These objects are created directly by V8 and supported by V8 Fast
API, meaning that the performance of FFI when working with "pointer"
type
parameters and return values has further improved from previous versions. The
pointer objects are opaque and cannot be manipulated from JavaScript directly.
This means that FFI becomes safer to use, as pointer spoofing is no longer as
easy as writing a JavaScript number.
This is a breaking change to the as-of-yet unstable FFI API. The
Deno.PointerValue
type still exists but now stands for null | PointerObject
,
and 64-bit integer parameters and return values now explicit use the type
number | bigint
. Migrating from the previous version thus means:
- Replacing usage of
Deno.PointerValue
withnumber | bigint
in places where it has been used to mark a 64-bit integer instead of a pointer. - Replacing usage of 0 as null pointers with
null
. - Replacing pointer arithmetic with
Deno.UnsafePointer.offset(pointer, offset)
usage.
In places where a pointer number must be turned into a pointer (eg. getting a
pointer from a TypedArray), use Deno.UnsafePointer.create(address)
.
Deno
APIs
Changes to API stabilizations
This release stabilizes two APIs:
Deno.Command
, and
Deno.osUptime()
. This means
that the --unstable
flag is no longer needed to use these APIs.
We recommend users migrate from the Deno.run()
API to the new Deno.Command
API, as we plan to deprecate Deno.run()
in the future.
Extensions to stable APIs
Deno.build.os
now returns more variants of operating systems:
"darwin" | "linux" | "windows" | "freebsd" | "netbsd" | "aix" | "solaris" | "illumos"
.
While some of these are not officially supported, some users are compiling Deno
themselves and asked for the extended list of operating systems.
Deno.resolveDns()
gets a new signal
option, that allows passing an
AbortSignal
to the API for cancelling an in-flight operation.
const ac = new AbortController();
const promise = Deno.resolveDns("www.example.com", "A", {
nameServer: { ipAddr: "127.0.0.1", port: 4553 },
signal: ac.signal,
});
ac.abort();
Changes to the command line interface
deno bundle
deprecation
The deno bundle command is no longer supported and will not show up in the help
output. While Deno has no immediate plans to remove it, users are encouraged to
switch to other bundling solutions such as deno compile
, deno_emit
, esbuild,
rollup, or others.
It is important to note that bundling JavaScript for browsers is a complex
process with various options and opinions. deno bundle
was not an adequate
solution for browser bundling. Its primary function was to create a
self-contained file for running server-side code in Deno, which has led to
confusion among users.
As Deno continues to support npm and built-in Node modules, supporting deno bundle becomes more difficult. Therefore, given that there are already excellent bundlers in userland, the decision has been made to remove this functionality from the runtime itself.
deno bench
JSON reporter for deno bench
now accepts a --json
flag that will print the benchmark results
as JSON. This allows for programmatic consumption of the results.
Please note that the format is still unstable and might change in the future.
$ deno bench --json bench_me.js
{
"runtime": "Deno/1.31.0 x86_64-apple-darwin",
"cpu": "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz",
"benches": [
"origin": "file:///dev/bench_me.js",
"group": null,
"name": "Deno.UnsafePointerView#getUint32",
"baseline": false,
"result": {
"ok": {
"n": 49,
"min": 1251.9348,
"max": 1441.2696,
"avg": 1308.7523755102038,
"p75": 1324.1055,
"p99": 1441.2696,
"p995": 1441.2696,
"p999": 1441.2696
}
}
]
}
Thanks to Serhiy Barhamon for implementing this feature.
Improvements to permission prompts
Starting with this release, the interactive permission prompt now accepts a new
option A
. This option allows granting permission for all subsequent calls to
APIs using the granted domain.
Example:
$ deno repl
Deno 1.31.0
exit using ctrl+d, ctrl+c, or close()
> Deno.env.get("DENO")
┌ ⚠️ Deno requests env access to "DENO".
├ Run again with --allow-env to bypass this prompt.
└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions) > A
✅ Granted all env access.
undefined
> Deno.env.get("FOOBAR")
undefined
>
Previously this was not possible and the user would have to grant permissions for every single API call that asked for different values than previously requested. This led to having to answer multiple prompts and this change makes it more ergonomic to grant permissions for certain domains.
Thanks to Asher Gomez for implementing this feature.
deno compile
works with statically analyzable dynamic imports
deno compile
now understands dynamic imports that can be resolved at compile
time, ie dynamic imports that take a plain string literal.
// main.ts
const { add } = await import("./add.ts");
console.log(add(1, 2));
// add.ts
export function add(a: number, b: number) {
return a + b;
}
> deno compile main.ts
Compile file:///V:/example/main.ts
Emit example.exe
> ./example
3
deno fmt
Shorter arguments for deno fmt
accepted a handful of options via CLI flags - all of them were in the
form of --options-<option_name>
. This release adds shorthand version of these
flags, that omits the “options” part of the flag name.
Example:
# before
deno fmt --options-line-width=100 --options-use-tabs=true
# after
deno fmt --line-width=100 --use-tabs=true
The old flags are still supported, but they are not included in the help output.
Thanks to aryan02420 for implementing this feature.
Changes to the standard library
The major change in this release of the standard library is the removal of
https://deno.land/std/node
modules. This code was moved to the main deno
repository and is now directly embedded in the Deno runtime. For users who are
relying on https://deno.land/std/node
we recommended to pin the version of std
to the 0.177.0
version (https://deno.land/[email protected]/node/fs.ts
) or by
using the built-in Node module specifiers (import fs from "node:fs"
).
std/http/file_server.ts
has become more efficient in Deno Deploy
std/http/file_server.ts
is the file server implementation in the standard
modules. It can work both in Deno and Deno Deploy thanks to
the compatibility of FS APIs in both
runtimes.
However because of the unavailability of the mtime
property of files in Deno
Deploy, the file server couldn’t return 304
responses to the request to the
same resource, and the site could be slow when it serves the same large
resources a number of times.
In this release, support for the
ETag
header
in the Deno Deploy environment has been added to the file server. It now can
return 304 responses correctly for requests to the same resource, and the site
served by the file server is much optimized.
V8 11.0
This release upgrades to the latest release of V8 (11.0, previously 10.9).