🎅

2024年のDenoのまとめと今後について

2024/12/23に公開

はじめに

Denoアドベントカレンダー 23日目の記事です🎅

https://qiita.com/advent-calendar/2024/deno

この記事では、2024年にDenoやその周辺に関する変更点などをまとめます。

Deno

Deno v2のリリース

Deno v2が正式にリリースされました:

https://www.youtube.com/watch?v=d35SlRgVxT8

Deno v2の正式リリースに伴い、Deno v2.1からLTSリリースが開始されています。

また、Deno for Enterpriseというサービスが正式に発表されました (主にエンタープライズ向けにDenoランタイムに関するSlackでのサポートなどが提供されるサービスのようです)

https://deno.com/enterprise

Node.js互換性の大きな改善 (Next.jsのサポートなど)

Next.jsのサポート

DenoにおけるNode.js互換性の改善に伴い、Next.jsが動作するようになったようです。Denoの公式ドキュメントなどにおいてNext.jsのチュートリアルが公開されています。

https://github.com/denoland/docs/blob/4482f1f5c080aca2ca256417c87d2c505bbec1f3/examples/tutorials/next.md

https://zenn.dev/yabuki/articles/2024-09-22-deno20-with-react-nextjs

また、Deno公式から@deno/nextjs-startというJSRパッケージが公開されています。このパッケージを使うことで、Deno DeployでNext.jsアプリケーションを動作させられるようです。

https://deno.com/blog/nextjs-on-deno-deploy

--allow-scripts - ライフサイクルスクリプトのサポート

セキュリティに関する懸念から、Denoにおいてはnpmパッケージに含まれるライフサイクルスクリプトの実行がサポートされていませんでした。

しかし、一部のnpmパッケージを動作させるためには、ライフサイクルスクリプトのサポートが必要になります。そこで、Deno v1.45から--allow-scriptsオプションが追加されました。この--allow-scriptsによって許可されたパッケージに対してのみ、限定的にライフサイクルスクリプトの実行が許可されます。

deno installによって依存パッケージをインストールする際などに--allow-scriptsにパッケージを指定することで、指定されたパッケージに含まれるライフサイクルスクリプトを実行することができます:

$ deno install --allow-scripts=npm:duckdb@1.0.0 npm:duckdb@1.0.0

CommonJSサポートの改善

Denoにおいて.cjs/.ctsモジュールの実行やimportがサポートされています。

また、package.json"type": "commonjs"が定義されているパッケージで.jsファイルをCommon JSモジュールとして読み込めるようにする機能が実装されています。この機能を利用する際は、node_modulesが自動で作成されるよう、deno.json"nodeModulesDir": "auto"の設定が推奨されます。

deno init --npm

これはnpm createなどに相当するコマンドで、npmに公開されたcreate-<package名>パッケージを実行することができます。

例えば、以下のコマンドを実行すると、Denoでcreate-honoパッケージが実行されます:

$ deno init --npm hono
⚠️ Do you fully trust npm:create-hono package? Deno will invoke code from it with all permissions. Do you want to continue? [y/n]
> 

deno task - package.jsonで定義されたスクリプトとnpmバイナリの実行がサポート

deno taskコマンドにpackage.jsonscriptsなどを認識してくれる機能が導入されています:

# 1) package.jsonを作成します
$ echo '{ "scripts": { "hi": "cowsay hi" } }' > package.json

# 2) npmパッケージをインストールします (package.jsonがあるため、そちらへ依存が追加されます)
$ deno add --dev npm:cowsay

# 3) npmパッケージがインストールされました
$ cat package.json
{
  "scripts": { "hi": "cowsay hi" },
  "devDependencies": {
    "cowsay": "^1.6.0"
  }
}


# 4) deno taskでnpmバイナリを実行します
$ deno task hi
Task hi cowsay hi
 ____
< hi >
 ----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

--unstable-node-globals

このオプションを指定すると、DenoにおいてNode.jsの各種グローバルAPIが有効化されます。

main.js
console.info(setImmediate);

このスクリプトを--unstable-node-globalsなしで実行するとエラーが発生します:

$ deno run main.js
error: Uncaught (in promise) ReferenceError: setImmediate is not defined
console.info(setImmediate);
             ^
    at file:///home/uki00a/ghq/github.com/uki00a/deno-sandbox/main.js:1:14

    info: setImmediate is not available in the global scope in Deno.
    hint: Import it explicitly with import { setImmediate } from "node:timers";,
          or run again with --unstable-node-globals flag to add this global.

--unstable-node-globalsを指定すると、実行に成功します:

$ deno run --unstable-node-globals main.js
[Function: setImmediate]

.npmrcのサポート

