Conversation
Implement closest, classList, and dataset by composing the existing selector, class-name, and attribute primitives. Keep remote synchronization on the unchanged hooks and cover traversal and mutation behavior.
Preserve remote-dom's flat element model instead of changing createElement and the HTML prototype hierarchy. Dataset remains a direct wrapper around data attribute operations.
Store dataset in a symbol-backed field so repeated access returns the same live object. Use a compact lazy initializer while preserving camel-case attribute normalization.
Cache a proxied DOMTokenList and route numeric properties to live tokens while rejecting indexed writes. Keep non-index properties and methods on the token-list object.
Place one proxy behind DOMTokenList.prototype so numeric lookups read live tokens and numeric assignments are ignored without allocating a proxy per element.
Store the owner and live tokens through the existing OWNER_ELEMENT and VALUE symbols. This follows the polyfill's private-state convention and avoids string-named implementation properties.
developit
marked this pull request as ready for review
July 31, 2026 15:32
andrewiggins
added a commit
that referenced
this pull request
Sep 4, 2026
Keep NamedNodeMap instances on their ordinary prototype path while resolving indexed and named properties through one shared proxy. Preserve indexed precedence and inherited-property masking. ESM bundle (esbuild --bundle --minify): 20,707 bytes minified, 7,012 bytes gzip, and 6,309 bytes brotli. This is 25 minified bytes, 21 gzip bytes, and 28 brotli bytes larger than the per-instance proxy in 6d2a7b3. Runtime benchmark (Node 24.19.0, Apple M4 Pro, three processes with 15 warmed samples each): getAttribute throughput is 11-15% above the pre-proxy dda8de3 implementation; replacement, removal, length, item, iteration, mixed access, and serialization are within about 1% of pre-proxy. Compared with 6d2a7b3, representative common operations improve by 2.2-12.5x. Creating an element, setting its first attribute, and reading map length remains about 14% below pre-proxy and 43% above 6d2a7b3. Direct indexed and named reads measure 12.5M and 20.6M operations/second respectively. Retained V8 heap usage returns to the pre-proxy baseline: approximately 344 bytes for an element with an empty materialized map and 882 bytes with four attributes, versus 376 and 914 bytes with the per-instance proxy. This removes about 32 bytes per materialized NamedNodeMap. Index validation benchmark: retaining the non-negative whole-number checks costs 15 minified bytes, 13 gzip bytes, and 11 brotli bytes versus a parsed canonical-number-only helper, or 36 minified bytes, 19 gzip bytes, and 15 brotli bytes versus the PR #619-style check. The stricter check matches or slightly exceeds valid-index throughput, improves ordinary named and missing access by 5-7%, and improves numeric-looking named access by 22-42% by avoiding unnecessary item() traversal. It has no retained-memory cost.
andrewiggins
added a commit
that referenced
this pull request
Sep 4, 2026
Move the strict canonical non-negative integer parser to shared.ts so NamedNodeMap and the DOMTokenList work in PR #619 can use the same property-index semantics. Keep each collection's shared-prototype proxy policy local until another implementation demonstrates a useful larger abstraction. ESM bundle (esbuild --bundle --minify): 20,780 bytes minified, 7,040 bytes gzip, and 6,332 bytes brotli. Extracting the helper adds 73 minified bytes, 28 gzip bytes, and 23 brotli bytes versus the inline implementation in 9e2a1c0. Runtime benchmark (Node 24.19.0, Apple M4 Pro, three processes with 15 warmed samples each): helper extraction changes valid-index throughput by -0.3% to -1.3%, ordinary named and missing access by -2.2% to -2.9%, and numeric-looking named access by -1.3% to -2.7%. It does not change retained object layout or memory usage. Compared with simpler index checks, the strict parser costs 15 minified bytes, 13 gzip bytes, and 11 brotli bytes versus a parsed canonical-number-only helper, or 36 minified bytes, 19 gzip bytes, and 15 brotli bytes versus the PR #619-style check. It matches or slightly exceeds valid-index throughput, improves ordinary named and missing access by 5-7%, and improves numeric-looking named access by 22-42% by avoiding unnecessary item() traversal.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Remote code can now use three familiar DOM conveniences:
closest()starts with the element itself and walksparentElement, using the selector matcher already shared byquerySelector().classListprovides live token operations and read-only indexed access overclassName.datasetmaps camel-cased properties todata-*attribute reads, writes, and deletes.datasetlives on the sharedElementabstraction. Remote DOM deliberately keeps its element model flat, so this makes the API available to ordinary and custom elements without changingdocument.createElement(), constructor identity, or the existing prototype hierarchy. Each element lazily creates and caches one dataset proxy, preserving normal dataset object identity while keeping it live against attribute changes.classListis also cached per element.DOMTokenList.prototypeinherits from a shared proxy that supplies live numeric properties such asclassList[1]; numeric assignments are silently ignored. Internal state uses the polyfill's existing owner and value symbols. This avoids allocating a proxy per element and does not pretend the token list is an array or expose mutable array methods.These APIs do not add or widen any hooks. Class and data changes continue through the existing attribute methods, so remote synchronization sees exactly the same mutations it did before.
Tests
Added focused coverage for closest-ancestor traversal, live and indexed class updates, token operations, stable class-list and dataset identity, dataset name conversion, string coercion, deletion, and attribute hook calls.
Validated with:
pnpm exec vitest run(184 tests)pnpm type-checkpnpm lintpnpm --filter @remote-dom/polyfill buildon Node 20.20.0