iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

やっと触ってみるDeno

こんにちは。

エンジニアのタクシです。

今日はDenoについて。

Denoとは?

公式から抜粋

Deno (/ˈdiːnoʊ/, pronounced dee-no) is an open source JavaScript, TypeScript, and WebAssembly runtime with secure defaults and a great developer experience. It's built on V8Rust, and Tokio.

(by deepL)

Deno (ディーノと発音する) はオープンソースJavaScript、TypeScript、WebAssemblyランタイムで、セキュアなデフォルトと優れた開発者体験を備えている。V8、Rust、Tokioをベースに構築されている。

Denoは、Node.jsの開発者であるRyan Dahlが2018年のJSConfで発表した、

10 Things I Regret About Node.js

という講演の中で、Node.jsの設計における反省点を改善しよりセキュアな開発ができるよう設計したものだそうです。

(ちなみに動画内では本人はデノと言っていましたが)

実際どんな点で違いがあるのか、 物は試し、ということで、実際に使いながらその特徴を調べてみます。

Denoをインストール

(今回はMacOS向けに書いていますので、他OSの場合は公式をご確認ください!)

Terminalで以下コマンドでDenoをインストールします。

curl -fsSL https://deno.land/install.sh | sh

上記以外にもHomebrewでのインストール方法もあります↓

https://docs.deno.com/runtime/manual/getting_started/installation

インストールしたら以下のような内容が表示されると思うので、パスを通します。

Manually add the directory to your $HOME/.zshrc (or similar)
    export DENO_INSTALL="/Users/ユーザー名/.deno"
    export PATH="$DENO_INSTALL/bin:$PATH"

できたらパスが通っているか確認してみましょう。

$ deno --version

deno 1.41.1 (release, aarch64-apple-darwin)
v8 12.1.285.27
typescript 5.3.3

無事通りました。

早速簡単なWebサーバーを作成してみましょう!

Denoの特徴

実際に試しながらDenoの特徴を見ていきます。

server.tsというファイルを作成し、以下のコードを追加します。

server.ts

Deno.serve((_request: Request) => {
  return new Response("Hello, world!");
});

保存したら以下コマンドを実行してサーバーを起動しましょう!

$ deno run --allow-net server.ts

デフォルトは8000番ポートなので、ブラウザでhttp://localhost:8000にアクセスしましょう。

小さくですが、左上に「Hello, world!」が表示されています!

1. TypeScriptの標準搭載

ファイル作成の時点で気になっていたかもしれませんが、 DenoはTypeScriptが標準で使えます。 TSのインストール、tsconfig.jsonの設定などは必要はありません。 JavaScript、そしてJSX TSXもサポートしています。

2. ネットワーク、ファイルシステムへのアクセス制限

Denoはデフォルトではネットワーク、ファイルへのアクセスが制限されます。 実行時にネットワークへのアクセスを許可するためには--allow-net フラグが必要です。

$ deno run --allow-net server.ts

フラグなしで実行すると、ネットワークへのアクセスを求めるプロンプトが現れます。

$ deno run server.ts

┌ ⚠️  Deno requests net access to "0.0.0.0:8000".
├ Requested by `Deno.listen()` API.
├ Run again with --allow-net to bypass this prompt.
└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions) >

全てのアクセスを許可する-A, --allow-allフラグもあります。

$ deno run -A server.ts

フラグを付けることで、実行時に明示的にアクセスを制限することができます。 これらのオプションは他にもいくつか用意されており、 特定のアクセス先を許可・拒否できます。詳しくは以下に一覧があります。

https://docs.deno.com/runtime/manual/basics/permissions

実行時にタイプチェックも同時にするには、

--check フラグを使います。

deno run --allow-net --check server.ts

3. パッケージマネージャがない

先ほどのserver.tsを書き換えてみました。 以下のコードを見てみましょう。

server.ts

import express from "npm:express@4";

