虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Deno 1.27 へのアップデートと変更事項まとめ

皆さんこんにちは。年末寒い中の大掃除を回避したく、早めに少し大掛かりな掃除をはじめました、おっくんです。

去る 2022 年 10 月 27 日に Deno 1.27 がリリースされました。 今回も、リリースノートを参考に変更事項の気になるところを紹介します。

Deno 1.27

Deno 1.27 での変更事項をDeno 1.27 リリースノートを元に確認します。

NPM 互換性の改善

型チェック、LSPサポートの拡充

Deno が npm: 指定子で取得する型情報を含むnpmパッケージから、TypeScript型を取得するようになりました。

リリースノートでは、VSCode でchalkの持つ関数のサジェストと引数の型情報がヒントとして表示されています。

型情報を含まずに、別途型情報を配布している @types パッケージが有る場合には、それを指定するディレクティブを使用できます。

リリースノートでは次のものが紹介されています。

// @deno-types="npm:@types/chalk@4"
import chalk from "npm:chalk@4";

また、@types/node を必要とする場合、トリプルスラッシュディレクティブで Node.js の独自型を取得できます。

/// <reference types="npm:@types/node" />

// @deno-types="npm:@types/express@4"
import express from "npm:express@4.18";

Node API のサポートを追加

npm パッケージで使用される Node-API (Node.jsからネイティブコードを扱うAPI)を Deno がサポートするようになりました。 このことで、parcelsqlite3usbfs-xattrがDenoで使用することができるようになりました。

この機能には、--allow-ffi の設定が必要です。

lockfile v2

ロックファイルのフォーマットが変更され、npmパッケージの情報が保存されるようになりました。

先に紹介した npm:chark@5 を参照したスクリプトでロックファイルを作成すると次のようになります。

$ cat test001.ts
import chalk from "npm:chalk@5"

console.log(chalk.red("message"))

$ deno run -A --unstable --lock=lock.json test001.ts
message

# キャッシュだけでも可能
deno cache --unstable --lock=lock.json test001.ts

作成された lock.json は次のようになります。

{
  "version": "2",
  "remote": {},
  "npm": {
    "specifiers": { "chalk@5": "chalk@5.1.2" },
    "packages": {
      "chalk@5.1.2": {
        "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==",
        "dependencies": {}
      }
    }
  }
}

deno cache が npm モジュールを直接キャッシュするようになりました

deno cache が npm: 指定子を直接キャッシュできるようになりました。 Deno のグローバル npm キャッシュにダウンロードされた様子というのは、見えづらいものです。 --node-modules-dir を使用した時には、node_modules 以下に保存されるようになります。

# グローバル npm キャッシュにキャッシュ
$ deno cache --unstable --reload npm:chalk@5

# ./node_modules にキャッシュ
$ deno cache --unstable --reload --node-modules-dir npm:chalk@5

$ tree
.
|-- lock.json
|-- node_modules
|   `-- chalk -> /usr/src/app/deno1.27/node_modules/.deno/chalk@5.1.2/node_modules/chalk
`-- test001.ts

Deno 1.27 では、navigator.language で、ユーザーのシステム優先言語を返すようになりました。

# deno 公式 docker image
$ deno
Deno 1.27.1
exit using ctrl+d, ctrl+c, or close()
> navigator.language
"en-US-u-va-posix"

# Windows 環境
$ deno
Deno 1.27.1
exit using ctrl+d, ctrl+c, or close()
> navigator.language
"ja-JP"

deno task が改善

deno task はこれまで実行時に 「将来的な変更の可能性」に関する警告を出していましたが、このリリースから削除されています。

環境変数 INIT_CWD が追加

deno task の実行時に、deno.jsonと同じ階層に作業ディレクトリに設定されます。 この作業ディレクトリを操作できる環境変数 INIT_CWD を参照するようになりました。

リリースノートで紹介されている deno.json を用意し動かしてみます。

$ cat deno.json
{
  "tasks": {
    "my_task": "cd $INIT_CWD && pwd"
  }
}

$ ls -la
drwxrwxrwx 1 root root   512 Nov  5 19:41 .
drwxr-xr-x 1 root root  4096 Nov  5 16:44 ..
-rwxrwxrwx 1 root root    58 Nov  5 19:19 deno.json
drwxrwxrwx 1 root root   512 Nov  5 19:41 test

