nuxt: global.URL is missing

Version

v2.4.0

Reproduction link

https://codesandbox.io/s/ww5n6p5mll

Steps to reproduce

Accessing URL object like new URL('http://example.com'); anywhere in server side code.

What is expected ?

URL object is accessible globally in server side since it is defined as global interface in node.js. https://nodejs.org/docs/latest-v10.x/api/globals.html#globals_url

What is actually happening?

Accessing URL object in server side code causes “ReferenceError URL is not defined”.

Additional comments?

It had been accessible before and including v2.3.4.

<div align="right">This bug report is available on Nuxt community (#c8582)</div>

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 9
  • Comments: 20 (4 by maintainers)

Most upvoted comments

This is because we’re using runInNewContext: true by default in dev mode for avoiding memory leak, but vue does’t inject URL in sandbox global https://github.com/vuejs/vue/blob/master/src/server/bundle-renderer/create-bundle-runner.js#L9.

You can use runInNewContext: false, but it may cause unexpected memory leak in dev mode.

So I created a pr in Vue for adding URL https://github.com/vuejs/vue/pull/10414.

Another tricky way is using require(‘url’) which will require module outside new context:

  created () {
    if (process.server) {
      const URL = require('url').URL;
      console.log(new URL("http://foo"));
    }
  }

And, npm run dev reproduces, while npm run build && npm start does not.

Here’s a temporary workaround that pulls from the appropriate place depending on the context.

// ./url.js
import * as url from 'url'

// Create the URL contructor for node or use the existing one for the browser
const urlConstructor = (process.server) ? url.URL : URL

// Create the URLSearchParams contructor for node or use the existing one for the browser
const paramsConstructor = (process.server) ? url.URLSearchParams : URLSearchParams

export { urlConstructor as URL }

export { paramsConstructor as URLSearchParams }

And you just pull it in like this import { URL, URLSearchParams } from './url'

Hi @pi0 this should be fixed in the next release according to your recent merge?

Another (slightly altered) temporary workaround:

if (process.server) {
  const { URLSearchParams } = require('url')
  global.URLSearchParams = URLSearchParams
}

In my case, I’m importing a module that uses URL from the vue file. There are two or three ways to reproduce my case.

  • I’m using typescript with Nuxt
  • I’ve tried Url from “url” node module and URL dom object
  • I’ve tried with and without "lib": ["dom"]
  • I’ve tried with and without npm i @types/node
import { Url } from "url"

and/or

import * as url from "url"
const URL = url.Url

VSCode throws error that Url is a type/interface but it’s used as a value in first case. In both cases, they ‘work’ despite VSCode throwing error, but doesn’t work properly. For example:

console.log(new Url("http://localhost:3001"))

prints a Url instance where all properties are null.

Third or second case:

console.log(URL)

just throws reference error that URL is not defined.

As expected, URL works just fine in the vue files.


Node version: 10.2.1 Nuxt version: 2.4.0

I looked into this a bit and it seems that eg URL is (and has been) a non-enumerable property on the global object. Eg global.Buffer can still be used but that is enumerable (for now, it will become non-enumerable in v12 probably).

Not sure where to look further for this, but probably its a babel / core-js issue? As a side note, core-js v3 has a URL polyfill.