Skip to content

Commit 0b88e09

Browse files
deps: update undici to 7.11.0
PR-URL: #58859 Co-authored-by: Joyee Cheung <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]>
1 parent 4c65776 commit 0b88e09

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1417
-894
lines changed

deps/undici/src/README.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,125 @@ The benchmark is a simple getting data [example](https://github.com/nodejs/undic
4343
└────────────────────────┴─────────┴────────────────────┴────────────┴─────────────────────────┘
4444
```
4545

46+
## Undici vs. Fetch
47+
48+
### Overview
49+
50+
Node.js includes a built-in `fetch()` implementation powered by undici starting from Node.js v18. However, there are important differences between using the built-in fetch and installing undici as a separate module.
51+
52+
### Built-in Fetch (Node.js v18+)
53+
54+
Node.js's built-in fetch is powered by a bundled version of undici:
55+
56+
```js
57+
// Available globally in Node.js v18+
58+
const response = await fetch('https://api.example.com/data');
59+
const data = await response.json();
60+
61+
// Check the bundled undici version
62+
console.log(process.versions.undici); // e.g., "5.28.4"
63+
```
64+
65+
**Pros:**
66+
- No additional dependencies required
67+
- Works across different JavaScript runtimes
68+
- Automatic compression handling (gzip, deflate, br)
69+
- Built-in caching support (in development)
70+
71+
**Cons:**
72+
- Limited to the undici version bundled with your Node.js version
73+
- Less control over connection pooling and advanced features
74+
- Error handling follows Web API standards (errors wrapped in `TypeError`)
75+
- Performance overhead due to Web Streams implementation
76+
77+
### Undici Module
78+
79+
Installing undici as a separate module gives you access to the latest features and APIs:
80+
81+
```bash
82+
npm install undici
83+
```
84+
85+
```js
86+
import { request, fetch, Agent, setGlobalDispatcher } from 'undici';
87+
88+
// Use undici.request for maximum performance
89+
const { statusCode, headers, body } = await request('https://api.example.com/data');
90+
const data = await body.json();
91+
92+
// Or use undici.fetch with custom configuration
93+
const agent = new Agent({ keepAliveTimeout: 10000 });
94+
setGlobalDispatcher(agent);
95+
const response = await fetch('https://api.example.com/data');
96+
```
97+
98+
**Pros:**
99+
- Latest undici features and bug fixes
100+
- Access to advanced APIs (`request`, `stream`, `pipeline`)
101+
- Fine-grained control over connection pooling
102+
- Better error handling with clearer error messages
103+
- Superior performance, especially with `undici.request`
104+
- HTTP/1.1 pipelining support
105+
- Custom interceptors and middleware
106+
- Advanced features like `ProxyAgent`, `MockAgent`
107+
108+
**Cons:**
109+
- Additional dependency to manage
110+
- Larger bundle size
111+
112+
### When to Use Each
113+
114+
#### Use Built-in Fetch When:
115+
- You want zero dependencies
116+
- Building isomorphic code that runs in browsers and Node.js
117+
- Simple HTTP requests without advanced configuration
118+
- You're okay with the undici version bundled in your Node.js version
119+
120+
#### Use Undici Module When:
121+
- You need the latest undici features and performance improvements
122+
- You require advanced connection pooling configuration
123+
- You need APIs not available in the built-in fetch (`ProxyAgent`, `MockAgent`, etc.)
124+
- Performance is critical (use `undici.request` for maximum speed)
125+
- You want better error handling and debugging capabilities
126+
- You need HTTP/1.1 pipelining or advanced interceptors
127+
- You prefer decoupled protocol and API interfaces
128+
129+
### Performance Comparison
130+
131+
Based on benchmarks, here's the typical performance hierarchy:
132+
133+
1. **`undici.request()`** - Fastest, most efficient
134+
2. **`undici.fetch()`** - Good performance, standard compliance
135+
3. **Node.js `http`/`https`** - Baseline performance
136+
137+
### Migration Guide
138+
139+
If you're currently using built-in fetch and want to migrate to undici:
140+
141+
```js
142+
// Before: Built-in fetch
143+
const response = await fetch('https://api.example.com/data');
144+
145+
// After: Undici fetch (drop-in replacement)
146+
import { fetch } from 'undici';
147+
const response = await fetch('https://api.example.com/data');
148+
149+
// Or: Undici request (better performance)
150+
import { request } from 'undici';
151+
const { statusCode, body } = await request('https://api.example.com/data');
152+
const data = await body.json();
153+
```
154+
155+
### Version Compatibility
156+
157+
You can check which version of undici is bundled with your Node.js version:
158+
159+
```js
160+
console.log(process.versions.undici);
161+
```
162+
163+
Installing undici as a module allows you to use a newer version than what's bundled with Node.js, giving you access to the latest features and performance improvements.
164+
46165
## Quick Start
47166

48167
```js
@@ -63,6 +182,44 @@ for await (const data of body) { console.log('data', data) }
63182
console.log('trailers', trailers)
64183
```
65184

185+
## Global Installation
186+
187+
Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally:
188+
189+
```js
190+
import { install } from 'undici'
191+
192+
// Install all WHATWG fetch classes globally
193+
install()
194+
195+
// Now you can use fetch classes globally without importing
196+
const response = await fetch('https://api.example.com/data')
197+
const data = await response.json()
198+
199+
// All classes are available globally:
200+
const headers = new Headers([['content-type', 'application/json']])
201+
const request = new Request('https://example.com')
202+
const formData = new FormData()
203+
const ws = new WebSocket('wss://example.com')
204+
const eventSource = new EventSource('https://example.com/events')
205+
```
206+
207+
The `install()` function adds the following classes to `globalThis`:
208+
209+
- `fetch` - The fetch function
210+
- `Headers` - HTTP headers management
211+
- `Response` - HTTP response representation
212+
- `Request` - HTTP request representation
213+
- `FormData` - Form data handling
214+
- `WebSocket` - WebSocket client
215+
- `CloseEvent`, `ErrorEvent`, `MessageEvent` - WebSocket events
216+
- `EventSource` - Server-sent events client
217+
218+
This is useful for:
219+
- Polyfilling environments that don't have fetch
220+
- Ensuring consistent fetch behavior across different Node.js versions
221+
- Making undici's implementations available globally for libraries that expect them
222+
66223
## Body Mixins
67224

68225
The `body` mixins are the most common way to format the request/response body. Mixins include:

deps/undici/src/docs/docs/api/CacheStore.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ The `MemoryCacheStore` stores the responses in-memory.
1313

1414
**Options**
1515

16-
- `maxSize` - The maximum total size in bytes of all stored responses. Default `Infinity`.
17-
- `maxCount` - The maximum amount of responses to store. Default `Infinity`.
18-
- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `Infinity`.
16+
- `maxSize` - The maximum total size in bytes of all stored responses. Default `104857600` (100MB).
17+
- `maxCount` - The maximum amount of responses to store. Default `1024`.
18+
- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `5242880` (5MB).
1919

2020
### Getters
2121

deps/undici/src/docs/docs/api/Debug.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ NODE_DEBUG=undici node script.js
1414
UNDICI 16241: connecting to nodejs.org using https:h1
1515
UNDICI 16241: connecting to nodejs.org using https:h1
1616
UNDICI 16241: connected to nodejs.org using https:h1
17-
UNDICI 16241: sending request to GET https://nodejs.org//
18-
UNDICI 16241: received response to GET https://nodejs.org// - HTTP 307
17+
UNDICI 16241: sending request to GET https://nodejs.org/
18+
UNDICI 16241: received response to GET https://nodejs.org/ - HTTP 307
1919
UNDICI 16241: connecting to nodejs.org using https:h1
20-
UNDICI 16241: trailers received from GET https://nodejs.org//
20+
UNDICI 16241: trailers received from GET https://nodejs.org/
2121
UNDICI 16241: connected to nodejs.org using https:h1
22-
UNDICI 16241: sending request to GET https://nodejs.org//en
23-
UNDICI 16241: received response to GET https://nodejs.org//en - HTTP 200
24-
UNDICI 16241: trailers received from GET https://nodejs.org//en
22+
UNDICI 16241: sending request to GET https://nodejs.org/en
23+
UNDICI 16241: received response to GET https://nodejs.org/en - HTTP 200
24+
UNDICI 16241: trailers received from GET https://nodejs.org/en
2525
```
2626

2727
## `fetch`
@@ -36,14 +36,14 @@ NODE_DEBUG=fetch node script.js
3636
FETCH 16241: connecting to nodejs.org using https:h1
3737
FETCH 16241: connecting to nodejs.org using https:h1
3838
FETCH 16241: connected to nodejs.org using https:h1
39-
FETCH 16241: sending request to GET https://nodejs.org//
40-
FETCH 16241: received response to GET https://nodejs.org// - HTTP 307
39+
FETCH 16241: sending request to GET https://nodejs.org/
40+
FETCH 16241: received response to GET https://nodejs.org/ - HTTP 307
4141
FETCH 16241: connecting to nodejs.org using https:h1
42-
FETCH 16241: trailers received from GET https://nodejs.org//
42+
FETCH 16241: trailers received from GET https://nodejs.org/
4343
FETCH 16241: connected to nodejs.org using https:h1
44-
FETCH 16241: sending request to GET https://nodejs.org//en
45-
FETCH 16241: received response to GET https://nodejs.org//en - HTTP 200
46-
FETCH 16241: trailers received from GET https://nodejs.org//en
44+
FETCH 16241: sending request to GET https://nodejs.org/en
45+
FETCH 16241: received response to GET https://nodejs.org/en - HTTP 200
46+
FETCH 16241: trailers received from GET https://nodejs.org/en
4747
```
4848

4949
## `websocket`
@@ -57,6 +57,6 @@ NODE_DEBUG=websocket node script.js
5757

5858
WEBSOCKET 18309: connecting to echo.websocket.org using https:h1
5959
WEBSOCKET 18309: connected to echo.websocket.org using https:h1
60-
WEBSOCKET 18309: sending request to GET https://echo.websocket.org//
60+
WEBSOCKET 18309: sending request to GET https://echo.websocket.org/
6161
WEBSOCKET 18309: connection opened <ip_address>
6262
```

deps/undici/src/docs/docs/api/DiagnosticsChannel.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,22 @@ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
2727

2828
Note: a request is only loosely completed to a given socket.
2929

30+
## `undici:request:bodyChunkSent`
31+
32+
This message is published when a chunk of the request body is being sent.
33+
34+
```js
35+
import diagnosticsChannel from 'diagnostics_channel'
36+
37+
diagnosticsChannel.channel('undici:request:bodyChunkSent').subscribe(({ request, chunk }) => {
38+
// request is the same object undici:request:create
39+
})
40+
```
3041

3142
## `undici:request:bodySent`
3243

44+
This message is published after the request body has been fully sent.
45+
3346
```js
3447
import diagnosticsChannel from 'diagnostics_channel'
3548

@@ -54,6 +67,18 @@ diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, respo
5467
})
5568
```
5669

70+
## `undici:request:bodyChunkReceived`
71+
72+
This message is published after a chunk of the response body has been received.
73+
74+
```js
75+
import diagnosticsChannel from 'diagnostics_channel'
76+
77+
diagnosticsChannel.channel('undici:request:bodyChunkReceived').subscribe(({ request, chunk }) => {
78+
// request is the same object undici:request:create
79+
})
80+
```
81+
5782
## `undici:request:trailers`
5883

5984
This message is published after the response body and trailers have been received, i.e. the response has been completed.

deps/undici/src/docs/docs/api/Dispatcher.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,9 +841,28 @@ try {
841841
Compose a new dispatcher from the current dispatcher and the given interceptors.
842842

843843
> _Notes_:
844-
> - The order of the interceptors matters. The first interceptor will be the first to be called.
844+
> - The order of the interceptors matters. The last interceptor will be the first to be called.
845845
> - It is important to note that the `interceptor` function should return a function that follows the `Dispatcher.dispatch` signature.
846846
> - Any fork of the chain of `interceptors` can lead to unexpected results.
847+
>
848+
> **Interceptor Stack Visualization:**
849+
> ```
850+
> compose([interceptor1, interceptor2, interceptor3])
851+
>
852+
> Request Flow:
853+
> ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
854+
> │ Request │───▶│interceptor3 │───▶│interceptor2 │───▶│interceptor1 │───▶│ dispatcher │
855+
> └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ .dispatch │
856+
> ▲ ▲ ▲ └─────────────┘
857+
> │ │ │ ▲
858+
> (called first) (called second) (called last) │
859+
> │
860+
> ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
861+
> │ Response │◀───│interceptor3 │◀───│interceptor2 │◀───│interceptor1 │◀─────────┘
862+
> └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
863+
>
864+
> The interceptors are composed in reverse order due to function composition.
865+
> ```
847866
848867
Arguments:
849868
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Global Installation
2+
3+
Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally without requiring imports.
4+
5+
## `install()`
6+
7+
Install all WHATWG fetch classes globally on `globalThis`.
8+
9+
**Example:**
10+
11+
```js
12+
import { install } from 'undici'
13+
14+
// Install all WHATWG fetch classes globally
15+
install()
16+
17+
// Now you can use fetch classes globally without importing
18+
const response = await fetch('https://api.example.com/data')
19+
const data = await response.json()
20+
21+
// All classes are available globally:
22+
const headers = new Headers([['content-type', 'application/json']])
23+
const request = new Request('https://example.com')
24+
const formData = new FormData()
25+
const ws = new WebSocket('wss://example.com')
26+
const eventSource = new EventSource('https://example.com/events')
27+
```
28+
29+
## Installed Classes
30+
31+
The `install()` function adds the following classes to `globalThis`:
32+
33+
| Class | Description |
34+
|-------|-------------|
35+
| `fetch` | The fetch function for making HTTP requests |
36+
| `Headers` | HTTP headers management |
37+
| `Response` | HTTP response representation |
38+
| `Request` | HTTP request representation |
39+
| `FormData` | Form data handling |
40+
| `WebSocket` | WebSocket client |
41+
| `CloseEvent` | WebSocket close event |
42+
| `ErrorEvent` | WebSocket error event |
43+
| `MessageEvent` | WebSocket message event |
44+
| `EventSource` | Server-sent events client |
45+
46+
## Use Cases
47+
48+
Global installation is useful for:
49+
50+
- **Polyfilling environments** that don't have native fetch support
51+
- **Ensuring consistent behavior** across different Node.js versions
52+
- **Library compatibility** when third-party libraries expect global fetch
53+
- **Migration scenarios** where you want to replace built-in implementations
54+
- **Testing environments** where you need predictable fetch behavior
55+
56+
## Example: Polyfilling an Environment
57+
58+
```js
59+
import { install } from 'undici'
60+
61+
// Check if fetch is available and install if needed
62+
if (typeof globalThis.fetch === 'undefined') {
63+
install()
64+
console.log('Undici fetch installed globally')
65+
}
66+
67+
// Now fetch is guaranteed to be available
68+
const response = await fetch('https://api.example.com')
69+
```
70+
71+
## Example: Testing Environment
72+
73+
```js
74+
import { install } from 'undici'
75+
76+
// In test setup, ensure consistent fetch behavior
77+
install()
78+
79+
// Now all tests use undici's implementations
80+
test('fetch API test', async () => {
81+
const response = await fetch('https://example.com')
82+
expect(response).toBeInstanceOf(Response)
83+
})
84+
```
85+
86+
## Notes
87+
88+
- The `install()` function overwrites any existing global implementations
89+
- Classes installed are undici's implementations, not Node.js built-ins
90+
- This provides access to undici's latest features and performance improvements
91+
- The global installation persists for the lifetime of the process

0 commit comments

Comments
 (0)