is there any replacement for the nodejs url.resolve function?

nodeJs provides the https://nodejs.org/api/url.html module which allows to:

  • resolve two relative urls:
require('url').resolve(`profile/user/99/details/`, `../../55/details/`) // -> 'profile/user/55/details/'
  • resolve a relative url and an absolute url:
require('url').resolve(`profile/user/99/details/`, `http://example.com`) // -> 'http://example.com/'
  • resolve an absolute url and a relative url:
require('url').resolve(`http://example.com`, `profile/user/99/details/`) // -> 'http://example.com/profile/user/99/details/'
  • resolve two absolute urls:
require('url').resolve(`http://example.com`, `https://stackoverflow.com`) // ->
'https://stackoverflow.com/'

however require('url').resolve was deprecated

what would be the correct (as in non deprecated) way to resolve the urls like in the examples above?


Solution 1:

For urls specific, you can use the new URL() constructor defined by the WHATWG standard.

// syntax
const url = new URL(url [, base]); // (url: string | URL, base?: string | URL) => URL

The href property holds the resolved url.

console.log(new URL(`profile/user/99/details/`, `http://example.com`).href);
console.log(new URL(`https://stackoverflow.com`, `http://example.com`).href);

For paths, you can use the path.posix.join() function provided by Node.js to force joining the paths with forward slashes.

const path = require("path");
path.posix.join(`profile/user/99/details/`, `../../55/details/`));

You could also combine the two.

const path = require("path");
const joined = path.posix.join(`profile/user/99/details/`,"..", "..", `55/details/`);

// 'https://stackoverflow.com/profile/user/55/details/'
const { href } = new URL(joined, "https://stackoverflow.com"); 

Examples.

const path = require("path");

// two relative paths => 'profile/user/55/details/'
path.posix.join("profile/user/99/details/", "../../55/details/");

// absolute and relative path (right) => 'http://example.com/profile/user/99/details/'
new URL("profile/user/99/details/", "http://example.com").href;

// absolute and relative path (wrong) => throws TypeError [ERR_INVALID_URL]
new URL("http://example.com", "profile/user/99/details/").href;

// two absolute paths => 'https://stackoverflow.com'
new URL("https://stackoverflow.com", "http://example.com").href;

// combined => 'http://example.com/profile/user/55/details'
new URL(path.posix.join(
    "profile", "user", "99", "details",
    "..", "..", "55", "details"
), "http://example.com").href;

// or 
new URL(path.posix.join(
    "profile/user/99/details/",
    "../../55/details"
), "http://example.com").href;

Solution 2:

You can use build-in new URL() constructor:

new URL(`https://stackoverflow.com`, `http://example.com`)

returns:

 URL {
  href: 'https://stackoverflow.com/',
  origin: 'https://stackoverflow.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'stackoverflow.com',
  hostname: 'stackoverflow.com',
  port: '',
  pathname: '/',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
 }

The problem with that:

  1. Constructor takes the first arg as primary. So as you wished: resolve(`http://example.com`, `https://stackoverflow.com`)' would not return https://stackoverflow.com.
  2. Returns whole class so you have to "collect" the .href only.

If you can use non-build-in methods, I would suggest https://www.npmjs.com/package/resolve-url .