Deno v1.44から.npmrcのサポートが追加されています。現時点では認証に関する設定などがサポートされています。

npm Workspacesのサポート

DenoにおいてNode.jsプロジェクトの動作を行いやすくするため、npm Workspacesのサポートが追加されています。Denoがpackage.jsonworkspacesキーを認識してくれます。

JSR

Deno公式ブログでJSRというパッケージレジストリが発表されました。

https://deno.com/blog/jsr_open_beta

https://deno.com/blog/how-we-built-jsr

JSRはDenoだけでなく、jsr-npmを使用することでNode.jsやBunなどの様々なランタイムもサポートすることが想定されています。

https://github.com/jsr-io/jsr-npm

Denoにおいてはjsr:URLによってJSRで公開されたパッケージを読み込むことができます。

import { assertEquals } from "jsr:@std/assert@1/equals";

assertEquals(sum(1, 2), 3);
assertEquals(sum(), 0);

JSRの開発は以下のリポジトリで行われています:

https://github.com/jsr-io/jsr

WASMモジュールのサポート

最近、リリースされたDeno v2.1ではWASMモジュールのサポートが追加されています。以下のように、JavaScript/TypeScriptコードから.wasmファイルをimportすることができます:

import { add } from "https://raw.githubusercontent.com/denoland/deno/refs/tags/v2.1.0/tests/testdata/wasm/math.wasm";

console.info(add(1, 2));

deno add

Deno v1.41.1deno addというコマンドが実装されています。npmパッケージやJSRパッケージをdeno.jsonpackage.jsonに依存関係として追加する際に利用することができます。また、deno.lockの更新も行ってくれます。

# npmパッケージをインストールします
$ deno add npm:chalk@5.3.0

# jsrパッケージをインストールします
$ deno add jsr:@oak/oak

deno remove

deno removeという新しいコマンドが追加されています。これはdeno.jsonimportsもしくはpackage.jsonから指定したパッケージを削除し、deno.lockを更新してくれるコマンドです。

# deno.jsonのimports 及び deno.lock から指定したパッケージを削除します
$ deno remove @deno/otel

# package.jsonで定義された依存パッケージも削除できます
$ deno remove cowsay

deno installの振る舞いの変更

元々、deno installコマンドはDenoで書かれたスクリプトやCLIツールをインストールするためのコマンドという位置づけでした (Goにおけるgo installに近いイメージです)

Deno v2のリリースに伴いdeno installコマンドの振る舞いが変更され、デフォルトではdeno addコマンドのエイリアスとして機能します:

# JSRから@oak/oakパッケージをインストールします
$ deno install jsr:@oak/oak

引数なしでdeno installを実行した場合は、プロジェクトが依存しているパッケージの一覧をインストールしてくれます。(npm installなどと同様に動作するように変わったイメージです)

もしDeno v1の頃と同様の振る舞いをさせたい場合は、--globalオプションを指定する必要があります。

$ deno install --global --allow-read=. --allow-write=. --allow-net https://deno.land/x/udd/main.ts

また、deno install--entrypointが追加されています。--entrypointが指定された場合、deno cacheコマンドと同様の振る舞いをします。(これに合わせて、deno cacheコマンドは非推奨化されています)

# main.tsを動作させるために必要なリモートモジュールがダウンロードされます
$ deno install --entrypoint main.ts

deno uninstallコマンドの振る舞いの変更

deno uninstallコマンドは元々、deno installコマンドによってインストールされたスクリプトを削除するためのコマンドでした。

このdeno uninstallコマンドについてもdeno installコマンドと同様に、deno removeコマンドのエイリアスとして機能するようデフォルトの振る舞いが変更されています。

# @deno/otelパッケージをdeno.jsonのimportsから削除します
$ deno uninstall @deno/otel

もしdeno uninstallコマンドを今までの挙動に戻したい場合は--globalまたは-gオプションを指定する必要があります。

deno outdated

deno outdatedという新しいコマンドが実装されています。このコマンドには2つの役割があり、まず1つ目として、プロジェクトが依存しているパッケージに関する最新情報などを表示できます:

$ deno outdated
┌────────────────────┬─────────┬────────┬────────┐
│ Package            │ Current │ Update │ Latest │
├────────────────────┼─────────┼────────┼────────┤
│ jsr:@oak/oak       │ 17.1.0  │ 17.1.3 │ 17.1.3 │
├────────────────────┼─────────┼────────┼────────┤
│ jsr:@hono/hono     │ 4.6.4   │ 4.6.11 │ 4.6.11 │
├────────────────────┼─────────┼────────┼────────┤
│ npm:@nestjs/common │ 10.4.4  │ 10.4.8 │ 10.4.8 │
├────────────────────┼─────────┼────────┼────────┤
│ npm:@nestjs/core   │ 10.4.4  │ 10.4.8 │ 10.4.8 │
└────────────────────┴─────────┴────────┴────────┘

