1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Denoで作るはじめてのCLI実行ファイルハンズオン

1
Last updated at Posted at 2026-08-08

tl;dr

  • Denoには deno compile が標準搭載されており、追加ツールなしでTypeScriptを単一実行ファイルにできる
  • main.ts を書いて deno test でテストし、deno task compile でビルドするだけの最短ルートを解説
  • 生成物にはDenoランタイムが同梱されるので、配布先にDenoがなくても動く

対象読者

  • Denoを触ったことがない、または触り始めたばかり
  • TypeScriptの基本文法がわかる
  • シェル(黒い画面)でコマンド操作ができる

本記事の執筆には生成AIを利用しています

Denoには標準で単一実行ファイルを生成する deno compile が組み込まれています。
Node.jsのように pkgnexe などの外部パッケージを別途インストールする必要がなく、TypeScriptのまま書いたコードをそのままバイナリ化できます。

  • ランタイム同梱: 生成した実行ファイルはDeno本体を内包するため、実行環境にDenoがなくても動く
  • TypeScriptネイティブ: トランスパイル設定を書かなくてもそのままコンパイル可能
  • クロスコンパイル対応: --target オプションで他OS向けバイナリも生成できる

この記事では、実際に手を動かしながら Hello, world! を出力するCLIを作り、単一実行ファイルにビルドするところまでをひととおり体験します。

Step 1: プロジェクトを作る

作業用ディレクトリを作り、deno.json を用意します。

mkdir deno-cli && cd deno-cli
deno init

deno init で生成されるファイル構成は以下のとおりです。

deno-cli/
├── deno.json
├── main.ts
└── main_test.ts

Step 2: Hello, world! を出力するソースを書く

main.tsに処理本体を書きます。import.meta.mainはこのファイルが直接実行されたときだけtrueになるため、モジュールとしてインポートされたときは何も実行されません。

main.ts
export function hello(): string {
  return "Hello, world!";
}

if (import.meta.main) {
  console.log(hello());
}

書けたら、一度そのまま実行して動作を確認します。

$ deno run main.ts
Hello, world!

Step 3: lintをかける

Denoは標準でリンターを内蔵しているため、追加ツールなしでコードの静的解析ができます。

$ deno lint
Checked 1 file

Step 4: fmtをかける

フォーマッターも標準搭載です。整形が必要な箇所があれば自動で直してくれます。

$ deno fmt
Checked 1 file

Step 5: テストを書く

Denoは標準でテストランナーも内蔵しているため、追加ライブラリなしでテストが書けます。アサーションだけ @std/assert を使います。

main_test.ts
import { assertEquals } from "@std/assert";
import { hello } from "./main.ts";

Deno.test("returns Hello, world!", () => {
  assertEquals(hello(), "Hello, world!");
});

deno.jsonimports に依存を定義しておきます。

deno.json
{
  "imports": {
    "@std/assert": "jsr:@std/assert@1"
  }
}

テストを実行します。

$ deno test
running 1 test from ./main_test.ts
returns Hello, world! ... ok (756µs)

ok | 1 passed | 0 failed

Step 6: タスクを定義する

毎回長いコマンドを打たずに済むよう、deno.jsontasks に開発・テスト・ビルドの3コマンドをまとめておきます。

deno.json
{
  "tasks": {
    "dev": "deno run main.ts",
    "compile": "deno compile --output hello main.ts",
    "test": "deno test"
  }
}
  • deno task dev … ソースをそのまま実行
  • deno task test … テストを実行
  • deno task compile … 単一実行ファイルにビルド

deno lintdeno fmt はDenoに標準搭載されているため、ESLintやPrettierを別途インストールしなくてもすぐ使えます。
頻度が低く省略にもならないコマンドになるので今回はtasksに含めず、直接実行する運用にしています。

Step 7: 単一実行ファイルにビルドする

deno task compilemain.ts をバイナリ化します。

$ deno task compile
Compile main.ts to hello.exe

生成された hello.exe(Windowsの場合)を実行します。

$ ./hello.exe
Hello, world!

Denoがインストールされていない環境でも、この実行ファイル単体で動作します。配布時にランタイムの
インストール手順を案内する必要がないのは地味に嬉しいポイントです。

おまけ: cloneせずGitHubから直接実行する

deno run にはURLを渡せるため、リポジトリをcloneしなくても以下のようにGitHub上のソースを直接実行できます。

$ deno run https://raw.githubusercontent.com/hidao80/deno-cli/main/main.ts
Hello, world!

この例ではgithub.com のファイル閲覧ページのURL(blobリンク)ではなく、raw.githubusercontent.com のURLを指定する点に注意してください。

ハマりポイント

  • importパスとtasksのパスがずれる: ファイルをsrc/配下などに移動すると、main_test.tsimportパスと deno.jsontasks側パスを両方直す必要があります。片方だけ直すとテストかビルドの一方だけが壊れて気づきにくいので、移動したら両方grepして確認するのが安全です
  • 初回コンパイルは時間がかかる: deno compileをはじめて実行すると、対象OS向けのDenoランタイム本体(denort)が ダウンロードされます。2回目以降はキャッシュされるため高速です
  • Windowsでは拡張子が自動で付く: --output helloと指定しても、Windows上ではhello.exeが生成されます。 README等でパスを案内する際はOS差を意識しておくと親切です
  • deno fmtはMarkdownも整形対象: デフォルトでは .md ファイルも既定の折り返し幅で整形されてしまいます。 記事本文まで意図せず改行されて困る場合は、deno.json に以下のように fmt.exclude を設定して除外します
deno.json
{
  "fmt": {
    "exclude": ["*.md"]
  }
}

ここで紹介した内容の公開リポジトリ

まとめ

ここまでで、Hello, world! を出力するだけのシンプルなCLIをDeno + TypeScriptで書き、テストを通し、deno compile で単一実行ファイルにするまでを体験しました。
外部ツールなしでバイナリ配布まで完結するのがDenoの強みです。小さなCLIツールを手軽に配布したいときの選択肢として選べるようにしておくと便利ですね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?