SSG 時にパスをドメインから始まるものに変更したいという要件があって、path.join
でドメインとパスを合体させてハマってしまったのでメモ
環境
- Node.js v18.18
path.join
に URL を渡すとhttps://
が https:/
になってしまう
http://
, https://
から始まる URL もパスだよね?と思って、path.join()
で結合したら protocol の //
が /
に変換されてしまい 404 な URL になってしまった
const path = require('path'); const host 1= 'https://example.com'; path.join(host1, '/foo'); // => https:/example.com/foo const host2 = 'http://example.com'; path.join(host2, '/bar'); // => http:/example.com/bar
path.resolve
はもっと壊れる
const path = require('path'); const host 1= 'https://example.com'; path.resolve(host1, '/foo'); // => /foo const host2 = 'http://example.com'; path.resolve(host2, '/bar'); // => /bar
どうやら path モジュールは URL はパスではないという扱いなのかもしれないようです
URL を組み立てる時は new URL
を使うほうが良さそう
new URL(input[, base])
input
The absolute or relative input
URL to parse. Ifinput
is relative, thenbase
is required. Ifinput
is absolute, thebase
is ignored. Ifinput
is not a string, it is converted to a string first.
base
The base URL to resolve against if the input
is not absolute. If `bas is not a string, it is converted to a string first.
new URL()
はオブジェクトを返すので .href
プロパティで結合した URL が取得できる
const host 1= 'https://example.com'; new URL('/foo', host1).href; // => https://example.com/foo const host2 = 'http://example.com'; new URL('bar', host2).href; // => http://example.com/bar
new URL は base が URL でない時はエラーになる
undefined
や URL でない文字列の時 Invalid URL
というエラーが発生する
new URL('/foo', undefined); // => TypeError [ERR_INVALID_URL]: Invalid URL new URL('/foo', '/'); // => TypeError [ERR_INVALID_URL]: Invalid URL new URL('/foo', '//'); // => TypeError [ERR_INVALID_URL]: Invalid URL
/
始まりな絶対パスにしたいケースと http
から始まる URL にしたいケースが混ざる場合は、URL にしたい時だけ new URL
に渡す場合分けが必要になる
new URL の input が URL の場合 base は無視される
パスの生成をユーティリティ化すると、input に渡される値が制御出来ない事も想定される。
new URL
の場合 input が URL だと base の値は無視される仕様になっているっぽい
const HOST = 'https://example.com' as const; const buildPath = (input: string) => { return new URL(input, HOST).href; }; buildPath('/images/sample.png'); // => https://example.com/images/sample.png buildPath('https://sample/images/test.png') // => https://sample/images/test.png
渡されるパスが /
始まりか担保されない、環境変数にあるドメインが /
で終わるか担保されない。という条件だったので、path.join()
で URL 作るのが安全やろ〜って軽い気持ちでユーティリティ作ってなんで https:/
になってるの?????ってはまってしまいました
new URL
protocol を https://
, https://
以外だと実装差もあるみたいですが、URL を組み立てる時はこちらを使ったほうが良さそう。と学びました!
学び〜 ₍ᐢ⑅•ᴗ•⑅ᐢ₎
[参考]