引数を指定すると、該当のパターンにマッチするパッケージの情報のみを表示することもできます:

$ deno outdated "@nestjs/*"
┌────────────────────┬─────────┬────────┬────────┐
│ Package            │ Current │ Update │ Latest │
├────────────────────┼─────────┼────────┼────────┤
│ npm:@nestjs/common │ 10.4.4  │ 10.4.8 │ 10.4.8 │
├────────────────────┼─────────┼────────┼────────┤
│ npm:@nestjs/core   │ 10.4.4  │ 10.4.8 │ 10.4.8 │
└────────────────────┴─────────┴────────┴────────┘

2つ目の役割として、--updateオプションを併用することで、プロジェクトが依存しているパッケージのバージョンを更新することができます:

# deno.jsonで指定されたバージョンレンジに基づいて指定されたパッケージを更新する
$ deno outdated --update "@nestjs/*"

# バージョンを明示する
$ deno outdated --update @nestjs/common@^10.4.8 @nestjs/core@^10.4.8

# バージョンレンジに関わらず、常に最新バージョンへアップデート
$ deno outdated --update --latest "@nestjs/*"

ワークスペース

Denoのワークスペース機能が正式にリリースされました。以下のようにdeno.jsonworkspaceでワークスペースに関する設定が行えます:

deno.json
{
  "workspace": {
    "members": ["./packages/*"]
  },
  "imports": {
    "@david/dax": "jsr:@david/dax@0.42.0"
  }
}

ワークスペースのメンバーとして扱う各パッケージについてもname/version/exportsの3つを定義したdeno.jsonを用意する必要があります:

packages/foo/deno.json
{
  "name": "@uki00a/foo",
  "version": "0.1.0",
  "exports": { ".": "./mod.ts" },
  "imports": {
    "@std/csv": "jsr:@std/csv@^1"
  }
}

各ワークスペースメンバー間においては、deno.jsonnameで定義された名前で参照することができます:

packages/bar/mod.ts
import { foo } from "@uki00a/foo";

このワークスペース機能の利点として、このようにdeno.jsonを複数定義することができるため、各ワークスペースメンバーごとに独自のImport mapsを定義することができます。ワークスペースのルートで定義されたImport mapsは全メンバーに適用されます。また、後述するdeno taskコマンドにおいて、ワークスペースの複数のメンバーに対して一括でタスクを実行する機能が導入されています。

deno test --docでコードブロックの実行がサポート

今まで、deno test --docコマンドではMarkdownファイルやJSDocコメント中のTypeScriptコードブロックの型チェックのみがサポートされていました。Deno v2のリリースに伴ってdeno test --docが拡張され、コードブロックのテストもサポートされました。

/**
 * ```typescript
 * import { assertEquals } from "jsr:@std/assert@1/equals";
 *
 * assertEquals(sum(1, 2), 3);
 * assertEquals(sum(), 0);
 * ```
 */
export function sum(...numbers: Array<number>): number {
  return numbers.reduce((a, b) => a + b, 0);
}

以下のようにJSDocコメントに記述されたコードブロックが実行されます:

$ deno test --doc ./sum.ts
Check file:///home/uki00a/ghq/github.com/uki00a/deno-sandbox/sum.ts
Check file:///home/uki00a/ghq/github.com/uki00a/deno-sandbox/sum.ts$2-8.ts
running 0 tests from ./sum.ts
running 1 test from ./sum.ts$2-8.ts
file:///home/uki00a/ghq/github.com/uki00a/deno-sandbox/sum.ts
$2-8.ts ... ok (0ms)

ok | 1 passed | 0 failed (32ms)

deno fmt - YAML/HTML/CSS/Vue/Svelte/Astro/SQLのサポート

deno fmtコマンドでは、今まではTypeScriptやJavaScript, Markdownなどがサポートされていました。

今年はdeno fmtのサポート対象の言語が大幅に拡張され、以下の言語もサポートが追加されました (一部の言語についてはまだ実験的サポートの段階であるため、--unstable-*オプションの指定が必要です):

  • YAML
  • CSS
  • LESS
  • Sass
  • SCSS
  • HTML
  • Svelte (利用には--unstable-componentの指定が必要です)
  • Vue (利用には--unstable-componentの指定が必要です)
  • Astro (利用には--unstable-componentの指定が必要です)
  • Angular (利用には--unstable-componentの指定が必要です)
  • Nunjucks (利用には--unstable-componentの指定が必要です)
  • Vento (利用には--unstable-componentの指定が必要です)
  • SQL (利用には--unstable-sqlの指定が必要です)

