bizmatch-project/bizmatch/ssr-dom-preload.mjs

155 lines
4.7 KiB
JavaScript

/**
* 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');
}