LoginSignup
6
1

More than 1 year has passed since last update.

mini_racerでNode.jsのURL APIを使うときに注意すること

Posted at

結論

正確にはmini_racerを使う時に限ったことではないのですが、Node.jsのAPIのURLには、legacy APIとWHATWG準拠のAPIがあることに注意しましょう

(ブラウザのURL APIもWHATWG API準拠)

上記のAPIドキュメントから引用します。

下の図は'https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash'というURLを両方のAPIでパースしたときの違いを表しています。
上半分がlegacy APIのurl.parse()を使ったときで、下半分がWHATWGのURLオブジェクトのプロパティを表しています。
originプロパティなど、いろいろ違いがあります。

┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                              href                                              │
├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
│ protocol │  │        auth         │          host          │           path            │ hash  │
│          │  │                     ├─────────────────┬──────┼──────────┬────────────────┤       │
│          │  │                     │    hostname     │ port │ pathname │     search     │       │
│          │  │                     │                 │      │          ├─┬──────────────┤       │
│          │  │                     │                 │      │          │ │    query     │       │
"  https:   //    user   :   pass   @ sub.example.com : 8080   /p/a/t/h  ?  query=string   #hash "
│          │  │          │          │    hostname     │ port │          │                │       │
│          │  │          │          ├─────────────────┴──────┤          │                │       │
│ protocol │  │ username │ password │          host          │          │                │       │
├──────────┴──┼──────────┴──────────┼────────────────────────┤          │                │       │
│   origin    │                     │         origin         │ pathname │     search     │ hash  │
├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
│                                              href                                              │
└────────────────────────────────────────────────────────────────────────────────────────────────┘

また、パースの仕方も、legacy APIではモジュールをimportした上でurl.parse()をするという違いがあります。

// WHATWG API
const myURL = new URL('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');
// legacy API
import url from 'node:url';

const myURL = url.parse('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');

はまった点

JavaScriptランタイムとしてmini_racerを使っている環境でURL APIを使おうとしました。
mini_racerはJavaScriptエンジンとしてV8を使っているのですが、ブラウザやNode.jsとは違ってURL APIが実装されていません。

そのため、最初は以下のnode-urlのパッケージを使おうとしていました。

このパッケージはwebpack 4までfallbackとして自動で追加されていたものです。

しかしこのパッケージはNode.jsのURLモジュール (legacy API)を提供しているもので、WHATWG準拠のAPIのように new URL()のように使えませんでした。
Node.jsのURL APIには2種類あるのを知りませんでした...

対応方法

whatwg-urlを用いて、ブラウザと同様にWHATWG準拠のURL APIを使いました。

import { URL, URLSearchParams } from 'whatwg-url'

const url = new URL('https://qiita.com')
const params = new URLSearchParams('?param=value')

残りの課題

例えばSSRしているコンポーネントでブラウザ上でも実行したい場合、上記の方法でも実行できますが、ブラウザにはURL APIが実装されているため、不要なソースコードをimportしてしまっていることになります。

そのため以下のように、globalThisにURL APIが実装されているかを判定して使うAPIを判定する処理を入れたいと思っています。

util/universal-url.js
import {
  URL as whatwgURL,
  URLSearchParams as whatwgURLSearchParams,
} from 'whatwg-url'

let hasNative
let outputURL
let outputURLSearchParams

try {
  const url = new globalThis.URL('https://qiita.com')
  const params = new globalThis.URLSearchParams('?param=value')
  hasNative = 'searchParams' in url && params.get('param') === 'value'
} catch (error) {
  hasNative = false
}

if (hasNative) {
  outputURL = globalThis.URL
  outputURLSearchParams = globalThis.URLSearchParams
} else {
  outputURL = whatwgURL
  outputURLSearchParams = whatwgURLSearchParams
}

export { outputURL as URL, outputURLSearchParams as URLSearchParams }

参考: https://github.com/stevenvachon/universal-url

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1