deno fmt/deno lint - .gitignoreのサポート

deno fmtdeno lint.gitignoreがサポートされました。.gitignoreで指定したファイルはデフォルトでフォーマットやLintの対象から除外されます。

deno lint - Quickfixのサポート

一部のLintルールでQuickfixがサポートされています。deno lint--fixオプションが指定された場合、修正可能な問題が検出された際に自動で修正を行ってくれます:

$ deno lint --fix main.js

deno lint - no-consoleルールがサポート

ESLintに存在する同名のルールと同様に、console.logなどの使用を検出してくれます。deno.jsonで以下のように設定しておくと有効化できます:

deno.json
{
  "lint": {
    "rules": { "include": ["no-console"] }
  }
}

deno jupyterの安定化

Deno v1.40からdeno jupyterコマンドが安定化されています。現在は--unstableを指定せずに利用することができます。

deno serve

deno serveという新しいコマンドが追加されています。deno serveを利用するためには、以下のようにDeno.ServeDefaultExportを実装したオブジェクトをdefault exportするファイルを用意します:

main.ts
export default {
  fetch(req) {
    return new Response("OK");
  },
} satisfies Deno.ServeDefaultExport;

その後、このファイルを引数に指定してdeno serveを実行すると、default exportされたDeno.ServeDefaultExportオブジェクトに基づいてHTTPサーバーを起動してくれます:

$ deno serve main.ts

$ curl http://localhost:8000/
OK

deno serveコマンドの大きなメリットとして、--parallelオプションを指定することで、利用可能なコア数に基づいて内部で複数のワーカーを起動して負荷分散を行ってくれる機能があります (ワーカー数はDENO_JOBS環境変数によって調整することも可能です)

$ DENO_JOBS=2 deno serve --parallel main.ts
deno serve: Listening on http://0.0.0.0:8000/ with 2 threads

deno task - タスク間の依存関係の定義がサポート

wireitを参考に、タスク間の依存関係の定義がサポートされました。以下のようにdependenciesによってタスク間の依存関係を定義できます:

deno.json
{
  "tasks": {
    "check:all": {
      "command": "echo 'All checks have been passed!'",
      "description": "Run all checks",
      "dependencies": ["check:fmt", "check:deno-json"]
    },
    "check:fmt": "deno fmt --check",
    "check:deno-json": {
      "description": "Check if deno.json is valid",
      "command": "deno run --allow-read=deno.json tools/check_deno_json.js"
    }
  }
}

上記の場合にdeno task check:allを実行すると、まずcheck:fmtcheck:deno-jsonタスクが並列で実行され、それらが成功した場合のみcheck:allcommandが実行されます。

dependenciesを持つタスクに関しては、おそらく次にリリースされるであろうDeno v2.2あたりでcommandの指定が省略可能になると思われます:

https://github.com/denoland/deno/pull/27191

deno task - ワークスペースのサポート

deno taskコマンドに--filter及び--recursiveオプションが追加されています。--filterオプションが指定された場合、該当の名前にマッチするメンバーのdeno.jsonで定義されたタスクをまとめて実行することができます:

# 名前が`platform-*`パターンにマッチするメンバーのhiタスクを実行
$ deno task --filter 'platform-*' hi

# すべてのメンバーのhiタスクを実行
$ deno task --filter '*' hi

--recursiveオプションについては、実質的に--filter *と同様に動作します:

# ワークスペース内の各パッケージで定義されたtestタスクを実行します
$ deno task --recursive test

deno cleanコマンド

deno cleanという新しいコマンドが追加されています。現状ではDenoのグローバルキャッシュ(DENO_DIR)の削除のみがサポートされています。

deno <entrypoint>

Deno v1.46からdeno runコマンドにおけるrunの指定を省略できるようになりました:

# `deno run --allow-read main.ts`と同様に動作します
$ deno --allow-read main.ts

パーミッションフラグの短縮形式

各種--allow-*オプションについて短縮形式がサポートされています:

パーミッションフラグ 短縮形
--allow-read -R
--allow-write -W
--allow-net -N
--allow-env -E
--allow-sys -S

例えば、以下はdeno run --allow-read --allow-env main.tsと同等です:

$ deno -ER main.ts

--allow-importの導入

Deno v2のリリースに伴い、--allow-import(-I)という新しいパーミッションフラグが導入されています。

