Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,44 @@ for await (const data of body) { console.log('data', data) }
console.log('trailers', trailers)
```

## Global Installation

Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally:

```js
import { install } from 'undici'

// Install all WHATWG fetch classes globally
install()

// Now you can use fetch classes globally without importing
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// All classes are available globally:
const headers = new Headers([['content-type', 'application/json']])
const request = new Request('https://example.com')
const formData = new FormData()
const ws = new WebSocket('wss://example.com')
const eventSource = new EventSource('https://example.com/events')
```

The `install()` function adds the following classes to `globalThis`:

- `fetch` - The fetch function
- `Headers` - HTTP headers management
- `Response` - HTTP response representation
- `Request` - HTTP request representation
- `FormData` - Form data handling
- `WebSocket` - WebSocket client
- `CloseEvent`, `ErrorEvent`, `MessageEvent` - WebSocket events
- `EventSource` - Server-sent events client

This is useful for:
- Polyfilling environments that don't have fetch
- Ensuring consistent fetch behavior across different Node.js versions
- Making undici's implementations available globally for libraries that expect them

## Body Mixins

The `body` mixins are the most common way to format the request/response body. Mixins include:
Expand Down
91 changes: 91 additions & 0 deletions docs/docs/api/GlobalInstallation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Global Installation

Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally without requiring imports.

## `install()`

Install all WHATWG fetch classes globally on `globalThis`.

**Example:**

```js
import { install } from 'undici'

// Install all WHATWG fetch classes globally
install()

// Now you can use fetch classes globally without importing
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// All classes are available globally:
const headers = new Headers([['content-type', 'application/json']])
const request = new Request('https://example.com')
const formData = new FormData()
const ws = new WebSocket('wss://example.com')
const eventSource = new EventSource('https://example.com/events')
```

## Installed Classes

The `install()` function adds the following classes to `globalThis`:

| Class | Description |
|-------|-------------|
| `fetch` | The fetch function for making HTTP requests |
| `Headers` | HTTP headers management |
| `Response` | HTTP response representation |
| `Request` | HTTP request representation |
| `FormData` | Form data handling |
| `WebSocket` | WebSocket client |
| `CloseEvent` | WebSocket close event |
| `ErrorEvent` | WebSocket error event |
| `MessageEvent` | WebSocket message event |
| `EventSource` | Server-sent events client |

## Use Cases

Global installation is useful for:

- **Polyfilling environments** that don't have native fetch support
- **Ensuring consistent behavior** across different Node.js versions
- **Library compatibility** when third-party libraries expect global fetch
- **Migration scenarios** where you want to replace built-in implementations
- **Testing environments** where you need predictable fetch behavior

## Example: Polyfilling an Environment

```js
import { install } from 'undici'

// Check if fetch is available and install if needed
if (typeof globalThis.fetch === 'undefined') {
install()
console.log('Undici fetch installed globally')
}

// Now fetch is guaranteed to be available
const response = await fetch('https://api.example.com')
```

## Example: Testing Environment

```js
import { install } from 'undici'

// In test setup, ensure consistent fetch behavior
install()

