rsnext/packages/next/server/node-polyfill-fetch.js
Ethan Arrowood e0cc9cd44f
feat(experimental): option to polyfill fetch using undici in Node.js <18 (#40318)
This PR adds a new `experimental.enableUndici` option to let the
developer switch from `next-fetch` to `undici` as the underlying
polyfill for `fetch` in Node.js.

In the current implementation, Next.js makes sure that `fetch` is always
available by using `node-fetch`. However, we do not polyfill in Node.js
18+, since those versions come with their own `fetch` implementation
already, built-in.

Node.js 18+ uses `undici` under the hood, so letting the developer use
`undici` earlier could make the migration easier later on.

Eventually, we hope to be able to stop polyfilling `fetch` in an
upcoming major version of Next.js, shipping less code.


## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Sukka <isukkaw@gmail.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Steven <steven@ceriously.com>
2022-09-27 13:37:28 -07:00

56 lines
1.4 KiB
JavaScript

// Polyfill fetch() in the Node.js environment
if (!global.fetch) {
function getFetchImpl() {
return global.__NEXT_USE_UNDICI
? require('next/dist/compiled/undici')
: require('next/dist/compiled/node-fetch')
}
// Due to limitation of global configuration, we have to do this resolution at runtime
global.fetch = (...args) => {
const fetchImpl = getFetchImpl()
if (global.__NEXT_USE_UNDICI) {
// Undici does not support the `keepAlive` option,
// instead we have to pass a custom dispatcher
if (
!global.__NEXT_HTTP_AGENT_OPTIONS?.keepAlive &&
!global.__NEXT_UNDICI_AGENT_SET
) {
global.__NEXT_UNDICI_AGENT_SET = true
fetchImpl.setGlobalDispatcher(new fetchImpl.Agent({ pipelining: 0 }))
}
return fetchImpl.fetch(...args)
}
const agent = ({ protocol }) =>
protocol === 'http:'
? global.__NEXT_HTTP_AGENT
: global.__NEXT_HTTPS_AGENT
if (!args[1]) {
args[1] = { agent }
} else if (!args[1].agent) {
args[1].agent = agent
}
return fetchImpl(...args)
}
Object.defineProperties(global, {
Headers: {
get() {
return getFetchImpl().Headers
},
},
Request: {
get() {
return getFetchImpl().Request
},
},
Response: {
get() {
return getFetchImpl().Response
},
},
})
}