Deno v2からはリモートモジュールの読み込みを許可するホストに制限がかかります。必要に応じて--allow-importにリモートモジュールの読み込みを許可するホストを指定する必要があります。ただし、デフォルトでは以下のホストからのモジュールのimportが許可されているため、基本的なケースにおいては今まで通り利用できると思われます:

  • deno.land
  • jsr.io
  • esm.sh
  • raw.githubusercontent.com
  • cdn.jsdelivr.net

上記以外のホストからモジュールをimportしたい場合、--allow-importの指定が要求されます。例えば、unpkg.comからモジュールをimportしようとすると権限が要求されます:

import ky from "https://unpkg.com/ky@1.7.2";

const res = await ky.get("https://api.github.com/repos/uki00a/deno-weekly").json();

以下のように--allow-importによって明示的に許可することでimportできます:

$ deno run --allow-net --allow-import=unpkg.com main.js

--allow-env - 特定の名前で始まる環境変数の一括許可がサポート

--allow-envオプションにおいて、以下のようにプレフィックスを指定することで、特定の環境変数へのアクセスを一括で有効化することがサポートされました:

# 名前が`APP_`から始まる環境変数の参照を許可します
$ deno run --allow-env='APP_*' main.js

DENO_TRACE_PERMISSIONS

DENO_TRACE_PERMISSIONSという環境変数が導入されています。この環境変数を設定すると、パーミッションプロンプトにおいてスタックトレースの表示が有効化され、あるパーミッションがどこで要求されたか判断しやすくなります:

$ DENO_TRACE_PERMISSIONS=1 deno run main.js
┏ ⚠️  Deno requests read access to "/home/uki00a/ghq/github.com/uki00a/deno-sandbox/data/test.txt".
┠─ Requested by `Deno.readFile()` API.
┃  ├─ op_fs_read_file_text_async (ext:core/00_infra.js:260:33)
┃  ├─ Object.readTextFile (ext:deno_fs/30_fs.js:779:24)
┃  └─ file:///home/uki00a/ghq/github.com/uki00a/deno-sandbox/main.js:1:25
┠─ Learn more at: https://docs.deno.com/go/--allow-read
┠─ Run again with --allow-read to bypass this prompt.
┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions) > 

DENO_TRACE_PERMISSIONSによって有効化されるスタックトレースの収集は高価な処理のため、この機能は本番環境などにおいては無効化することが推奨されます。

--frozen-lockfile

--frozen-lockfileという新しいオプションが導入されています。このオプションが指定された場合、あるパッケージに関してdeno.lockで指定されているバージョンと実際に使用されているバージョンが異なる場合にエラーが発生します。CIにおいて利用するとよさそうです。

$ deno test --allow-net --no-check --frozen-lockfile ./test

deno compile - ローカルファイル/ディレクトリの埋め込みがサポート (--include)

実行可能ファイルへのローカルのファイル/ディレクトリの埋め込みがサポートされています。

main.js
console.info(await Deno.readTextFile(import.meta.dirname + "/data/test.txt"));

deno compile--includeオプションを指定することで、ファイルまたはディレクトリを生成される実行可能ファイルへ埋め込むことができます:

$ cat data/test.txt
foo
bar

$ deno compile --output sample --include ./data ./main.js

$ ./sample
foo
bar

denort(deno compile向けの軽量バイナリ)の再導入

Deno v1.40.5において3年前に削除(#10350)されていたdenortバイナリが改めて導入されました。これによってdeno compileによって生成される実行可能ファイルのサイズが2分の1ほどまで軽量化されています。

GitHub Releasesに各プラットフォーム向けのdenortバイナリーがアップロードされており、deno compileを実行する際に自動でダウンロードされます。

Deno v1.41の公式ブログ記事によると、deno compileをする際に特定の機能のみを有効化したカスタムビルドをサポートすることで、さらにバイナリを軽量化する機能を将来的に導入することなども検討されているようです。

https://deno.com/blog/v1.41

External WebGPU surfaces / BYOW (Bring your own Window)

Deno v1.40からDeno.UnsafeWindowSurfaceというAPIが追加されています。

deno_sdl2@0.8.0などではこの機能のサポートが追加されていて、これによりWebGPUを活用して高速にレンダリングが行えるようです。

この機能を活用したwguiというフレームワークも開発されているようです:

https://github.com/littledivy/wgui

OpenTelemetryサポート (Deno.telemetry)

Deno v2.1からOpenTelemetryサポートが実験的に追加されています。20日目の記事で内容を書いたので、もしご興味がありましたら参照いただければと思います。

https://scrapbox.io/uki00a/Deno_v2.1で導入されたOpenTelemetryサポートを試してみる

Deno.errors.NotCapable

Deno.errors.NotCapableという新しいエラーが導入されています。今までは、OSによる権限エラーとDenoによる権限エラー(--allow-*の指定漏れ)の両方がDeno.errors.PermissionDeniedによって表現されていましたが、それらをきちんと区別できるようにするために、Denoの権限エラーはDeno.errors.NotCapableによって表現されるよう変更されています。

Temporalのサポート

Deno v1.40からTemporalのサポートが実験的に追加されています。

利用するには--unstable-temporalまたはdeno.json"unstable": ["temporal"]の指定が必要です。

compilerOptions.jsxImportSourceTypes

Deno v1.43で導入されたTypeScriptに関する独自のオプションです。

deno.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "npm:react@18.3.1",
    "jsxImportSourceTypes": "npm:@types/react@18.3.1"
  }
}