const app = express();

app.get("/", (request, response) => {
  response.send("Hello from Express!");
});

app.listen(3000);

次はexpressを使ったwebサーバーの例です。 ただ、通常expressを使った場合との違いが一点あります。 それが以下のimportの部分です。

import express from "npm:express@4";

Denoは標準ではパッケージマネージャは使用しません。 package.jsonやnode_modulesも必要ありません。 ですが、npmパッケージやNode.jsの標準モジュールへの互換性も担保されています。 (まだ完全ではないようですが) 利用する際には、モジュールのimport時にnpm:node: のように指定する必要があります。 cdnも使えます。 先ほど「package.jsonは使用しない」 と書きましたが、使えないわけではありません。 Node.jsからDenoに移行したい場合なども出てくると思います。 その時は、package.jsonをもとにDenoが依存関係を解決してくれます。 https://docs.deno.com/runtime/manual/node/package_json

4. Deno標準ライブラリ

先ほどはサードパーティーのライブラリを使う場合でしたが、 Denoにはスタンダードライブラリというものが存在します。 fs、assertEqualなどはスタンダードライブラリからimportすることで使うことができます。 以下はスタンダードライブラリを使用した簡単なtestの例です。

import { assertEquals } from "https://deno.land/std@0.218.0/assert/mod.ts";

interface Person = {
    lastName: string;
    firstName: string;
}

const sayHello = (p: Person): string => {
    return `Hello, ${p.firstName}!`;
}

Deno.test("sayHello function", () => {
  const grace: Person = {
    lastName: "Hopper",
    firstName: "Grace",
  };

  assertEquals("Hello, Grace!", sayHello(grace));
});

“https://deno.land/std@0.218.0/assert/mod.ts"

というURLからassertEqualsモジュールをimportしています。 この、std@0.218.0が、スタンダードライブラリの最新版です。 (移行stdと記載しています) stdに限らず、Denoでは、URLからコードを読み込み、リモートモジュールを使用することができます。(cdnなど) また、リモート・ローカルかぎらず、Deno上で別ファイルのモジュールをimportするときは、拡張子まで含めなければなりません。(npm:、node:の場合は除く) ただ、stdは頻繁に使うことが予想されるため、毎回URLを書いていくのはなかなか効率悪いですよね、、 その場合は、deno.json というファイルに設定ができます。

deno.json

{
  "imports": {
    "std/": "https://deno.land/std@0.218.0/"
  },
}

このdeno.jsonの内容でassertEqualsを使いたいときは、

import { assertEquals } from "std/assert/mod.ts";

とすれば毎回URLをフルで入れる必要はありません。 Denoは、package.jsonやnode_modulesを使わずに、 import mapsという機能を利用しています。 他にもlint、fmt(formatter)、taskなど、 さまざまな設定ができるようです。 https://docs.deno.com/runtime/manual/getting_started/configuration_file

最後に

感覚的には結構シンプルで使いやすい!とは思いました。 (特に設定が最小限なところ、、) ただ、実際にゴリゴリ使うか、はまた別な気がします。 third-partyライブラリなどとの互換性や、他フレームワークを乗せた時にどうなるのか、 など色々試していくのは面白いかとは思いますが、 大規模開発などで導入するのはなかなか想像しづらい、、(個人的)

実際のところ、Denoのシェアはまだ小さいように思います。

Statistaの調査(2023時点)によると、 Node.jsを使用している割合が42.65%に対し、 Denoを使用している割合は2.36%となかなか大きな差がありますね。

ただ、クラウドサービスやReactなどにも対応してはいる(対応するためのライブラリがある)ので、 そこも試してみようかとは思います。

この記事を読んで興味を持って下さった方がいらっしゃればぜひカジュアル面談でお話ししましょう!是非ご応募ください! Wantedly / Green

参考資料 https://docs.deno.com/runtime/manual https://deno.com/learn/nodes-security-problem