/** * Node.js Preload Script for SSR Development * * This script creates DOM global mocks BEFORE any modules are loaded. * It only applies in the main thread - NOT in worker threads (sass, esbuild). */ import { isMainThread } from 'node:worker_threads'; // Only apply polyfills in the main thread, not in workers if (!isMainThread) { // Skip polyfills in worker threads to avoid breaking sass/esbuild // console.log('[SSR] Skipping polyfills in worker thread'); } else { // Create screen mock const screenMock = { width: 1920, height: 1080, availWidth: 1920, availHeight: 1080, colorDepth: 24, pixelDepth: 24, deviceXDPI: 96, deviceYDPI: 96, logicalXDPI: 96, logicalYDPI: 96, }; // Create document mock const documentMock = { createElement: (tag) => ({ style: {}, setAttribute: () => { }, getAttribute: () => null, appendChild: () => { }, removeChild: () => { }, classList: { add: () => { }, remove: () => { }, contains: () => false }, tagName: tag?.toUpperCase() || 'DIV', }), createElementNS: (ns, tag) => ({ style: {}, setAttribute: () => { }, getAttribute: () => null, appendChild: () => { }, getBBox: () => ({ x: 0, y: 0, width: 0, height: 0 }), tagName: tag?.toUpperCase() || 'SVG', }), createTextNode: () => ({}), head: { appendChild: () => { }, removeChild: () => { } }, body: { appendChild: () => { }, removeChild: () => { } }, documentElement: { style: {}, clientWidth: 1920, clientHeight: 1080, querySelector: () => null, querySelectorAll: () => [], getAttribute: () => null, setAttribute: () => { }, }, addEventListener: () => { }, removeEventListener: () => { }, querySelector: () => null, querySelectorAll: () => [], getElementById: () => null, getElementsByTagName: () => [], getElementsByClassName: () => [], }; // Create window mock const windowMock = { requestAnimationFrame: (callback) => setTimeout(callback, 16), cancelAnimationFrame: (id) => clearTimeout(id), addEventListener: () => { }, removeEventListener: () => { }, getComputedStyle: () => ({ getPropertyValue: () => '' }), matchMedia: () => ({ matches: false, addListener: () => { }, removeListener: () => { }, addEventListener: () => { }, removeEventListener: () => { }, }), document: documentMock, screen: screenMock, devicePixelRatio: 1, navigator: { userAgent: 'node', platform: 'server', language: 'en', languages: ['en'], onLine: true, geolocation: null, }, location: { hostname: 'localhost', href: 'http://localhost', protocol: 'http:', pathname: '/', search: '', hash: '', host: 'localhost', origin: 'http://localhost', }, history: { pushState: () => { }, replaceState: () => { }, back: () => { }, forward: () => { }, go: () => { }, length: 0, }, localStorage: { getItem: () => null, setItem: () => { }, removeItem: () => { }, clear: () => { }, }, sessionStorage: { getItem: () => null, setItem: () => { }, removeItem: () => { }, clear: () => { }, }, setTimeout, clearTimeout, setInterval, clearInterval, innerWidth: 1920, innerHeight: 1080, outerWidth: 1920, outerHeight: 1080, scrollX: 0, scrollY: 0, pageXOffset: 0, pageYOffset: 0, scrollTo: () => { }, scroll: () => { }, Image: class Image { }, HTMLElement: class HTMLElement { }, SVGElement: class SVGElement { }, }; // Set globals globalThis.window = windowMock; globalThis.document = documentMock; globalThis.navigator = windowMock.navigator; globalThis.screen = screenMock; globalThis.HTMLElement = windowMock.HTMLElement; globalThis.SVGElement = windowMock.SVGElement; globalThis.localStorage = windowMock.localStorage; globalThis.sessionStorage = windowMock.sessionStorage; console.log('[SSR] DOM polyfills loaded'); }