# 環境変数 INIT_CWD 無設定
$ deno task my_task
Task my_task cd $INIT_CWD && pwd
/usr/src/app

# 環境変数 INIT_CWD 設定
$ export INIT_CWD=test
$ deno task my_task
Task my_task cd $INIT_CWD && pwd
/usr/src/app/test

$ pwd
/usr/src/app

非同期コマンドが失敗したときに、タスクが失敗するようになりました

以前は、非同期コマンドが失敗した場合でも、他のコマンドは実行され続けていました。 この動作は一般的なシェルの動作とは同じですが、deno task の目的として実用的ではないためこの変更が入ったようです。

動かしてみます。

$ cat server.ts
import { serve } from "https://deno.land/std@0.162.0/http/server.ts";

serve(() => new Response("Hello World\n"));

console.log("http://localhost:8000/");

$ cat client.ts
setTimeout(async () => {
  const result = await fetch("http://localhost:8000/");
  console.log(await result.text());
}, 100);

$ deno task start
Task start deno run --allow-net server.ts & deno run --allow-net client.ts
Listening on http://localhost:8000/
http://localhost:8000/
Hello World

続けて、server.ts だけ、必ず失敗するようにします。

$ cat server.ts
import { serve } from "https://deno.land/std@0.162.0/http/server.ts";

serve(() => new Response("Hello World\n"));
throw new Error();

console.log("http://localhost:8000/");

$ deno task start
Task start deno run --allow-net server.ts & deno run --allow-net client.ts
Listening on http://localhost:8000/
error: Uncaught Error
throw new Error();
      ^
    at file:///usr/src/app/deno1.27/server.ts:4:7

タスク全体が終了しているのが確認できます。

これまでと同様に非同期コマンドの失敗がしても、後続のコマンドを実行を続けたい場合には、|| true を付けることで対応できます。

$ cat deno.json
{
  "tasks": {
    "my_task": "cd $INIT_CWD && pwd",
    "start": "deno run --allow-net server.ts & deno run --allow-net client.ts",
    "start_2": "deno run --allow-net server.ts || true & deno run --allow-net client.ts || true"
  }
}

$ deno task start_2
Task start_2 deno run --allow-net server.ts || true & deno run --allow-net client.ts || true
Listening on http://localhost:8000/
error: Uncaught Error
throw new Error();
      ^
    at file:///usr/src/app/deno1.27/server.ts:4:7