このオプションが導入された背景についてですが、まずJSX Transformが有効化された場合、TypeScriptは<some-jsx-package>/jsx-runtimeimportするようなコードを生成します:

// 例) Reactの場合、以下のようなコードが生成されます
import {jsx as _jsx} from 'react/jsx-runtime';

// ...

元々、Denoにはこの<some-jsx-package>/jsx-runtimeimportに対して適用すべき型定義を判断する方法が存在せず、JSX Transformを有効化してReactなどを使う場合に型エラーが発生する課題がありました。TypeScriptによって自動生成されるコードのため@ts-typesプラグマ(旧@deno-types)を適用することもできませんでした。

compilerOptions.jsxImportSourceTypesはこの課題を解消するために導入されたもので、上記のような<some-jsx-package/jsx-runtimeimportに対して、Denoがどの型定義を適用すればよいか判断できるようになります。

@ts-types@ts-self-typesプラグマ

@ts-types@ts-self-typesという新しいプラグマが導入されています。

https://github.com/denoland/deno-docs/pull/502

@ts-typesについては@deno-typesプラグマと同様に、特定のJavaScriptモジュールに対して型定義を適用したい場合に指定することが想定されているようです。今後は@deno-typesではなく@ts-typesの方の使用が推奨されるようです。

// @ts-types="./add.d.ts"
import { add } from "./add.js";

@ts-self-typesについてもJavaScriptで書かれたモジュールに型を適用するための機能のようですが、実質的に/// <reference types="..." />と同様に動作するようです。JavaScriptモジュールに対して型を適用したいケースを除いて、/// <reference types="..." />の方の使用が推奨されるようです。

// @ts-self-types="./globals.d.ts"

deno lspのパフォーマンス改善

Deno v1.43においてdeno lspのパフォーマンスが大幅に改善されています。今までは巨大なプロジェクトにおいては自動補完に6〜8秒程時間がかかることもあったようですが、現在は1秒以内に収まる程度まで高速化されているようです。

https://deno.com/blog/v1.43

Deno本体においてdeco-cx/appsを使用したベンチマークの仕組みも導入されており、これによってパフォーマンスが計測されているようです。

https://github.com/denoland/deno/pull/23395

V8コードキャッシュ

V8が生成したコードキャッシュを保存することで、Denoの起動を高速化する仕組みが導入されています。DENO_DIR配下にv8_code_cache_v2というSQLiteデータベースファイルが作られ、そこで生成されたV8コードキャッシュが管理されます。

この仕組みはデフォルトで有効化されており、--no-code-cacheによって無効化できます。

deno compileにおけるサポートについて

このV8コードキャッシュの仕組みはdeno compileで生成される実行可能ファイルにおいてもサポートされています。

deno compileにおいては通常のケースとは異なり、deno compileによって作成された実行可能ファイルの初回実行時に/tmpディレクトリ配下にV8コードキャッシュが保存されます。実行可能ファイルを2回目以降に実行する際に、/tmpディレクトリに保存されたV8コードキャッシュが読み込まれます。

deno compileによって生成された実行可能ファイルが保存したV8コードキャッシュのパスについては、DENO_LOG=debugを指定することで確認できます:

$ DENO_LOG=debug ./sample
  ... 省略 ...
DEBUG RS - denort::standalone::code_cache:45 - Loaded 1 code cache entries from /tmp/deno-compile-sample.cache
  ... 省略 ...

deno bundleコマンドの削除

非推奨化されていたdeno bundleコマンドが削除されています。

deno_emitesbuildなどへの移行が推奨されています。

deno vendorコマンドが削除

非推奨化されていたdeno vendorコマンドが削除されました。

deno.json"vendor": trueまたは--vendorを指定することで同様のことが実現できるため、今後はそちらなどへの移行が推奨されます。

非推奨APIの削除

Deno v2のリリースに伴い、様々な非推奨APIが削除されています。公式でマイグレーションガイドが公開されており、移行先などについて解説されています。

