Nodeに標準で備わっているWHATWG URLを使おうとすると、TypeError: url__WEBPACK_IMPORTED_MODULE_0__.URL is not a constructor
とエラーを出て使えないことがあったので、原因を調査して対策しました。
WHATWG URL
WHATWG URLは、Node.js8.0から正式対応したURL解析モジュールであり、IE・Edgeを除くブラウザにも対応しています。
import { URL } from 'url';
const url = new URL('https://test.jp/hoge');
console.log(url);
URL {
href: 'https://test.jp/hoge',
origin: 'https://test.jp',
protocol: 'https:',
username: '',
password: '',
host: 'test.jp',
hostname: 'test.jp',
port: '',
pathname: '/hoge',
search: '',
searchParams: URLSearchParams {},
hash: ''
}
このようにURLをprotocolだったり、hostだったり、URLを解析した結果をオブジェクト型で返します。
これを利用すると簡単にパラメータの操作ができます。
例えば、パラメータでページャーの制御をしているときには、以下のように使えます。
url.searchParams.set('page', 2);
console.log(url.href);
// => https://test.jp/hoge?page=2
url.searchParams.set('page', 3);
console.log(url.href);
// => https://test.jp/hoge?page=3
エラーになる理由
便利で普段から使っていたのですが、あるとき以下のようなエラーが出て使えませんでした。
URL
が見つからないようです。
Nodeのバージョン古かったかな?と思い確認したのですが、
$ node -v
v12.4.0
Node8.0以上はクリア。もちろん、公式リファレンスも存在しています。
コンソール画面でNodeを実行して確認してみても、URLというメソッドが存在しています。
$ node
> var url = require('url');
> url
{
Url: [Function: Url],
parse: [Function: urlParse],
resolve: [Function: urlResolve],
resolveObject: [Function: urlResolveObject],
format: [Function: urlFormat],
URL: [Function: URL],
URLSearchParams: [Function: URLSearchParams],
domainToASCII: [Function: domainToASCII],
domainToUnicode: [Function: domainToUnicode],
pathToFileURL: [Function: pathToFileURL],
fileURLToPath: [Function: fileURLToPath]
}
>
webpackを通しているのが原因かなと思い、console.log(url);
をしてみると、
URLが存在しません!
あれ?なんで?webpackのバージョンが古い?configミスった?とか考え、いろいろと試行錯誤した結果原因がわかりました。
サーバーサイドでは動くけど、クライアントサイドでは動かない!
そうなんです。同じ実行環境で、サーバーサイドとクライアントサイドでURL
を確認すると、なぜかクライアントサイドでは、URL
というメソッドがなくなっていました。
クライアントサイドでURLを使うためには
ブラウザ上ではURL
が使えないのが分かったのですが、どうしても使いたい!
そんなときは、方法として2パターン考えました。
1. ブラウザに標準実装されているURLを使う
もし、実行するファイルがクライアントサイドだけで使うものであれば、import { URL}
せずに使うとこができます。その1行をコメントアウトして実行してみてください。
ただし、URL
はIE・Edgeには対応していませんので、url-polyfill を読み込ませることで、全ブラウザ上でも実行可能になります。
インストール
$ yarn add url-polyfill
使い方
import 'url-polyfill';
読み込ませる位置は、URL
を使うファイル上でも良いですし、app.js
といったメインファイルに読み込ませておいても問題ありません。
2. Node上でもブラウザ上でも使えるuniversal-urlを使う
importしたurlモジュールをuniversal-urlに置き換えるだけで、サーバーサイド・クライアントサイド両方で使えるコードとなります。
インストール
$ yarn add universal-url
使い方
import { URL } from 'url'
と置き換える
import { URL } from 'universal-url';
私は、UniversalJSの方がラクなので、後者のuniversal-url
を導入して解決しました。