error: Uncaught (in promise) TypeError: error sending request for url (http://localhost:8000/): error trying to connect: tcp connect error: Cannot assign requested address (os error 99)
  const result = await fetch("http://localhost:8000/");
                 ^
    at async mainFetch (deno:ext/fetch/26_fetch.js:247:14)
    at async fetch (deno:ext/fetch/26_fetch.js:464:9)
    at async file:///usr/src/app/deno1.27/client.ts:2:18

server.ts がエラーを出した後に、タスク全体が終了しないために client.ts の実行が継続されこちらもエラーとなっていることがわかります。

sleep の時間サフィックスのサポートを追加

linux マニュアルページで紹介されている sleep の時間サフィックスのサポートが追加されました。 実際に比較し確認します。

$ cat deno.json
{
  "tasks": {
    "sleep_cmd": "sleep 3s && pwd"
  }
}

# deno 1.26
$ deno task sleep_cmd
Warning deno task is unstable and may drastically change in the future
Task sleep_cmd sleep 3s && pwd
sleep: error parsing argument '3s' to number: invalid float literal

# deno 1.27 => 3秒待って カレントディレクトリを出力
$ deno task sleep_cmd
Task sleep_cmd sleep 3s && pwd
/usr/src/app

3s のように、s m h d のサフィックスがサポートされていることが確認できます。

deno lint の更新

deno lint が、ESLint ライクなコンパクトなレポート形式で出力できるようになりました。 この出力形式を使うには、--compact を指定するか、deno.json(c) で設定が必要です。

比較してみます。

$ cat test002.ts
const a = 100

# これまで通りの出力形式
$ deno lint test002.ts
(no-unused-vars) `a` is never used
const a = 100
      ^
    at /usr/src/app/deno1.27/test002.ts:1:6

    hint: If this is intentional, prefix it with an underscore like `_a`
    help: for further information visit https://lint.deno.land/#no-unused-vars

Found 1 problem
Checked 1 file

# 新しいコンパクトな形式
$ deno lint --compact test002.ts
/usr/src/app/deno1.27/test002.ts: line 1, col 7 - `a` is never used (no-unused-vars)
Found 1 problem
Checked 1 file

# deno.json(c) への記述で --compact が不要に
$ echo {\"lint\":{\"report\":\"compact\"}} >deno.json
$ deno lint test002.ts
/usr/src/app/deno1.27/test002.ts: line 1, col 7 - `a` is never used (no-unused-vars)
Found 1 problem
Checked 1 file

標準ライブラリの変更

std@0.161.0 にて、多数のAPIが削除されました。 数も多いので、内容については直接リリースノートの参照をオススメします。 筆者個人でも、これまで使用していたモジュールに影響が出ていました。 その場合は、https://deno.land/std@0.160.0/hogehoge/mod.ts のようにバージョンのを記述することで回避できることがあります。

また、自身では書き換えられない外部モジュールが https://deno.land/std/hogehoge/mod.ts のようにバージョン指定していない場合には、import-map を使うことで次のように記述してパッチすることも可能です。

[import_map.json]

{
  "imports": {
    "https://deno.land/std/hogehoge/mod.ts": "https://deno.land/std@0.160.0/hogehoge/mod.ts"
  }
}

アップグレードチェッカーの追加

Deno には、deno up grade という最新バージョンを取得できるサブコマンドが同梱されています。 今回のリリースから、Deno は、利用可能な最新バージョンをチェックし、プロンプトを表示するようになりました。

この機能は、1日に1回しか動きません。また環境変数 DENO_NO_UPDATE_CHECK=1 を設定することで完全に無効化できます。

Deno API の変更

安定化

以下のAPIは安定化となり、実行時に --unstable が不要になりました。

  • Deno.consoleSize()
  • Deno.futime()
  • Deno.futimeSync()
  • Deno.loadavg()
  • Deno.osRelease()
  • Deno.stdin.setRaw()
  • Deno.utime()
  • Deno.utimeSync()

仕様などの変更

仕様変更

  • Deno.kill() の第2引数には、Signalの設定が必要でしたが、このリリースから省略可能になりました。引数を省略した場合、SIGTERM シグナルが送信されます。

API追加

  • TcpListenOptions.reusePort オプションが追加 Linux でのみサポートされており、実行時には、--unstable が必要です。 複数のプロセスが、同じアドレスとポートを読めるようになります。

名称変更

  • Deno.getGid()は、Deno.gid()に名称変更されました
  • Deno.getUid()は、Deno.uid()に名称変更されました

V8 バージョンアップ

Deno 1.27 に同梱される V8 のバージョンが、10.8になりました。

このリリースより、以下に示す、Array.prototype.toReversed() -> Array に代表される新しいAPIが使用できます。

$ deno
Deno 1.27.1
exit using ctrl+d, ctrl+c, or close()
> const arr = [1,2,3]
undefined
# 既存のAPI .reverse() 元の配列 arr を変更する
> arr.reverse()
[ 3, 2, 1 ]
> arr
[ 3, 2, 1 ]
# 新しいAPI .toReversed() 元の配列 arr を変更しない
> arr.toReversed()
[ 1, 2, 3 ]
> arr
[ 3, 2, 1 ]

その他

  • Node.js 互換性の向上
    Node.js 互換性レイヤーのテストスイートが Node.js の最新LTS 18.12.0 に合わせられました
  • 言語サーバーと、統合開発環境の改善
    • Inlay Hint の追加 ソースコードに記述の無い型情報の表示など可読性の向上に寄与します
    • deno.land/x に登録されたモジュールをエディタが補完できるようになりました

まとめ

Deno の npm 互換性の向上が特に目立ったように感じたリリースでした。 最近は Vite が Deno で動かせるようになったりと、これまで様子見をしていた方にも現在の業務の延長線上で手を出しやすい環境がより整ってきています。

Deno 1.28も公開済みとなり、大きな取っころでは npm:の使用に、--unstable を付ける必要がなくなり安定化になりました。 こちらも追いかけていきます。

P.S.

採用

虎の穴では一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
yumenosora.co.jp

LINEスタンプ

エンジニア専用のメイドちゃんスタンプが完成しました!
「あの場面」で思わず使いたくなるようなスタンプから、日常で役立つスタンプを合計40個用意しました。
エンジニアの皆さん、エンジニアでない方もぜひスタンプを確認してみてください。 store.line.me