BrowserSync が勝手にパスを変えてきやがるので矯正する
BrowserSync を使って開発しているのだが、何故かリンクのパスを勝手に書き換えてきやがって「Can't GET」エラーが発生してしまう。
本来、次のような URL に遷移するリンクなのだが、
/about/search.html
なぜだか次のようなパスに変換されてしまう。
/about/search/index.html
リンクは当然、
<a href="./about/search.html">リンク</a>
このように書いているので、間違われるはずがない。しかし現状、どうしてもこのように間違ったパスに変換されてしまうのだ。
頭に来たので調べたところ、Express と同様のミドルウェアを自分で定義できるらしいので、次のようなミドルウェアを書いて、強制的に対象のファイルが表示できるように直してやった。
const browserSync = require('browser-sync').create();
// ファイルの存在チェックを行う関数
function isExist(targetPath) {
try {
fs.statSync(targetPath);
return true;
}
catch(_error) {
return false;
}
}
browserSync.init({
middleware: [
// 勝手に `/path/to/file.html` へのリンクを `/path/to/file/` でアクセスしようとしてエラーになりやがるので置換する
// `req.url` はスラッシュ始まり・スラッシュで終わる
(req, _res, next) => {
if(isExist(`./public${req.url}index.html`)) {
// `/path/to/file/` に変換された時、`/path/to/file/index.html` が存在するならその内容を返す
req.url = `${req.url}index.html`;
}
else if(isExist(`./public${req.url.replace((/\/$/u), '.html')}`)) {
// `/path/to/file/index.html` が存在せず `/path/to/file.html` が存在するならそのファイルへのパスを返す
req.url = `${req.url.replace((/\/$/u), '.html')}`;
}
next();
}
// ……
});
このように、req.url
を書き換えるという方法で、遷移先 URL と参照する HTML ファイルを調整してやるのだ。
ブラウザのアドレスバーの表示は /path/to/file/
のまま変わらないが、とりあえずやりたいように出来たし、不具合はなさそう。
あと、コレまで serve
という npm パッケージで静的な確認をしていたが、この serve
も、同様に /path/to/file.html
へのリンクを /path/to/file/index.html
と解釈したがる癖があって頭に来たので、捨ててやった。
今は代わりに sirv-cli
を使っている。コチラはそのようなバカなパス変換をしないので良い子。