writeFileSyncは実行ディレクトリからの相対パスで注意が必要
nodejsのrequireは実行されるファイルからの相対パスが使われるのに対して、writeFileSyncはファイルを実行したディレクトリからの相対パスが使われるので混同していたらハマることになる。
これをサンプルコードを元に示す。
サンプルコード
main.js
とgreet.js
をnodetest
ディレクトリ以下に作成する。それぞれコードは下記。
main.js
const fs = require('fs');
const Greet = require('./greet.js');
Greet.sayHello();
fs.writeFileSync('./data/data.txt', 'Hello');
dataディレクトリは別途作成しておく。
greet.js
module.exports = {
sayHello: () => {
console.log('hello');
}
};
これをnodetestディレクトリから実行
[yamanaka@118-27-1-231 nodetest]$ node main.js
hello
問題なく実行される。
それではこれを一つ上の階層から実行する。
node nodetest/main.js
hello
internal/fs/utils.js:299
throw err;
^
Error: ENOENT: no such file or directory, open './data/data.txt'
at Object.openSync (fs.js:474:3)
at Object.writeFileSync (fs.js:1436:35)
at Object.<anonymous> (/home/yamanaka/public_html/nodetest/main.js:4:4)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47 {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: './data/data.txt'
}
helloは出力されているので、requireでモジュールは正しくインポートができている。しかしwriteFileSyncは実行ディレクトリからの相対パスなので、そのディレクトリにはdataディレクトリが存在しない
よってエラーが起きてしまう。
まとめ
writeFileSyncに限らずファイル保存系の関数が、nodeファイルではなく、nodeファイルを実行したディレクトリをベースとしていることは、普段の開発であれば問題とはならないが、ciツールでのビルドや、cronで回す時などにはハマり得るポイントかと思われる。
必ずcd nodetest
など所定のディレクトリにまず行ってから実行しよう。