BLOGサブスレッドの日常

2020.05.10

Denoがついに1.0になるので、特徴をまとめた

s.kono

Deno 1.0 will be released immediately!

Deno 1.0に関する記事を見ました。

JavaScript/TypeScriptが好きな僕は、Denoを作るということが発表された時「すごい面白いものがくる!」と思いました。僕の中で、Node.jsはよく出来たツールだったので、それと同じようなものが生まれようとするとは思っていなかったのです。
面白いと思ったのは僕だけではなく、当時たくさんの人がそう感じたはずです(このissueからもそう感じました)。

あれから二年弱、ついにDeno 1.0がリリースされるということで、深夜についその記事を読みふけってしまいました…。

本記事では、Deno 1.0に関する記事に書かれていたことと、denoのドキュメントを眺めて集めた情報をまとめます。
超訳も一部取り入れようと思ったんですが、記事のコメントを見ると、記事自体の翻訳を許可していなさそうなので、自分なりの表現でまとめました。


Denoとは

JavaScript/TypeScriptの実行環境です。JavaScriptやTypeScriptが書かれたテキストファイルを読み込ませると、そのテキストファイル内のプログラムを実行してくれます。
つまりJavaScriptの実行環境であるNode.jsとの競合ということになります。

面白いのは、Node.jsもDenoも、作者は同じRyan Dahl (ry)さんだということです。

ryさんはNode.jsを作ってメンテナから外れた後、後悔したことがたくさんあったようです。Denoは、その後悔に基づき、ryさんが新たに作成したプロダクトです。

Denoがどうして生まれたかは、下記の記事をお読みください。すごく面白いです。

特徴

セキュリティ

  • Denoはサンドボックス内で実行される
    • サンドボックス内では、ファイルシステムやネットワークへのアクセス、サブプロセスの作成などができない
    • ファイルシステムやネットワークへのアクセス、サブプロセスの作成などを行うにはパーミッションの指定が必要
      • パーミッションの指定を行わず、例えばファイルシステムへのアクセスを行うAPIを実行した場合、PermissionDenied例外が発生する
  • パーミッションの指定は、Denoを使ってプログラムを実行する時の引数で行う
    • 例えば、ファイルの読取りを許可する場合はdeno run --allow-read my-script.tsのようなコマンドを発行する
    • deno run -A my-script.ts のように-Aオプションを加えると、全てのパーミッションを許可した状態でプログラムを実行できる
      • しかし、プログラムに必要以上のパーミッションを与えるのは推奨されない
    • deno --allow-read=/etc my-script.tsのように、権限を適切に指定することが推奨されている
      • この場合/etc内のプログラムの読取のみ許可させることができる
  • コマンドでの実行時、パーミッションの指定を毎回行うのは面倒。解決する方法は、下記が挙げられる
    1. bash scriptを作る
    2. Drakeなどのタスクランナーを使用する
    3. Denoプログラムをインストールする

標準ライブラリ

ビルドインツール

  • Denoには標準でいくつかのツールが付属している
    • テストランナー(deno test)
    • コードフォーマッタ(deno fmt)
    • バンドラー(deno bundle)
      • webpackのように複数のJavaScript/TypeScriptプログラムを一つにまとめるツール
    • デバッガー
    • ドキュメントジェネレータ(deno doc)
    • モジュール依存関係を見るツール(deno info)
    • lintツール(deno lint)

tsconfig.json

  • DenoはJavaScriptだけでなく、TypeScriptプログラムの実行も可能であるため、tsconfig.jsonの指定が可能
  • プログラム実行時に-cオプションをつけることで、任意のtsconfig.jsonを指定することが可能
    • deno run -c tsconfig.json my-script.ts
    • サポートされているパラメータと、Denoでのデフォルト値はCustom TypeScript Compiler Optionsを参考のこと

Web互換API

  • Denoにはfetch APIが標準で実装されている
    • Node.jsでは標準で実装されておらず、Node Fetchが必要だった
  • fetch API以外にも、DenoにはたくさんのWeb互換APIが用意されている
  • Denoで動かすプログラムは、ブラウザでもDenoでも動くようにすべき
    • Deno名前空間下にあるメソッドを使用しないほうが良い

import時の拡張子

  • Denoでモジュールを読み込ませる時はファイル拡張子が必須
    • 例) import { MyClass } from './my-script.ts'
  • しかし、import文に拡張子を書くと、IDEに文法エラーがあると怒られてしまう
    • この問題は、今はVSCode拡張を導入し、Deno向けのプロジェクト内で有効化することで解決できる

