タスクランナーとは、コマンドに対してショートカットを設定しておくことができる機能です。サーバー立ち上げやビルド用のコマンドをあらかじめタスクランナーに設定しておくことで、開発体験を向上することができます。Node.jsではnpm scriptsが一般的に使われています。
Deno1.20では、タスクランナーがDeno CLI本体に入りました。基本的にはnpm scriptsと同じ機能なのですが、デフォルトでクロスプラットフォーム対応になっているなど、違う所もあります。
deno task コマンドの使い方
タスクの設定
まず、deno.json(c)でタスクの内容を設定します。
※deno.json(c)の構文についてはこちらの記事を参照してください。
{
"tasks": {
// "<タスク名>": "<タスク内容>" の形で定義する
// deno task hello
"hello": "deno eval \"console.log('hello')\"",
// deno task world
"world": "deno eval \"console.log('world')\"",
// deno task args hello world # output: ["hello", "world"]
"args": "deno eval \"console.log(Deno.args)\"",
"echo": "echo hello world",
"nesting": "echo $(deno eval \"console.log('hello world')\")",
"concat1": "echo 1 && echo 2",
"concat2": "deno eval \"Deno.exit(1)\" || echo 2",
"pipe": "echo hello world | deno eval \"Deno.stdin.readable.pipeTo(Deno.stdout.writable)\"",
"var": "VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\"",
"export": "export VAR=hello && echo $VAR && deno eval \"console.log(Deno.env.get('VAR'))\""
}
}
このdeno.jsonを置いたディレクトリより下層のディレクトリでは、定義したタスクが有効になります。
タスク名として使えるのは英数字+コロン(1文字目は必ず英字)です。(^[A-Za-z][A-Za-z0-9_\\-:]*$
)
以下、このdeno.jsonを使って解説していきます。
タスクを実行
ターミナルでdeno task <タスク名>
というコマンドを打つと、タスクが実行されます。
> deno task hello
Warning deno task is unstable and may drastically change in the future
Task hello deno eval "console.log('hello')"
hello
タスク名の後に引数を渡すと、その引数はそのままコマンドに渡されます。
> deno task args hello world # hello worldが引数の部分
Warning deno task is unstable and may drastically change in the future
Task args deno eval "console.log(Deno.args)" "hello" "world"
[ "hello", "world" ]
タスクのリストを表示
ターミナルでdeno task
コマンド(引数無し)を打つと、タスクのリストが表示されます。
> deno task
Warning deno task is unstable and may drastically change in the future
Available tasks:
- args
deno eval "console.log(Deno.args)"
- concat1
echo 1 && echo 2
- concat2
deno eval "Deno.exit(1)" || echo 2
- echo
echo hello world
# ...(以下略)
タスクの文法
コマンドの連結や入れ子、glob展開がサポートされています。
複数コマンドの実行
文法 | 意味 |
---|---|
<command1> && <command2> |
command1 が成功(exit code 0)したらcommand2 を実行する |
<command1> || <command2> |
command1 が失敗(exit code 1)したらcommand2 を実行する |
<command1> ; <command2> |
command1 が終了したら成功・失敗に関係なくcommand2 を実行する |
<command1> & <command2> |
command1 とcommand2 を並列に実行する |
# 1つ目が成功したら2つ目を実行
echo hello && echo world
# 1つ目が失敗したら2つ目を実行
echo hello || echo world
# 1つ目が終了したら2つ目を実行
echo hello ; echo world
# 1つ目と2つ目を並列実行
echo hello & echo world
出力のパイプ・リダイレクト
文法 | 意味 |
---|---|
command1 | command2 |
command1 のstdoutをcommand2 にパイプする |
command1 |& command2 |
command1 のstdoutとstderrをcommand2 にパイプする |
command > filename |
command1 のstdoutをファイルにパイプする(ファイルを上書き) |
command 2> filename |
command1 のstderrをファイルにパイプする(上書き) |
command &> filename |
command1 のstdoutとstderrをファイルにパイプする(上書き) |
command >> filename |
command1 のstdoutをファイルにパイプする(追記) |
# 1つ目のstdoutを2つ目のstdinに渡す
echo hello world | deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)'
# 1つ目のstderrを2つ目のstdinに渡す
deno eval 'console.log(1); console.error(2);' |& deno eval 'Deno.stdin.readable.pipeTo(Deno.stdout.writable)'
# stdoutをファイルに出力する
deno eval 'console.log(1); console.error(2);' > file.txt
# stderrをファイルに出力する
deno eval 'console.log(1); console.error(2);' 2> file.txt
# stdoutとstderrをファイルに出力する
deno eval 'console.log(1); console.error(2);' &> file.txt
# stdoutをファイルに追記する
deno eval 'console.log(1); console.error(2);' >> file.txt
# stderrをファイルに追記する
deno eval 'console.log(1); console.error(2);' 2>> file.txt
# stdoutとstderrをファイルに追記する
deno eval 'console.log(1); console.error(2);' &>> file.txt
出力の破棄
/dev/null
へリダイレクトすることで出力を捨てることができます。(Windowsでも動作)
# stdoutを破棄する
deno run main.ts > /dev/null
# stderrを破棄する
deno run main.ts 2> /dev/null
# stdoutとstderrを破棄する
deno run main.ts &> /dev/null
シェル変数と環境変数
シェル変数はシェル内でのみ参照できる変数、環境変数は生成したプロセス内でも参照できる変数です。
文法 | 意味 |
---|---|
VAR_NAME=<val> |
シェル変数VAR_NAME に値を代入する(値は生成したプロセス内で利用できない) |
export VAR_NAME=<val> |
環境変数VAR_NAME に値を代入する(値は生成したプロセス内で利用できる) |
$VAR_NAME |
シェル変数や環境変数を使用する |
VAR=hello && echo $VAR
export VAR=hello && deno eval "console.log(Deno.env.get('VAR'))"
VAR=hello && echo $VAR
コマンドの入れ子
文法 | 意味 |
---|---|
$(<command>) |
コマンドを入れ子にする |
echo $(deno eval 'console.log(1)')
終了コードの反転
文法 | 意味 |
---|---|
! <command> |
コマンドの終了コードの失敗/成功を反転する |
# 終了コードを反転させる
! deno eval 'Deno.exit(1)' # exit codeは0
! deno eval 'Deno.exit(0)' # exit codeは1
glob展開
Deno v1.34以降、ファイル名に対してglob展開を行うことができます。
rustのglobライブラリを使用して実装されているようです。そのドキュメントによると使用できる構文は以下のものです。
文法 | 意味 |
---|---|
? |
任意の1文字に一致 |
* |
任意の文字列に一致 (空文字列にも一致) |
** |
カレントディレクトリと任意のサブディレクトリに一致 ただし、 **a やb** , *** のような構文はエラー |
[...] |
括弧内の任意の文字と一致 (例: [0-9] /[a-b] /[abc] )Unicode順に従って文字の範囲を指定することができる |
[!...] |
括弧内にない任意の文字と一致 (例: [!0-9] /[!a-b] /[!abc] ) |
メタ文字(?
, *
, [
, ]
)自体にマッチさせたい時は、各括弧[]
構文を使用してマッチできます。(例: [?]
)
-
[[]
と[]]
はそれぞれ[
と]
という文字に対してマッチする。 -
[![]
と[!]]
も同様に、それぞれ[
と]
という文字以外に対してマッチする。 -
[...]
内で-
という文字にマッチさせたい時は、先頭か末尾に配置する
(例:❌[a-b]
、⭕[-ab]
)
# カレントディレクトリより下層にあるすべての.tsファイルにマッチ
echo **/*.ts
# カレントディレクトリの.tsファイルにマッチ
echo *.ts
# data0.csv から data9.csv まで連番でマッチ
echo data[0-9].csv
クロスプラットフォーム対応
npm scriptsの場合、Windows/Linux/Mac OSの間でクロスプラットフォームなコマンドを書くためにはshxなどのパッケージをインストールする必要がありました。
(例えばrm
などはwindowsに存在しないので、こうしたパッケージを通して使う必要があった)
一方、deno taskではクロスプラットフォーム対応のコマンドが最初から組み込まれています。
Deno1.34時点では以下のコマンドがデフォルトで組み込まれており、Windowsでも追加パッケージ無しで使えるようになっています。
-
cp
: ファイルをコピーする -
mv
: ファイルを移動する -
rm
: ファイルを削除する(例:rm -rf [FILE]...
) -
mkdir
: ディレクトリを作成する(例:mkdir -p DIRECTORY...
) -
pwd
: カレントディレクトリを表示する -
sleep
: n秒待つ(例:sleep 1
) -
echo
: 文字列を表示する -
cat
: ファイルの内容を読み取って出力する (ファイルが指定されていない場合はstdinを読み取って出力する) -
exit
: シェルからexitする -
unset
: 環境変数を削除する(例:unset VAR_NAME
) -
xargs
: 標準入力から渡されたデータを引数に渡す
使い方については、同名のUnixコマンドと同じです。
これらのコマンドがなぜWindowsでも使えるのかというと、deno_task_shellリポジトリでシェルごと実装されているからです。もし他に追加してほしいコマンドがあれば、このリポジトリでissueを開くと追加してくれるそうです。
LinuxやMacでこの組み込みコマンドではなくOSのコマンドを使用したい場合は、sh
コマンドを使います(例:sh -c cp source destination
)
まとめ
- deno.json(c)でタスクを使うと
deno task
コマンドから利用可能 - デフォルトでクロスプラットフォーム対応している
従来は、Denoのタスクランナーとしてvelociraptorやmakefileが使われていました。一方で、Deno本体にクロスプラットフォームなタスクランナーを搭載してほしいという要望もあり、deno taskが実装されました。
これからは3rd party製のツールに頼ることなく、タスクランナーを使うことができます。
最近では標準ライブラリにdotenv
モジュールが追加されるなど、基本的に全員がインストールすることになるツールはデフォルトで使えるようになっているのがDenoの嬉しい所です。