// Now all tests use undici's implementations
test('fetch API test', async () => {
const response = await fetch('https://example.com')
expect(response).toBeInstanceOf(Response)
})
```

## Notes

- The `install()` function overwrites any existing global implementations
- Classes installed are undici's implementations, not Node.js built-ins
- This provides access to undici's latest features and performance improvements
- The global installation persists for the lifetime of the process
1 change: 1 addition & 0 deletions docs/docsify/sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* [Errors](/docs/api/Errors.md "Undici API - Errors")
* [EventSource](/docs/api/EventSource.md "Undici API - EventSource")
* [Fetch](/docs/api/Fetch.md "Undici API - Fetch")
* [Global Installation](/docs/api/GlobalInstallation.md "Undici API - Global Installation")
* [Cookies](/docs/api/Cookies.md "Undici API - Cookies")
* [MockClient](/docs/api/MockClient.md "Undici API - MockClient")
* [MockPool](/docs/api/MockPool.md "Undici API - MockPool")
Expand Down
15 changes: 15 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,18 @@ module.exports.mockErrors = mockErrors
const { EventSource } = require('./lib/web/eventsource/eventsource')

module.exports.EventSource = EventSource

function install () {
globalThis.fetch = module.exports.fetch
globalThis.Headers = module.exports.Headers
globalThis.Response = module.exports.Response
globalThis.Request = module.exports.Request
globalThis.FormData = module.exports.FormData
globalThis.WebSocket = module.exports.WebSocket
globalThis.CloseEvent = module.exports.CloseEvent
globalThis.ErrorEvent = module.exports.ErrorEvent
globalThis.MessageEvent = module.exports.MessageEvent
globalThis.EventSource = module.exports.EventSource
}

module.exports.install = install
126 changes: 126 additions & 0 deletions test/install.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
'use strict'

const { test } = require('node:test')
const assert = require('node:assert')
const { install } = require('../index')

test('install() should add WHATWG fetch classes to globalThis', () => {
// Save original globals to restore later
const originalFetch = globalThis.fetch
const originalHeaders = globalThis.Headers
const originalResponse = globalThis.Response
const originalRequest = globalThis.Request
const originalFormData = globalThis.FormData
const originalWebSocket = globalThis.WebSocket
const originalCloseEvent = globalThis.CloseEvent
const originalErrorEvent = globalThis.ErrorEvent
const originalMessageEvent = globalThis.MessageEvent
const originalEventSource = globalThis.EventSource

try {
// Remove any existing globals
delete globalThis.fetch
delete globalThis.Headers
delete globalThis.Response
delete globalThis.Request
delete globalThis.FormData
delete globalThis.WebSocket
delete globalThis.CloseEvent
delete globalThis.ErrorEvent
delete globalThis.MessageEvent
delete globalThis.EventSource

// Verify they're not defined
assert.strictEqual(globalThis.fetch, undefined)
assert.strictEqual(globalThis.Headers, undefined)
assert.strictEqual(globalThis.Response, undefined)
assert.strictEqual(globalThis.Request, undefined)
assert.strictEqual(globalThis.FormData, undefined)
assert.strictEqual(globalThis.WebSocket, undefined)
assert.strictEqual(globalThis.CloseEvent, undefined)
assert.strictEqual(globalThis.ErrorEvent, undefined)
assert.strictEqual(globalThis.MessageEvent, undefined)
assert.strictEqual(globalThis.EventSource, undefined)

// Call install()
install()

// Verify all classes are now installed
assert.strictEqual(typeof globalThis.fetch, 'function')
assert.strictEqual(typeof globalThis.Headers, 'function')
assert.strictEqual(typeof globalThis.Response, 'function')
assert.strictEqual(typeof globalThis.Request, 'function')
assert.strictEqual(typeof globalThis.FormData, 'function')
assert.strictEqual(typeof globalThis.WebSocket, 'function')
assert.strictEqual(typeof globalThis.CloseEvent, 'function')
assert.strictEqual(typeof globalThis.ErrorEvent, 'function')
assert.strictEqual(typeof globalThis.MessageEvent, 'function')
assert.strictEqual(typeof globalThis.EventSource, 'function')

// Test that the installed classes are functional
const headers = new globalThis.Headers([['content-type', 'application/json']])
assert.strictEqual(headers.get('content-type'), 'application/json')

const request = new globalThis.Request('https://example.com')
assert.strictEqual(request.url, 'https://example.com/')

const response = new globalThis.Response('test body')
assert.strictEqual(response.status, 200)

const formData = new globalThis.FormData()
formData.append('key', 'value')
assert.strictEqual(formData.get('key'), 'value')
} finally {
// Restore original globals
if (originalFetch !== undefined) {
globalThis.fetch = originalFetch
} else {
delete globalThis.fetch
}
if (originalHeaders !== undefined) {
globalThis.Headers = originalHeaders
} else {
delete globalThis.Headers
}
if (originalResponse !== undefined) {
globalThis.Response = originalResponse
} else {
delete globalThis.Response
}
if (originalRequest !== undefined) {
globalThis.Request = originalRequest
} else {
delete globalThis.Request
}
if (originalFormData !== undefined) {
globalThis.FormData = originalFormData
} else {
delete globalThis.FormData
}
if (originalWebSocket !== undefined) {
globalThis.WebSocket = originalWebSocket
} else {
delete globalThis.WebSocket
}
if (originalCloseEvent !== undefined) {
globalThis.CloseEvent = originalCloseEvent
} else {
delete globalThis.CloseEvent
}
if (originalErrorEvent !== undefined) {
globalThis.ErrorEvent = originalErrorEvent
} else {
delete globalThis.ErrorEvent
}
if (originalMessageEvent !== undefined) {
globalThis.MessageEvent = originalMessageEvent
} else {
delete globalThis.MessageEvent
}
if (originalEventSource !== undefined) {
globalThis.EventSource = originalEventSource
} else {
delete globalThis.EventSource
}
}
})
Loading