年を跨いでしまいましたがこの記事はDenoアドベントカレンダー2023の記事です。
Denoでコンパイル時に動的に情報を渡したいなと思い、ドキュメントを見ていたところ以下の3行の記載を発見した。
Script arguments can be partially embedded.
> deno compile --allow-read --allow-net https://deno.land/std/http/file_server.ts -p 8080
> ./file_server --help
説明がこれしかないが、要するにコンパイル時に渡した-p 8080
は生成されたバイナリに埋め込まれるよということらしい。
試しにdeno compile
に引数を渡したところ、コンパイル時に指定した引数が生成されたバイナリの引数に組み込まれることがわかった。
この挙動はあまり馴染みがなかったので、興味を持っていくつか試してみた。
console.log(Deno.args);
# まずはdeno run
$ deno run args.ts
[]
$ deno run args.ts args_1
["args_1"]
$ deno compile args.ts # 引数なし
Compile file:///home/jlandowner/args.ts to args
$ ./args
[]
$ ./args args_1
["args_1"]
$ deno compile args.ts compile_1 # 引数を1つ指定
Compile file:///home/jlandowner/args.ts to args
$ ./args
["compile_1"] # 第一引数にコンパイル時に指定した引数が組み込まれている
$ ./args args_1
["compile_1", "args_1"] # 実行時に指定した引数はその後に入る
$ ./args args_1 args_2
["compile_1", "args_1", "args_2"]
$ deno compile args.ts compile_1 compile_2 # 引数を2つ指定
Compile file:///home/jlandowner/args.ts to args
$ ./args
["compile_1", "compile_2"] # コンパイル時に複数の引数を指定した場合も同様
$ ./args args_1
["compile_1", "compile_2", "args_1"] # 実行時に指定した引数はその後に入る
$ ./args args_1 args_2
["compile_1", "compile_2", "args_1", "args_2"]
deno compile
に引数を指定すると生成されたバイナリの引数に組み込まれることがわかった。
deno compile
に引数を指定する想定のスクリプトに対してdeno run
を行うと引数がないと想定外の挙動になるので注意が必要だが、ドキュメントの例のようにDeno標準パッケージstd/cli
のparseArgs
と使うことでやりたかったことができた。
import { parseArgs } from "https://deno.land/std@0.211.0/cli/parse_args.ts";
console.log(parseArgs(Deno.args));
$ deno compile parse_args.ts --opt compile_1
Compile file:///home/jlandowner/parse_args.ts to parse_args
$ ./parse_args
{ _: [], opt: "compile_1" }
$ ./parse_args --opt arg_1
{ _: [], opt: "arg_1" }
Deno標準パッケージstd/cli
のparseArgs
はminimistの仕様をベースとしているため、同じオプションが指定された際は後に指定された方が優先される。
ちなみにparseArgs
自体にもデフォルト値を設定する機能や他のスキーマライブラリ等で設定できるので、自分のスクリプトに対して単にデフォルト値を設定するだけでは上記の方法を使うメリットは特にない。
そうではなく、サードパーティのツールに対して自分の環境特有の独自のデフォルト値を埋め込めたり、コミットしたくない情報など埋め込んだ独自のバイナリを作っておく場合に使える(これがやりたかった)
NOTE: Deno標準パッケージ
std/cli
のparseArgs
は同じ名前のnode:util
のparseArgs
とは仕様が異なるため注意が必要。
std/cli
のparseArgs
仕様: https://github.com/minimistjs/minimistnode:util
のparseArgs
仕様: https://nodejs.org/api/util.html#utilparseargsconfig
deno install
でも
同じような挙動になることがわかった。
$ deno install args.ts
✅ Successfully installed args
/home/jlandowner/.deno/bin/args
$ cat /home/jlandowner/.deno/bin/args
#!/bin/sh
# generated by deno install
exec deno run --no-config 'file:///home/jlandowner/args.ts' "$@"
deno install
の場合、単に生成されるシェルに対してinstall時に指定した引数が直接埋め込まれていることが確認できた。
$ deno install args.ts compile_1 # 引数を1つ指定
✅ Successfully installed args
/home/jlandowner/.deno/bin/args
$ cat /home/jlandowner/.deno/bin/args
#!/bin/sh
# generated by deno install
exec deno run --no-config 'file:///home/jlandowner/args.ts' compile_1 "$@"
deno compile
でも恐らく生成されたバイナリの内部ではdeno install
と同じような形でコンパイルがされているのかなと推測している。