はじめに
少し特殊な使い方だとは思うのですが、Node.jsの教材を作っていて
- 後から見返しやすいように全部のプログラムをひとつのディレクトリ以下に置く
- 章ごとにサブディレクトリに分ける
というやり方をしていました。
で、fsモジュールを説明する段階になって以下のようなプログラムを書きました。
const fs = require('fs');
fs.writeFile('test.txt', 'This is test file', function(err) {
if (err) throw err;
console.log('OK');
});
fs_sample.jsはchap2ディレクトリに置いています。
あれ?なんでルートディレクトリにできてるの?ひょっとしてプログラム実行するときルートディレクトリがカレントディレクトリになってる?
と、まあこの場合なら別にいいのですが、今後Expressに入っていくと非常にまずい。というわけで対策を行いました。
launch.json設定
多分、launch.jsonで実行するファイルのあるディレクトリをカレントディレクトリにする設定書けばいいんだろうな、カレントディレクトリはcwdだろうから、後はファイルのディレクトリが取れるかと調べてみたところ、
https://code.visualstudio.com/docs/editor/variables-reference
${fileDirname} - the current opened file's dirname
はい、ありました。これで勝てます。
というわけで以下のようなlaunch.jsonを作成。実際にはテンプレで作られるものにcwdを付け足しただけです。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "プログラムの起動",
"program": "${file}",
"cwd": "${fileDirname}"
}
]
}
fs_sample.jsを再実行。fs_sample.jsがあるchap2ディレクトリにtest.txtが作成されるようになりました。
余談:requireの動作
fsモジュール、つまりモジュール周りの話を書いてて今回の件に遭遇したわけですが、ふと、「あれ?requireで同じディレクトリにある別ファイル読み込むのもまずい?」と思いましたがそちらはlaunch.json書かなくても大丈夫でした。
何故なら、
https://nodejs.org/dist/latest-v8.x/docs/api/modules.html#modules_file_modules
A required module prefixed with './' is relative to the file calling require().
というわけで、requireはrequireを呼び出しているファイルとの相対位置でどのファイルかが決定されるようです。
まあ確かにそりゃそうか。node_modulesに入ってる各パッケージは自分のファイルを相対パスで読んでるだろうしな。