できた。どうやらIPC通信ではデフォルト引数を渡すとその値で固定されてしまうらしい。前回はそのせいで失敗していた模様。
ブツ
インストール&実行
NAME='Electron.fs.cp.Directory.20220829162638'
git clone https://github.com/ytyaru/$NAME
cd $NAME
npm install
npm start
- インストール&実行してアプリ終了する
- 以下ファイルが作成される(ファイルとディレクトリ両方コピー)
dst/src/lib/toastify/1.11.2/min.js
dst/src/lib/toastify/1.11.2/min.css
dst/memo/
ディレクトリとその配下にあるファイル一式
前回
Node.jsのfs.cpでファイルのコピーを試みるのとき、ディレクトリがコピーできなかった。
今回
色々試した結果、どうやらIPC通信の引数にデフォルトオプションをつけていたせいらしい。それを必須にしたら成功した。何を言っているかわからないと思うので順に説明する。
バグ調査
main.jsの以下cp
ハンドルにconsole.log
を仕込んだ。するとif
側に入ってほしいのに、実際はelse
側に入っていたことが判明した。
ipcMain.handle('cp', async(event, src, dst, options=null) => {
if (options) { console.log('aaaaaaaaa', src, dst, options); fs.cp(src, dst, options, ()=>{}); }
else { console.log('bbbbbbbbb', src, dst); fs.cp(src, dst, ()=>{}); }
})
if
の条件式をnull!=options
に変えても同様だった。
つまり、options
は必ずnull
になっていたことになる。
だが、呼出元のsite-maker.js
ではちゃんと以下のように{'recursive':true, 'preserveTimestamps':true}
というoptions
を渡している。
await window.myApi.cp(path, `dst/${this.setting.github.repo}/${path}`, {'recursive':true, 'preserveTimestamps':true}) }
なのになぜnull
になるのか? コードをみるかぎりmain.jsの以下しかない。メソッド定義の仮引数のところでoptions=null
にしている。これがそのまま入ってしまったのでは?
ipcMain.handle('cp', async(event, src, dst, options=null) => {
そんなバカな。JavaScriptはデフォルト引数にできるはず。MDNにも書いてある。
ああ、もしかしてこれもElectronのIPC通信における制約なのか? うわー、それっぽい予感。と思って確認するためにコードを書いてみた。すると案の定だった。
ディレクトリをコピーするコード
以下が成功したコード。思ったとおりデフォルト引数をやめたらディレクトリのコピーができた。
main.js
ipcMain.handle('cpdir', async(event, src, dst, options) => {
if (null!=options) { console.log('aaaaaaaaa', src, dst, options); fs.cp(src, dst, options, ()=>{}); }
else { console.log('bbbbbbbbb', src, dst); fs.cp(src, dst, ()=>{}); }
})
ようするに[fs.cp][]の引数options
を必須にした。ただしcpdir
という名前で新しくICPハンドルを作った。ファイルをコピーしたいなら先述のcp
ハンドルを使う。
preload.js
contextBridge.exposeInMainWorld('myApi', {
cpdir:async(src, dst, options)=>await ipcRenderer.invoke('cpdir', src, dst, options),
})
renderer.js
class SiteMaker {
constructor(setting) {
this.setting = setting
}
async make() {
await this.#cpdir(`memo/`)
}
async #cpdir(path) { await window.myApi.cpdir(path, `dst/${this.setting.github.repo}/${path}`, {'recursive':true, 'preserveTimestamps':true}) }
}
結論
IPC通信の制約によりIPCハンドラの引数にはデフォルト引数が使えない。仮に使ったとしたら、必ずそのデフォルト値がセットされてしまうらしい。
なんか謎のバグが起きるたびにElectronのIPC謎仕様のせいだと発覚しているなぁ。公式ドキュメントのどこかに書いてあるのかな? そのうち罠として情報をまとめておきたい。