このすみろぐ

とあるWebエンジニアが、技術や趣味について書くブログです。

tscでソースディレクトリが1つの場合と複数の場合の出力先の違いについて

プログラミングTypeScriptを読む進めているのですが、tscコンパイラの出力時の動きに、気になる挙動を発見しました。

ソースディレクトリが1つでコンパイルした時の出力先

tsconfig.jsonは、"outDir": "./dist"としている状態です。 コンパイルすると、dist/配下にtest.tsが出力されます。

$ tree src
src
└── test.ts

$ npx tsc

$ tree dist/
dist/
└── test.js

ソースディレクトリが複数でコンパイルした時の出力先

先ほどの例に、src2を追加して検証します。

$ tree src
src
└── test.ts
$ tree src2
src2
└── test2.ts

$ npx tsc

$ tree dist/
dist/
├── src
│   └── test.js
└── src2
    └── test2.js

出力結果を確認すると、test.jsの出力先が変わっていることが分かります。

ソースディレクトリが1つの場合は、test.jsはdist/配下に直接展開されていました。 ところがソースディレクトリを2つに増やした途端、test.jsの出力場所はdist/src/配下に変化しました。

rootDirの未設定が原因である

この挙動さが発生する理由は、tscコンパイラにソースディレクトリのパスを明示していないことが原因でした。 たとえば、tsconfig.jsonで "rootDir": "./"と明示した状態で、再度コンパイルしてみます。

$ tree src/
src/
└── test.ts

$ npx tsc

$ tree dist/
dist/
└── src
    └── test.js

今度はtscコンパイラが起点とするディレクトリを明示しているため、ソースディレクトリが1つであってもdist/src配下に出力されていることがわかります。

まとめ:tsconfig.jsonのrootDirは明示的に指定したほうが良い

予期せぬディレクトリ階層でJSファイルが出力されることを防ぐため、tsconfig.jsonのrootDirは明示するほうが良さそうです。

参考:tsconfig.jsonの各種ディレクトリオプション

Programming Fieldさんの記事が参考になりました。

rootDir を指定しなかった場合は、全ての入力ファイルで共通の親ディレクトリを rootDir として扱い、前述のルールにのっとって出力先を決定します。

  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」の2つである場合 → rootDir は「src/main」の扱いとなる
  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」と「src/gen/pork.ts」の3つである場合 → rootDir は「src」の扱いとなる
  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」と「src/gen/pork.ts」と「externals/banana.ts」の4つである場合 → rootDir は「.」(プロジェクトディレクトリと同じ)の扱いとなる

www.pg-fl.jp