Better handling for window and document objects in SSR environment
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
SSR Window provides safe handling for window and document objects in server-side rendering (SSR) environments. Unlike full DOM implementations like JSDOM, it provides minimal patches to prevent SSR applications from throwing errors when accessing browser-specific APIs. This lightweight approach ensures compatibility without the overhead of complete DOM simulation.
npm install ssr-windowimport { getWindow, getDocument, ssrWindow, ssrDocument, extend } from "ssr-window";For CommonJS:
const { getWindow, getDocument, ssrWindow, ssrDocument, extend } = require("ssr-window");import { getWindow, getDocument } from "ssr-window";
// Get safe window and document objects
const window = getWindow();
const document = getDocument();
// Use them safely in SSR environment
window.addEventListener('resize', () => {
console.log('Resize event (safe in SSR)');
});
const div = document.createElement('div');
div.setAttribute('class', 'container');
// Query DOM safely (returns null/empty arrays in SSR)
const elements = document.querySelectorAll('.item');SSR Window is built around two core concepts:
ssrWindow and ssrDocument objects with safe default implementationsextend utility for adding application-specific propertiesSafe window object handling that works in both browser and SSR environments.
/**
* Returns a patched Window object that works in both browser and SSR environments
* @returns Window object extended with SSR-safe properties
*/
function getWindow(): Window;
/**
* Pre-configured window-like object with SSR-safe properties and methods
*/
declare const ssrWindow: {
document: typeof ssrDocument;
navigator: {
userAgent: string;
};
location: {
hash: string;
host: string;
hostname: string;
href: string;
origin: string;
pathname: string;
protocol: string;
search: string;
};
history: {
replaceState(): void;
pushState(): void;
go(): void;
back(): void;
};
CustomEvent: () => any;
addEventListener(): void;
removeEventListener(): void;
getComputedStyle(): {
getPropertyValue(): string;
};
Image(): void;
Date(): void;
screen: {};
setTimeout(): void;
clearTimeout(): void;
matchMedia(): {};
requestAnimationFrame(callback: any): NodeJS.Timeout | null;
cancelAnimationFrame(id: any): void;
};Usage Examples:
import { getWindow, ssrWindow } from "ssr-window";
// Get patched window object (browser window + SSR fallbacks)
const window = getWindow();
window.requestAnimationFrame(() => {
// Safe in both browser and SSR
});
// Access pre-configured SSR window directly
console.log(ssrWindow.navigator.userAgent); // Returns empty string in SSRSafe document object handling for DOM operations in SSR environments.
/**
* Returns a patched Document object that works in both browser and SSR environments
* @returns Document object extended with SSR-safe properties
*/
function getDocument(): Document;
/**
* Pre-configured document-like object with SSR-safe properties and methods
*/
declare const ssrDocument: {
body: {};
addEventListener(): void;
removeEventListener(): void;
activeElement: {
blur(): void;
nodeName: string;
};
querySelector(): null;
querySelectorAll(): any[];
getElementById(): null;
createEvent(): {
initEvent(): void;
};
createElement(): {
children: any[];
childNodes: any[];
style: {};
setAttribute(): void;
getElementsByTagName(): any[];
};
createElementNS(): {};
importNode(): null;
location: {
hash: string;
host: string;
hostname: string;
href: string;
origin: string;
pathname: string;
protocol: string;
search: string;
};
};Usage Examples:
import { getDocument, ssrDocument } from "ssr-window";
// Get patched document object (browser document + SSR fallbacks)
const document = getDocument();
const element = document.createElement('div'); // Safe in SSR
element.setAttribute('class', 'container');
// Access pre-configured SSR document directly
const results = ssrDocument.querySelectorAll('.items'); // Returns [] in SSRUtility for safely extending objects with additional properties, used internally and available for custom extensions.
/**
* Safely extends target object with source object properties
* Recursively merges objects while avoiding prototype pollution
* @param target - Target object to extend (defaults to empty object)
* @param src - Source object to copy properties from (defaults to empty object)
*/
function extend(target?: any, src?: any): void;Usage Examples:
import { ssrWindow, ssrDocument, extend } from "ssr-window";
// Extend ssrWindow with custom properties
extend(ssrWindow, {
navigator: {
language: 'en-US',
platform: 'linux',
},
customProperty: 'custom value',
});
// Extend ssrDocument with custom properties
extend(ssrDocument, {
body: {
classList: {
add: () => {},
remove: () => {},
},
},
title: 'SSR Page Title',
});
// Use extended objects
console.log(ssrWindow.navigator.language); // 'en-US'
console.log(ssrDocument.title); // 'SSR Page Title'SSR Window is designed to prevent errors rather than throw them:
null or empty arrays instead of throwingsetTimeout/clearTimeoutAll methods are designed to fail silently in SSR environments while working normally in browser environments.