https://github.com/denoland/docs/blob/4482f1f5c080aca2ca256417c87d2c505bbec1f3/runtime/reference/migration_guide.md

Denoの今後について

Denoにおいて直近で進められている開発内容についていくつか紹介いたします。

QUICとWebTransport APIのサポート

まず、直近でQUICに関するサポートがDeno本体のmainブランチにすでにマージされています。

https://github.com/denoland/deno/pull/21942

Deno.connectQuicDeno.listenQuicなどのAPIが実装されており、利用するには--unstable-netの指定が必要になる想定です。おそらく、QUICのサポートに関しては間もなくリリースされると思われるDeno v2.2あたりでリリースされるのではないかと思います。

また、このQUICの実装をベースにWebTransport APIを実装するPRも作成されています。

https://github.com/denoland/deno/pull/27431

このPRはまだマージはされていませんが、WebTransport APIの実装に加えて、Deno.upgradeWebTransportというWebTransportサーバーを立てるための独自のAPIも実装されているようです。(これらのAPIについても、使用には--unstable-netの指定が必要になります)

deno lintでのJavaScriptプラグインのサポート

まだマージはされておらず正式に導入されるかどうかはわかりませんが、deno lintにおいてJavaScriptでプラグインを記述するための機能を実装するPRが作成されています:

https://github.com/denoland/deno/pull/27203

直近ではJavaScriptプラグインを実行するためのDeno[Deno.internal].runLintPluginという内部APIを実装するPRがDeno本体のmainブランチへすでにマージされているようです。(まだCLIオプションや公開APIなどは追加されていないため、一般利用はできない状態です)

https://github.com/denoland/deno/pull/27416

node:sqlite

Deno本体にnode:sqliteパッケージを実装するPRが作成されています。

https://github.com/denoland/deno/pull/27308

まだ正式に導入されるかどうかはわかりませんが、個人的には非常に便利なのではないかと思っています。

deno_std (@std )

deno_stdはDeno公式の標準ライブラリです。

JSRへの公開とv1のリリースについて

まず、deno_stdに関する大きな変更として、JSRへのパッケージの公開が実施されました:

https://deno.com/blog/std-on-jsr

今後はhttps://deno.land/stdではなくjsr:@std経由での利用が推奨されます。

JSRにdeno_stdが公開されたことにより、deno_stdを構成する各パッケージごとに独立してバージョン管理ができるようになりました。

https://deno.com/blog/stabilize-std

これによって、deno_stdにおいてすでに安定しているパッケージについてはv1がリリースされています。

例)

パッケージの運用について

v1がリリースされていないパッケージについては、既存のAPIに対して破壊的変更が発生する可能性があります。

すでにv1がリリースされているパッケージに新規APIを追加する際は、unstable-プレフィックスつきのモジュールから公開されます (例: @std/http/unstable-route)

このunstable-がついたモジュールから公開されるAPIについては、破壊的変更が実施される可能性があります。

@std/http/unstable-route - 軽量なルーティングモジュール

HTTP関連のパッケージである@std/httpに軽量なルーティング用モジュールが実験的に追加されています:

main.ts
import type { Route } from "jsr:@std/http@1/unstable-route";
import { route } from "jsr:@std/http@1/unstable-route";

const routes: Array<Route> = [
  {
    pattern: new URLPattern({ pathname: "/messages/:id" }),
    handler: (
      _req,
      params,
    ) => new Response(`Message ${params?.pathname.groups.id}`),
  },
  {
    pattern: new URLPattern({ pathname: "/authenticate" }),
    method: "POST",
    handler: () => new Response("OK"),
  },
];
const defaultHandler = (req: Request) =>
  new Response("Not Found", { status: 404 });
const handler = route(routes, defaultHandler);

export default {
  fetch: (req) => handler(req),
} satisfies Deno.ServeDefaultExport;

deno serveあたりと併用して、ちょっとしたWebアプリケーションを実装したい場合などに便利そうです。

@std/uuid/unstable-v7 - UUIDv7の実験的サポート

UUIDに関する機能を提供する@std/uuidでUUIDv7の実験的サポートが追加されています。

import { generate } from "jsr:@std/uuid@1/unstable-v7";

console.info(generate());

新規パッケージ

以下のような新規パッケージがdeno_stdに追加されています:

パッケージ 説明
@std/cache 関数のメモ化などの機能が提供されます
@std/tar tarに関するユーティリティーです (これの追加に伴い、@std/archiveは削除されました)
@std/random 乱数の生成や配列のシャッフルなどのユーティリティーが提供されます
@std/cbor CBORの実装です

Fresh v2

FreshはDeno公式のPreactベースのメタフレームワークです:

https://github.com/denoland/fresh

