EventSource Polyfill provides a comprehensive browser polyfill for the W3C EventSource API (Server-Sent Events). It enables SSE functionality in browsers that don't natively support it, including Internet Explorer 8+ and Android browser 2.1+, with automatic reconnection, event parsing, custom event types, and cross-browser compatibility.
npm install eventsource-polyfillFor browserify/webpack/CommonJS environments (automatic polyfill):
require('eventsource-polyfill');
// This automatically adds the polyfill to window.EventSource if not present
// After requiring, use: new EventSource(url)Direct module import (manual usage):
const EventSourcePolyfill = require('eventsource-polyfill');
const eventSource = new EventSourcePolyfill(url);For browser script inclusion:
<script src="dist/eventsource.js"></script>
<!-- This makes EventSource available globally if not already present -->// Import the polyfill (for browserify/webpack environments)
require('eventsource-polyfill');
// Create an EventSource connection
const eventSource = new EventSource('https://example.com/events');
// Handle connection events
eventSource.onopen = function(event) {
console.log('Connection opened:', event);
};
eventSource.onmessage = function(event) {
console.log('Received message:', event.data);
};
eventSource.onerror = function(event) {
console.log('Error occurred:', event);
};
// Listen for custom event types
eventSource.addEventListener('custom-event', function(event) {
console.log('Custom event received:', event.data);
});
// Close the connection when done
eventSource.close();The polyfill is built around several key components:
Creates a new EventSource connection for Server-Sent Events with optional configuration.
/**
* EventSource constructor for Server-Sent Events polyfill
* @param {string} url - The URL to connect to for Server-Sent Events
* @param {object} options - Optional configuration options
*/
function EventSource(url, options);Usage Examples:
// Basic connection
const eventSource = new EventSource('/api/events');
// With configuration options
const eventSource = new EventSource('/api/events', {
loggingEnabled: true,
interval: 1000,
silentTimeout: 60000,
xhrHeaders: {
'Authorization': 'Bearer token123'
}
});Methods for managing event listeners on the EventSource instance.
/**
* Add an event listener for the specified event type
* @param {string} type - Event type ('open', 'message', 'error', or custom type)
* @param {function} handler - Event handler function
*/
addEventListener(type, handler);
/**
* Remove an event listener for the specified event type
* @param {string} type - Event type
* @param {function} handler - Event handler function to remove
*/
removeEventListener(type, handler);Usage Examples:
// Add listeners
eventSource.addEventListener('message', function(event) {
console.log('Message:', event.data);
});
eventSource.addEventListener('custom-notification', function(event) {
console.log('Notification:', event.data);
});
// Remove listeners
function messageHandler(event) {
console.log('Message:', event.data);
}
eventSource.addEventListener('message', messageHandler);
eventSource.removeEventListener('message', messageHandler);Methods for controlling the EventSource connection lifecycle.
/**
* Close the EventSource connection
*/
close();Usage Example:
// Close the connection
eventSource.close();
console.log('Connection state:', eventSource.readyState); // 2 (CLOSED)Properties providing information about the current connection state.
/**
* Current connection state
* @type {number} - 0 (CONNECTING), 1 (OPEN), or 2 (CLOSED)
*/
readyState;
/**
* The URL being connected to
* @type {string}
*/
URL;
/**
* ID of the last received event
* @type {string|null}
*/
lastEventId;Constants defining the possible connection states.
/**
* Connection state constants
*/
EventSource.prototype.CONNECTING = 0;
EventSource.prototype.OPEN = 1;
EventSource.prototype.CLOSED = 2;Properties for setting event handlers directly.
/**
* Handler for connection open events
* @type {function|null}
*/
onopen;
/**
* Handler for message events
* @type {function|null}
*/
onmessage;
/**
* Handler for error events
* @type {function|null}
*/
onerror;Usage Example:
eventSource.onopen = function(event) {
console.log('Connection opened');
};
eventSource.onmessage = function(event) {
console.log('Received:', event.data);
};
eventSource.onerror = function(event) {
console.error('Connection error:', event);
};Configuration options available when creating an EventSource instance.
/**
* Default configuration options
*/
const defaultOptions = {
/** Enable/disable console logging */
loggingEnabled: false,
/** Prefix for log messages */
loggingPrefix: "eventsource",
/** Reconnection interval in milliseconds */
interval: 500,
/** Maximum buffer size in bytes */
bufferSizeLimit: 256 * 1024,
/** Timeout for silent connections in milliseconds */
silentTimeout: 300000,
/** GET parameters to append to URL */
getArgs: {
'evs_buffer_size_limit': 256 * 1024
},
/** HTTP headers for XMLHttpRequest */
xhrHeaders: {
'Accept': 'text/event-stream',
'Cache-Control': 'no-cache',
'X-Requested-With': 'XMLHttpRequest'
}
};Usage Example:
const eventSource = new EventSource('/events', {
loggingEnabled: true,
loggingPrefix: 'MyApp',
interval: 2000,
silentTimeout: 120000,
xhrHeaders: {
'Accept': 'text/event-stream',
'Authorization': 'Bearer ' + token
},
getArgs: {
'user_id': '12345',
'evs_buffer_size_limit': 512 * 1024
}
});Static property indicating the polyfill implementation type.
/**
* Indicates the polyfill implementation type (only present when using polyfill)
* @type {string} - "XHR" for modern browsers, "IE_8-9" for older IE versions
*/
EventSource.isPolyfill;Usage Example:
// Note: This property only exists when using the polyfill, not native EventSource
if (typeof EventSource.isPolyfill !== 'undefined') {
console.log('Using polyfill with transport:', EventSource.isPolyfill);
} else {
console.log('Using native EventSource implementation');
}/**
* MessageEvent object for Server-Sent Events
*/
interface MessageEvent {
/** Event type */
type: string;
/** Event data payload */
data: string | null;
/** Event origin */
origin: string;
/** Event ID for reconnection */
lastEventId: string;
/** Event bubbling (always false) */
bubbles: boolean;
/** Event cancelable (always false) */
cancelable: boolean;
/** Event cancel bubble (always false) */
cancelBubble: boolean;
}
/**
* EventSource configuration options
*/
interface EventSourceOptions {
/** Enable console logging */
loggingEnabled?: boolean;
/** Log message prefix */
loggingPrefix?: string;
/** Reconnection interval in ms */
interval?: number;
/** Buffer size limit in bytes */
bufferSizeLimit?: number;
/** Silent connection timeout in ms */
silentTimeout?: number;
/** URL query parameters */
getArgs?: { [key: string]: any };
/** HTTP request headers */
xhrHeaders?: { [key: string]: string };
}The polyfill automatically detects the browser environment and uses the appropriate transport:
XMLHttpRequest with full header support and progress eventsXDomainRequest with modified configuration for cross-domain supportWhen running in IE 8-9, the polyfill automatically:
xhrHeaders: null)evs_preamble: 2056 to GET arguments for XDomainRequest bufferingevs_last_event_id GET parameter instead of Last-Event-Id header for reconnectionThe polyfill handles various error conditions and connection issues:
eventSource.onerror = function(event) {
// Different error types based on event.data
switch(event.data) {
case 'Reconnecting ':
console.log('Connection lost, attempting to reconnect...');
break;
case 'XDomainRequest error':
console.log('IE XDomainRequest failed (IE 8-9 only)');
break;
case 'XDomainRequest timed out':
console.log('IE XDomainRequest timed out (IE 8-9 only)');
break;
default:
// Server HTTP error responses
if (event.data && event.data.startsWith('The server responded with ')) {
console.log('HTTP error:', event.data);
} else {
console.log('Unknown error:', event.data);
}
}
};// Server sends: event: notification\ndata: New message\n\n
eventSource.addEventListener('notification', function(event) {
console.log('Notification received:', event.data);
});eventSource.addEventListener('error', function(event) {
if (event.data === 'Reconnecting ') {
console.log('Lost connection, will retry...');
// The polyfill handles reconnection automatically
}
});// Access the last event ID for manual reconnection
console.log('Last event ID:', eventSource.lastEventId);
// Server can send: id: 12345\ndata: Some data\n\n
// On reconnection, the polyfill sends Last-Event-Id: 12345 header