Deno 1.29: Custom npm registry support
Deno 1.29 has been tagged and released with the following new features and changes:
- npm compatibility improvements
- REPL changes
- Quality of life improvements
- Changes to
Deno
APIs - TypeScript 4.9
- Changes to the standard modules
If you already have Deno installed, you can upgrade to 1.29 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.
npm compatibility improvements
This release features several npm compatibility improvements and 30+ bug fixes since 1.28.0.
Custom registry support via environment variable
Deno now respects the NPM_CONFIG_REGISTRY
environment variable, which allows
for specifying a custom npm registry.
# change this to a custom registry
> NPM_CONFIG_REGISTRY=https://registry.npmjs.org deno run main.ts
In a future release, there will be support for using different registries per package scope and the ability to set credentials. Follow issue #16105 for updates.
deno install
support
npm specifiers can now be used with
deno install
.
> deno install -A npm:[email protected]
✅ Successfully installed cowsay
C:\Users\david\.deno\bin\cowsay.cmd
C:\Users\david\.deno\bin\cowsay (shell)
> cowsay Hello from deno!
__________________
< Hello from deno! >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
This will additionally create a lockfile for the command on first run to ensure each subsequent run uses the same npm dependency versions.
REPL changes
REPLs are very valuable tools in a developer’s toolchain; allowing for quick experimentation. This release brings a plethora of updates to the REPL:
npm support
You can now use npm packages directly from the REPL. As for other Deno subcommands no prior installation step is required - just import a package and you’re good to go.
$ deno
> import cowsay from "npm:cowsay"
undefined
> console.log(cowsay.say({ text: "hello world" }))
_____________
< hello world >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
undefined
>
deno repl
runs with no permissions by default
Before this release both the deno
and deno repl
commands started the REPL
with full permissions granted. While it’s useful for quick experimentation to
not have to answer permission prompts, it’s somewhat conflicting with Deno’s
“secure by default” story.
This release changes the deno repl
subcommand to have no permissions granted
by default. Permissions can be specified using --allow-*
flags or you can
defer to permission prompt when calling an API that requires a permission:
$ deno repl --allow-write
Deno 1.29.0
Run repl.help() to see help
exit using ctrl+d, ctrl+c, or close()
> Deno.writeTextFileSync("hello.txt", "hello world");
undefined
$ deno repl
Deno 1.29.0
Run repl.help() to see help
exit using ctrl+d, ctrl+c, or close()
> Deno.writeTextFileSync("hello.txt", "hello world");
⚠️ ┌ Deno requests write access to "hello.txt".
├ Requested by `Deno.writeFileSync()` API
├ Run again with --allow-write to bypass this prompt.
└ Allow? [y/n] (y = yes, allow; n = no, deny) > y
✅ Granted write access to "hello.txt".
undefined
To make it clearer, running deno
will show a banner informing that all
permissions are allowed and suggesting to use deno repl
subcommand if you want
to limit permissions:
$ deno
Deno 1.29.0
Run repl.help() to see help
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
>
More reliable history handling
The REPL will now update history file on each executed statement, making history less spotty.
--quiet
flag is now respected
If you use the REPL with --eval
or --eval-file
to build a custom REPL, it
might be undesirable to see the default banner printed on startup. The REPL now
respects the --quiet
flag which will hide any auxiliary output from the REPL:
$ deno --quiet
>
Quality of life improvements
deno init
improvements
The deno init
subcommand was added in the
v1.25 release to allow users
to quickly scaffold a new project (though it’s completely optional). While this
subcommand is very handy, it was also very minimalistic - generating only
main.ts
and main_test.ts
files.
To make it more useful and allow IDEs to discover that we just initialized a new
Deno project, deno init
will also generate a deno.jsonc
file as well as a
main_bench.ts
file.
The output of the subcommand was also refreshed.
deno init
in Deno v1.28:
$ deno init ./my_deno_project
✅ Project initialized
Run these commands to get started
cd ./my_deno_project
deno run main.ts
deno test
deno init
in Deno v1.29:
$ deno init ./my_deno_project
✅ Project initialized
Run these commands to get started
cd ./my_deno_project
// Run the program
deno run main.ts
// Run the program and watch for file changes
deno task dev
// Run the tests
deno test
// Run the benchmarks
deno bench
Thanks to sigmaSd for contributing these improvements.
Config file improvements
Starting with this release you can specify file inclusions and exclusions for
deno bench
, as well as the lockfile inside your configuration file.
Configure deno bench
:
{
"bench": {
"files": {
"include": ["./benches/"],
"exclude": ["./benches/testdata/"]
}
}
}
If you want to use a non-default filename for the lockfile, you can do it like so…
{
"lock": "./lock.file"
}
…or you can disable using lockfile altogether:
{
"lock": false
}
Your IDE should be able to suggest these new options automatically.
Thanks to Geert-Jan Zwiers and @roj1512 for contributing these improvements.
--allow-*
flags used incorrectly
Warning when Deno allows you to opt-in into the sandbox by providing various --allow-*
flags. When executing deno run
, these flags need to come before the script
name, otherwise they are passed to the script itself in Deno.args
.
// example.js
console.log("cli args", Deno.args);
await Deno.writeTextFile("./hello.txt", "hello world");
Before Deno v1.29 you would get such output:
$ deno run example.js --allow-write
cli args [ "--allow-write" ]
⚠️ ┌ Deno requests write access to "./hello.txt".
├ Requested by `Deno.writeFile()` API
├ Run again with --allow-write to bypass this prompt.
└ Allow? [y/n] (y = yes, allow; n = no, deny) >
We found that it’s a common mistake to place permission flags after the script name, so starting with this release, Deno will warn you that this might have been unintentional and suggest how to run the program properly:
$ deno run example.js --allow-write
Permission flags have likely been incorrectly set after the script argument.
To grant permissions, set them before the script argument. For example:
deno run --allow-read=. main.js
cli args [ "--allow-write" ]
⚠️ ┌ Deno requests write access to "./hello.txt".
├ Requested by `Deno.writeFile()` API
├ Run again with --allow-write to bypass this prompt.
└ Allow? [y/n] (y = yes, allow; n = no, deny) >
Thanks to Asher Gomez for contributing this improvement.
Show unresolved promise in top-level await
Deno supports
top-level await
which allows you to use the await
keyword without having to wrap your code in
an async IIFE. This is very useful and ergonomic, but in some situations the
awaited promise never resolves - most often than not, due to a bug in the code:
// example.js
await new Promise((resolve) => {}); // this promise will never resolve!
console.log("hello world");
In such cases, an error was returned and program terminated execution:
deno run example.js
error: Module evaluation is still pending but there are no pending ops or dynamic imports. This situation is often caused by unresolved promises.
While the error suggests what might be the problem, it was up to the user to
read through the code and try to spot where the problem lies. Thanks to a new
v8
API a much nicer error is now shown along with stack
trace of the unresolved promise:
$ deno run example.js
error: Top-level await promise never resolved
await new Promise((_resolve) => {});
^
at <anonymous> (file:///Users/ib/dev/deno/example.js:1:1)
node_modules
and .git
folders by default
Ignore Starting with this release, all built-in Deno tooling will skip node_modules/
and .git/
directories by default. You can run tools like formatter
(deno fmt
) or linter (deno lint
) without having to worry that they will
start crawling through these big directories. You can still opt-in to search
through these directories by specifying them explicitly (eg.
deno fmt node_modules/
).
deno check --remote
flag renamed to --all
There was a discrepancy between the deno run
and deno check
commands where
type checking all the code for deno run
required doing
deno run --check=all main.ts
, but doing the same with deno check
required
using the --remote
flag—deno check --remote main.ts
.
This has now been resolved with --remote
in deno check
being renamed to
--all
, which also includes npm packages. The previous command will still work
fine, but the new one is recommended.
--inspect-wait
CLI flag
New Deno has an ability to connect to debuggers like Chrome DevTools, VSCode and
others. You can do that if you specify either a --inspect
or --inspect-brk
flag. The former will enable the debugger and immediately run your code, while
the latter will enable the debugger, wait for it to connect and stop execution
on the first line of your code.
We received reports that there are situations, where it’s useful to wait for
debugger to connect, but not necessarily break on the first line of user code.
We’re happy to announce that we added a new --inspect-wait
flag, which fills
this requirement - it will wait for debugger session to be established before
running user code, but it will not place a breakpoint on the first line of the
code.
The --inspect-wait
flag, similarly to --inspect
and --inspect-brk
allows
you to provide an optional value with the network address for the debugger to
connect to, like so: --inspect-wait=127.0.0.1:3000
.
Inlay hints are enabled by default in VSCode extension
We added support for inlay hints in Deno v1.27. They were off by default, as we wanted to make sure that everything works fine. We are now confident that this feature is working as expected and we’re happy to announce that the latest release of VSCode extension for Deno now uses inlay hints by default (following default VSCode settings).
If you wish to disable them, you may do so by setting the following settings in your VSCode user settings:
{
"deno.inlayHints.parameterNames.enabled": "none",
"deno.inlayHints.parameterTypes.enabled": false,
"deno.inlayHints.variableTypes.enabled": false,
"deno.inlayHints.propertyDeclarationTypes.enabled": false,
"deno.inlayHints.functionLikeReturnTypes.enabled": false,
"deno.inlayHints.enumMemberValues.enabled": false
}
Alternatively, you could just disable inlay hints everywhere in VSCode by setting:
{
"editor.inlayHints.enabled": "off"
}
Deno
APIs
Changes to Stabilizations:
The following APIs have been stabilized in this release and no longer require
the --unstable
flag to be used:
Deno.TcpConn.setNoDelay()
Deno.TcpConn.setKeepAlive()
Deno.spawn
Removal of unstable The big change in this release is the removal of the unstable Deno.spawn()
,
Deno.spawnSync()
and Deno.spawnChild()
APIs. All of them have been replaced
by a unified Deno.Command
API. Subprocess APIs are hard to design to be both
ergonomic for common tasks and flexible enough when you need low-level control
of the subprocess you are spawning.
Let’s see examples on how to migrate your code:
const { stdout, stderr } = await Deno.spawn("echo", { args: ["foo"] });
// becomes...
const { stdout, stderr } = await new Deno.Command("echo", { args: ["foo"] })
.output();
const { stdout, stderr } = Deno.spawnSync("echo", { args: ["foo"] });
// becomes...
const { stdout, stderr } = new Deno.Command("echo", { args: ["foo"] })
.outputSync();
const child = Deno.spawnChild("cat", { stdin: "piped" });
// becomes...
const child = new Deno.Command("cat", { stdin: "piped" }).spawn();
Deno.Command#.spawn()
is “inherit” by default for stdout and stderr
The unstable Deno.Command
is now “inherit” by default for stdout and stderr
when calling .spawn()
. It remains as “piped” by default when calling
.output()
and .outputSync()
.
// outputs "1\n" to stdout and "2\n" to stderr
new Deno.Command("deno", {
args: ["eval", "console.log(1); console.error(2);"],
}).spawn();
createNew
option for Deno.writeFile
and Deno.writeTextFile
This release adds a createNew
option to Deno.writeFile
,
Deno.writeTextFile
, and the corresponding synchronous APIs.
// ok
await Deno.writeTextFile("file.txt", "some text", { createNew: true });
// error: Deno.errors.AlreadyExists
await Deno.writeTextFile("file.txt", "some text", { createNew: true });
Previously, you would have needed to use the Deno.open
API to get this
functionality, which was overly verbose.
TypeScript 4.9
Deno v1.29 ships with the latest stable version of TypeScript. For more information on new features in TypeScript see TypeScript’s 4.9 blog post
Changes to the standard modules
testing/types
module
Addition of In this release the testing/types
module was added. It is a testing utility
for checking the behaviors of complex types. The module is inspired by and
ported from
Conditional Type Checks
by David Sherret.
import {
assertType,
IsExact,
IsNullable,
} from "https://deno.land/[email protected]/testing/types.ts";
const result = "some result" as string | number;
// compile error if the type of `result` is not exactly `string | number`
assertType<IsExact<typeof result, string | number>>(true);
// causes a compile error that `true` is not assignable to `false`
assertType<IsNullable<string>>(true); // error: string is not nullable
Thanks Lino Le Van for contributing this feature.
Structure changes towards single-export pattern
In the standard modules, multiple APIs are implemented in a single file in some
places. The examples of such modules are bytes
, datetime
, io
, etc. On the
other hand, some modules have the pattern that each exported item is implemented
in a single file (We call this pattern single-export pattern here). The examples
of such modules are collections
, fs
, etc. There wasn’t explicit policy about
which pattern to use for organizing modules so far, but we decided to move to
the latter (single-export) pattern wherever it’s appropriate.
In this release the following 4 modules, archive
, bytes
, io
, and stream
,
are restructured into single-export pattern. As a result, the following paths
are deprecated, and will be removed in later releases (See the deprecation
messages in IDEs for the exact versions of removals). Please update your import
paths if you import from these paths.
std/streams/buffer.ts
std/streams/conversion.ts
std/streams/delimiter.ts
std/io/buffer.ts
(exceptBuffer
class)std/io/files.ts
std/io/readers.ts
std/io/util.ts
std/io/writers.ts
std/archive/tar.ts
(Untar
export is deprecated.)
You can find the updated paths in the search dialog of the homepage.
Thanks Asher Gomez for suggesting and contributing this change.
API renames
The following APIs are renamed in this release. Please update them if you use these APIs directly in your code.
std/dotenv/mod.ts
config
->load
configSync
->loadSync
- Note: the parameters also renamed. Please see the type definition for details.
std/fmt/bytes.ts
prettyBytes
->format
std/fmt/duration.ts
prettyDuration
->format
Thanks Tim Reichen for suggesting and contributing these changes.
If you could see helping ship something in a future release, check out our job postings.