This improved DOM polyfill provides the minimal DOM functionality required by @observablehq/notebook-kit/dist/src/lib/serialize.js to work in a Node.js environment.
- Modular approach: Created
enhanceElement()function to handle property setup for any element type - Property-attribute synchronization: Properties like
idandtypeautomatically sync with attributes - Better textContent handling: Improved getter/setter with proper child node management
- HTML escaping: innerHTML now properly escapes text content for HTML serialization
- Improved adapter: Enhanced the
xmldomAdapterwith better error handling and type checking - NodeList compatibility: Created proper NodeList-like objects with
item()andforEach()methods - Better element filtering: Only element nodes are considered in selector operations
- Fallback handling: Graceful error handling for malformed selectors
- Complete document setup: Added
querySelectorandquerySelectorAllto the global document - Improved createTextNode: Better handling of empty/null text content
- Better element creation: All created elements are enhanced with modern DOM properties
- Proper typing: Fixed TypeScript errors while maintaining functionality
- Type-safe casts: Used appropriate type assertions where needed
- Better error handling: Comprehensive error catching and logging
Based on analysis of serialize.js, the polyfill provides:
document.createElement(tagName)- Creates enhanced elementsdocument.createTextNode(data)- Creates text nodesdocument.querySelector(selector)- Finds first matching elementdocument.querySelectorAll(selector)- Finds all matching elements
element.id- Syncs with id attributeelement.type- Syncs with type attribute (for script elements)element.textContent- Text content getter/setterelement.innerHTML- HTML content getter (read-only)element.outerHTML- Full element HTML (read-only)element.setAttribute(name, value)- Set attributeselement.hasAttribute(name)- Check for attributeselement.appendChild(child)- Add child nodes
new DOMParser().parseFromString(html, contentType)- Parse HTML strings- Parsed documents have
querySelectorandquerySelectorAllmethods
import './dom-polyfill'; // Polyfills global document and DOMParser
// Now you can use DOM operations like serialize.js does:
const notebook = document.createElement('notebook');
notebook.setAttribute('theme', 'air');
const script = document.createElement('script');
script.id = '1';
script.type = 'module';
script.textContent = 'console.log("Hello");';
notebook.appendChild(script);
console.log(notebook.outerHTML);
// Output: <notebook theme="air"><script id="1" type="module">console.log("Hello");</script></notebook>- Minimal overhead: Only polyfills what's actually needed
- Lazy property setup: Properties are defined only when elements are created
- Efficient selectors: Uses css-select library for fast CSS selector matching
- Memory efficient: No unnecessary polyfills or globals
- Works with xmldom for XML/HTML parsing
- Compatible with css-select for selector queries
- TypeScript friendly with proper type definitions
- Node.js environment focused (doesn't interfere with browser globals)