vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.22k stars 27.02k forks source link

URL.parse() not polyfilled #72914

Open supernes opened 5 days ago

supernes commented 5 days ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/determined-knuth-87352t?file=%2Fapp%2Fpage.tsx%3A3%2C16

To Reproduce

  1. Run or build the application
  2. Get error

Current vs. Expected behavior

Expected result is no error Actual result is a runtime/buildtime error

npm run dev

GET / 500 in 4185ms
⨯ app/page.tsx (3:28) @ parse
⨯ TypeError: URL.parse is not a function
at Home (./app/page.tsx:9:30)
at AsyncLocalStorage.run (node:async_hooks:346:14)
at stringify (<anonymous>)
at AsyncLocalStorage.run (node:async_hooks:346:14)
at AsyncResource.runInAsyncScope (node:async_hooks:206:9)
digest: "779954570"
1 | /** Add your relevant code here for the issue to reproduce */
2 | export default function Home() {
3 |   const { hostname } = URL.parse("https://vercel.com");
|                            ^
4 |
5 |   return <h1>{ hostname }</h1>;
6 | }

npm run build


Failed to compile.

./app/page.tsx:3:28 Type error: Property 'parse' does not exist on type '{ new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string): boolean; createObjectURL(obj: Blob | MediaSource): string; revokeObjectURL(url: string): void; }'.

1 | /* Add your relevant code here for the issue to reproduce / 2 | export default function Home() {

3 | const { hostname } = URL.parse("https://vercel.com"); | ^ 4 | 5 | return

{ hostname }

; 6 | }

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.9.0
  npm: 9.8.1
  Yarn: 1.22.19
  pnpm: 8.10.2
Relevant Packages:
  next: 15.0.4-canary.17 // Latest available version is detected (15.0.4-canary.17).
  eslint-config-next: N/A
  react: 19.0.0-rc-380f5d67-20241113
  react-dom: 19.0.0-rc-380f5d67-20241113
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Runtime

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local), Vercel (Deployed)

Additional context

URL.parse() is a static method on the URL class supported on all major platforms, but the Next.js polyfill clobbers it on both server and client - only the canParse() method is included, even though core-js has a polyfill for parse() as well.

https://github.com/vercel/next.js/blob/c50109b4468bb274c29dfc0eb5aaa906736dc4d9/packages/next-polyfill-nomodule/src/index.js#L52

Additionally, Safari does not support this method until v18 (released two months ago). Found this out when I started to get runtime errors on my phone on a Vercel production deployment.

Node v20 LTS - https://nodejs.org/docs/latest-v20.x/api/url.html#urlparseinput-base MDN - https://developer.mozilla.org/en-US/docs/Web/API/URL/parse_static Can I Use? - https://caniuse.com/mdn-api_url_parse_static

It's been added in Node v22 and backported to LTS. Here's an example from my dev environment that shows it working:

nes@vm:~$ node --version
v20.18.0
nes@vm:~$ node
Welcome to Node.js v20.18.0.
Type ".help" for more information.
> URL.parse("https://vercel.com")
URL {
  href: 'https://vercel.com/',
  origin: 'https://vercel.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'vercel.com',
  hostname: 'vercel.com',
  port: '',
  pathname: '/',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}
samcx commented 3 days ago

@supernes Taking a look if this is something feasible to add!

supernes commented 2 days ago

Thanks for looking into this. I would classify this is a mostly Developer Experience issue, but it can lead to a deceptive mismatch between development and production behavior.

The reference documentation shows the API as widely available, and it works in local development on an up-to-date software stack, but will actually fail with a "client error" when deployed for around 30% of global users. Even on Node v20 LTS it can fail unpredictably, as in this case - it builds on Vercel, but not on CodeSandbox (who are several minor versions behind).

Eventually I just rewrote the code around the call, but it seems like an easy improvement to polyfill it.