現在、Freshではv2の開発が進められており、v2のアルファバージョンが公開されています。

https://github.com/denoland/fresh/issues/2363

また、先程紹介したJSRにおいては、すでにFresh v2のアルファバージョンが採用されています。

https://github.com/jsr-io/jsr/pull/558

Fresh v2での変更内容などについては以下のページにまとめています:

https://scrapbox.io/uki00a/Fresh_v2

Deno Deploy

Deno DeployはDenoが提供しているサーバーレスJavaScriptランタイムです:

https://deno.com/deploy

Deno Deploy NextGen

Deno公式からDeno Deploy NextGenというものが公開されています:

https://github.com/denoland/nextgen-install

まだ公式ブログなどでのアナウンスはされていないですが、これはKubernetesクラスター上でユーザーがDeno Deployのインフラストラクチャーを実行するための基盤のようで、現時点だとAWSとAzureがサポートされているようです。

Web Cache APIのサポート

Deno DeployにおいてWeb Cache APIのベータサポートが実施されています。

以下の記事ではHTTPヘッダーに基づいたキャッシュの有効期間の管理や内部の仕組み、料金設定などについて解説されています。

https://deno.com/blog/deploy-cache-api

エコシステム

@deno/vite-plugin

Deno公式からViteプラグインが公開されています:

npm:/jsr:/https:のサポートや、deno.jsonで定義されたImport mapsの解決などがサポートされているようです。

@types/deno

DefinitelyTypedに@types/denoパッケージが追加されています:

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/70492

DenoのAPIに関する型定義が提供されるようです。

@deno/kv-utils

Deno公式から提供されているDeno KVのユーティリティーパッケージです。

https://github.com/denoland/kv-utils

元々、kv-toolboxから提供されていた一部のAPIは、現在では@deno/kv-utilsから提供されています。

LumeCMS

LumeCMSというCMSが発表されています。

https://lume.land/blog/posts/lume-cms/
https://github.com/lumeland/cms

名前の通り、LumeというスタティックサイトジェネレーターではこのLumeCMSのサポートがデフォルトで提供されます。

https://lume.land/blog/posts/lume-2.1.0-release-notes/

Lumeと名前についていますが、アダプターを実装することによって様々なスタティックサイトジェネレーターと連携できるようにすることが想定されています。

Slint

GUIツールキットであるSlintのv1.4.0において、Denoのサポートが追加されています。

https://slint.dev/blog/slint-1.4-released

NativeScript

NativeScriptの公式ブログで@nativescript/macos-node-apiというパッケージが紹介されています。

https://blog.nativescript.org/macos-node-api-preview/

このパッケージはNode.jsに加えてDenoでも動作するようです。

以下のリポジトリでは、このパッケージとNode.jsまたはDenoを使って、macOS向けのデスクトップアプリを作成する例が公開されています。

https://github.com/DjDeveloperr/NSBall

UnJSプロジェクト

UnJSにおいてDenoサポートを進めていくことが検討されているようです:

以前からDenoのサポートが進められていたNitro (v2.5.0)に加えて、現在ではcrosswsでもDenoのサポートが導入されているようです。

また、直近ではUnstorageにDeno KVドライバーの実装が追加されています:

https://github.com/unjs/unstorage/pull/233
https://github.com/unjs/unstorage/pull/521

jsr:@eslint/*

ESLint関連のパッケージがjsrへ公開されています:

https://github.com/eslint/rewrite/pull/16

@eslint/core@eslint/compat, @eslint/jsonなどのパッケージが公開されているようです。

Hono

Honoではv4.4.0からJSRへのパッケージの公開が行われています:

https://github.com/honojs/hono/releases/tag/v4.4.0

Oak

DenoのWebフレームワークであるOakについてはv14.1.0からNode.jsとCloudflare Workersのサポートが追加されています。

https://github.com/oakserver/oak/commit/7693dae7584034db6ff43cd5e7f2cc4ddf2d366e

また、JSRパッケージも公開されています。

https://jsr.io/@oak/oak

esm.sh

esm.shに関する大きな変更として、JSRのサポートが追加されています。

https://x.com/jexia_/status/1763557916156875110

ブラウザーなどから直接JSRパッケージを読み込みたいケースなどで活用できそうです。

おわりに

今年はDeno v2のリリースやJSRの公開など、大きな変更がたくさんありました。

初期のころから要望が多くあったWASMモジュールのサポートが導入されたり、External WebGPU surfacesなどのよりユースケースを拡充するための機能なども導入されました。

今後、deno lintにおけるJavaScriptプラグインサポートやnode:sqliteなどが導入されるとさらに利便性が向上すると思われるため、個人的に非常に楽しみにしています。

Discussion