パッケージマネージャ

  • Denoには中央パッケージマネージャがない
    • つまりNode.jsで言うところのnpmがない
    • Denoで、サードパーティ製のプログラムを呼び出すには、import文に書くファイル名をURLにするだけでよい
      • もうNode.jsの 魔法の モジュール解決アルゴリズムはない
  • Denoでは、モジュール解決アルゴリズムとしてpackage.jsonは使わない
    • 言い換えると、package.json内のdepedenciesdevDependenciesといった辞書値は使用せず、モジュールの依存関係を解決する
  • Denoでは、モジュールのバージョン管理のために、deps.tsという特別なファイルを作成しておき、その中で使用するクラスのインポートを行うのが良いとされている
  • ダウンロードされたモジュールは、デフォルトでDenoを実行したカレントディレクトリではない、見えない場所にキャッシュされ、利用される
    • ダウンロードされたモジュールのキャッシュを読み直す場合は、--reloadオプションをコマンドに付与すれば良い
    • 見える場所にダウンロードされたモジュールのキャッシュを置く場合は、$DENO_DIR環境変数を指定する

サードパーティ製ライブラリの使用

  • DenoとNode.jsは原則APIの互換がないため、Node.js APIを使用しているサードパーティ製ライブラリはNode.jsモジュールをDenoで使用することは出来ない
  • Deno互換のサードパーティ製モジュールは、Third Party Modulesから検索可能

ファイルの監視

  • Denoでのファイル監視(nodeで言うところのwatch)は、Rustのnotifyライブラリを使って実現されている
  • ファイルの監視はいくつかの方法がある
    1. Deno.watchFs()APIを使う
    2. Denonを使う方法
      • Denonはnodeでいうところのnodemonと同じ役割のもの

Denoを試してみる (on macOS)

記事の目的とは少し離れますが、試しにDenoを使ってみた時のコマンドとコード例です。
##で始まっている行はコメントです。

DenoのインストールとHello, World!

## HomebrewでDenoのインストール
brew install deno

## Hello, World!
deno run https://deno.land/std/examples/welcome.ts

パーミッション

## ヘルプを表示
## ヘルプの中に、パーミッションのサンプルが書かれている
deno run -h

## パーミッションなしでファイルサーバープログラム起動
## PermissionDeniedでクラッシュすればOK
deno run https://deno.land/std/http/file_server.ts

## パーミッションありでファイルサーバープログラム起動
## 起動し、ブラウザからアクセスできればOK
deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts

fetch API

  • 下記をgithub-api.tsとして保存
async function fetchFromGitHub(path: string) {
    const result = await fetch(`https://api.github.com${path}`)
    return await result.json()
}

console.log('Fetching from / ...')
console.log(await fetchFromGitHub('/'))
console.log('')
console.log('Fetching from /users/octocat ...')
console.log(await fetchFromGitHub('/users/octocat'))
  • コマンドラインで実行する
deno --allow-net ./github-api.ts

ドキュメントジェネレータの使用

  • 下記をgithub-api.tsとして保存
/**
 * Fetch Data from GitHub
 * 
 * @param path URL Path
 */
export async function fetchFromGitHub(path: string) {
    const result = await fetch(`https://api.github.com${path}`)
    return await result.json()
}

console.log('Fetching from / ...')
console.log(await fetchFromGitHub('/'))
console.log('')
console.log('Fetching from /users/octocat ...')
console.log(await fetchFromGitHub('/users/octocat'))
  • コマンドラインで実行する
deno doc ./github-api.ts

まとめ

Denoの特徴やNode.jsとの違いを見てきました。

見ていて考えされられたのは、DenoはNode.jsと比べると、思ったよりも多くの違いがあることについてです。
Node.jsとのAPIの違いも多く、多くのライブラリはDeno向けに書き直し、もしくはDenoとの互換性を保つためにリファクタリングが必要になります。そのため、すぐにDenoに移行することは出来ません。

1.0になったとはいえ、サードパーティ製ライブラリは少なく、Deno自体にもまだ十分な量のAPIはまだ用意されていません。
Web技術者にDenoの良さが認められ次第、徐々にコミュニティが大きくなり、サードパーティ製ライブラリも準備され、Node.jsからDenoへゆっくりと移り変わっていくもののように思いました。
実際のプロダクトにDeno組み込まれて使われるまでにはまだ時間がかかりそうです。仕事で使用するのはまだ先だと思います。

しかしTypeScriptを組み込むなど、Denoは現在のモダンな流れともマッチしたランタイムです。
Web技術者を勢いづけるには十分な設計の良さを持っているように感じました。
僕は気持ち的には、すぐにでも使い始めたいくらいです…!

参考元URL


おまけ

Denoのロゴって何なのか

Denoのロゴの絵はDino in the rainと呼ばれているっぽい?です。つまりロゴの中に書かれているのは、ヘビでもチンアナゴでもなく、首長竜類か恐竜の竜脚類ですね。

で、ここでdoc.deno.landのAPIを見てみると。

足があって歩いてますね。ということで竜脚類の何かでした。

ちなみにうちにはこんなストラップがありまして。

かなり近くないですか。Denoって名前つけるしかない。

この記事を書いた人

s.kono