Deno 1.34: deno compile supports npm packages
As we continue our development journey towards Deno 2, this minor release is primarily focused on boosting compatibility with npm and Node.js, enhancing the overall quality of life and developer experience, and establishing the foundation for future performance enhancements.
The most significant updates in this release include three highly anticipated features:
deno compile
supports npm packages- Glob support in
deno.json
and CLI flags - TLS certificates with IP addresses
Besides the aforementioned features, there are many other improvements and bug fixes worth mentioning:
- Configuration file improvements
- Language server improvements
- Deno API changes
- Improvements to npm and Node compatibility
- V8 11.5 and TypeScript 5.0.4
deno compile
supports npm packages
Ever since v1.6, deno compile
has
allowed you to compile your project into a single binary executable. This
development has proven to be substantial for a multitude of reasons, as it
enables developers to:
- distribute and execute binaries on all major platforms without needing to install Deno or dependencies
- include assets inside executable for more portability
- simplify deployment with a single binary
- achieve faster startup time
Since then, we’ve continued to make deno compile
more useful, by
adding support for web workers and dynamic imports,
and today, by supporting npm packages.
Here’s an example creating a single binary executable with cowsay
:
$ cat main.ts
import { say } from "npm:[email protected]";
console.log(say({ text: "Hello from Deno!" }));
$ deno compile --allow-read main.ts
$ ./main
__________________
< Hello from Deno! >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
cowsay
is a simple example, but you can use deno compile
with much more
complex projects. Let’s try vite
:
$ deno compile --allow-read --allow-write --allow-env --allow-net npm:vite
$ ./vite
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
Or maybe eslint
?
$ deno compile --allow-read --allow-write --allow-env --allow-net npm:eslint
$ cat .eslintrc.js
module.exports = {
"env": {
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
}
}
$ cat foo.js
function foo() {
}
$ ./eslint
/dev/foo.js
1:10 error 'foo' is defined but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
The difference between using deno compile
to create an eslint
binary and
npm install -g eslint
is that Deno packages eslint
with all of its
dependencies and configurations alongside the actual deno
executable. This
means that the produced executable ensures its dependencies will not be changed
by accident and continue working the same way without interference from other
dependencies on your system. Additionally, our testing suggests the binaries
from deno compile
tend to start up faster than executing the same program with
dependencies cached locally.
There’s more work to improve deno compile
, including minimizing total binary
size, which we intend to address in upcoming releases.
Do you specific feedback on deno compile
?
Let us know.
deno.json
and CLI flags
Glob support in Globs are now supported in
the configuration file deno.json
, deno task
, and CLI arguments for
specifying files. The glob syntax is cross platform, so you can confidently use
it on Windows, macOS, and Linux.
In deno.json
, you can use *
to match any number of characters in a path,
?
to match a single character, and **
to match any number of directories:
{
"fmt": {
"include": ["data/example?.txt"],
"exclude": ["testdata/**/*.ts"]
}
}
You can also use glob patterns as CLI arguments. Here’s the above example,
but using deno fmt
:
$ deno fmt --exclude="testdata/**/*.ts" "data/example?.txt"
⚠️ Notice that we put the glob in quotes to prevent the shell from expanding it.
With deno task
, in addition to the glob syntax above, you can also use
square brackets to match a range of characters:
{
"task": {
"files": "echo **/*.ts",
"data": "echo data[0-9].txt"
}
}
TLS certificates with IP addresses
One of the most wanted features is finally here. You can now use TLS certificates that contain IP addresses.
This is useful for things like Kubernetes pods, which often use IP addresses instead of domain names, and for DNS over HTTPS/TLS which needs an IP address for the server to avoid circular dependency on name resolution.
With Deno v1.34 any API that uses TLS will work with IP addresses. For example:
const resp = await fetch("https://1.1.1.1");
console.log(await resp.text());
Configuration file improvements
Exclude files or folders for all sub commands
Previously, if you wanted Deno to ignore a file or folder for every sub command, you would have to specify it repetitively:
{
"fmt": {
"exclude": ["target/"]
},
"lint": {
"exclude": ["target/"]
},
"test": {
"exclude": ["target/"]
},
"bench": {
"exclude": ["target/"]
}
}
Starting in this release, you can use a top level exclude
property:
{
"exclude": ["target/"]
}
Thank you to @scarf005 for implementing this feature.
nodeModulesDir
property
A nodeModulesDir
property can now be specified in the deno.json
file for
explicitly enabling or disabling Deno’s use of the node_modules
directory.
{
"nodeModulesDir": true
}
If you are using Deno with a package.json and node_modules
directory, it is
recommended to enable this setting as it will provide a better experience. For
example, with it enabled, Deno’s language server will use the local
node_modules
directory for caching and resolving packages.
Language server improvements
Deno 1.33 introduced document preloading in the language server, which pre-loads modules in the workspace on initialize so Deno knows about them and their contents.
In some cases, the default 1000 file system entry limit was either too little or
too much, so it’s now configurable by setting the deno.documentPreloadLimit
property.
{
"deno.enable": true,
"deno.documentPreloadLimit": 2000
}
Additionally, the language server’s internal TypeScript isolate’s default max
memory limit was increased to 3GB to match TypeScript in VS Code’s default.
Lastly, this limit can be configured in the VSCode extension via
deno.maxTsServerMemory
:
{
"deno.enable": true,
"deno.maxTsServerMemory": 3072
}
Deno API changes
Deno.serve()
Last month, we hinted that we planned to stabilize the Deno.serve()
API. After
much deliberation, however, we decided to postpone the stabilization by another
month in order to make this API more forward compatible.
The signature of Deno.serve()
has been changed to return an instance of
Deno.Server
instead of Promise<void>
. Deno.Server
has a finished
property that’s a Promise
, which resolves when the server shuts down (using an
AbortSignal
). This gives more flexibility in controlling the server
programmatically.
const ac = new AbortController();
const server = Deno.serve(
{ signal: ac.signal },
(_req) => new Response("Hello world"),
);
setTimeout(() => {
ac.abort();
}, 1000);
await server.finished;
console.log("Server has shut down");
Additionally, Deno.Server
has ref()
and unref()
methods. You can use these
methods to control whether the server should keep the process alive or not.
Deno.createHttpClient()
This unstable API now exposes a few more options that allow greater control over the created client:
const client = Deno.createHttpClient({
// Set maximum number of idle connections in the connection pool per host to 10.
poolMaxIdlePerHost: 10,
// Set a timeout for idle connection being kept alive to 10s. You can disable
// timeout all together by passing `false`.
poolIdleTimeout: 10_000,
// Configure if the client can use HTTP1.
http1: false,
// Configure if the client can use HTTP2.
http2: true,
});
const resp = await fetch("...", { client });
Deno.FileInfo
The Deno.FileInfo
interface now includes the following new fields:
Deno.FileInfo.isBlockDevice
Deno.FileInfo.isCharDevice
Deno.FileInfo.isFifo
Deno.FileInfo.isSocket
The fields are available on Linux and macOS. On Windows, they are always null
.
Thank you to Hirotaka Tagawa for the contribution.
Improvements to npm and Node compatibility
There are a couple other notable improvements to npm support:
deno vendor
handles npm specifiers and will no longer error when they are encountered.deno task
runspre
andpost
scripts if present when executing a script from a package.json file similar to npm. Thanks to Marvin Hagemeister for implementing this feature.
We also polyfilled a few more built-in Node.js APIs:
crypto.createDiffieHellman
crypto.createDiffieHellmanGroup
http.Server.unref
Module.runMain
performance.markResourceTiming
process.release
worker_threads
Additionally, the following N-API symbols now work properly:
napi_async_init
napi_async_destroy
napi_add_finalizer
V8 11.5 and TypeScript 5.0.4
Finally, Deno v1.34 ships with V8 11.5 and TypeScript 5.0.4.
Take a look at Deno KV, our globally distributed database for Deno Deploy, now in beta