npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mutation-events

v1.0.8

Published

A polyfill for Mutation Events, using Mutation Observer

Downloads

3,182

Readme

mutation-events Polyfill

This is a polyfill of the Mutation Events:

  • DOMCharacterDataModified
  • DOMNodeInserted
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemoved
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified

Usage

To use this polyfill, simply load it before any calls to addEventListener for Mutation Events:

<script src="mutation_events.min.js"></script>
<div id=target></div>
<script>
target.addEventListener('DOMNodeInserted',() => {});
</script>

Implementation / Behavior

The polyfill monkeypatches addEventListener and removeEventListener and attaches a Mutation Observer whenever addEventListener is called with a Mutation Event name. Mutation Observer is well supported by all evergreen browsers. The polyfill also adds an implementation of the MutationEvent class, and monkeypatches Document.createEvent so that it can be created.

There is no standard for Mutation Events, and indeed there are some differences between rendering engines. Roughly, for a listener on target, the behavior is:

This polyfill is based on the behavior of Chrome v115, which differs from Safari and Firefox in a few ways:

  1. Firefox does not fire DOMNodeInsertedIntoDocument or DOMNodeRemovedFromDocument. Chrome and Safari do. This polyfill does.
  2. Firefox fires DOMSubtreeModified events when attributes are modified via target.setAttribute(), but not when changed directly via target.attributes[0].value=foo. Chrome and Safari do not fire events in either of those cases, and neither does this polyfill.
  3. Chrome and Safari fire two sets of DOMSubtreeModified events when nodes are both added and removed, e.g. via a call to replaceChildren(). They differ on the timing of the second set. Firefox only fires a single set of DOMSubtreeModified events. This polyfill fires two sets of DOMSubtreeModified events.
  4. Generally, Firefox fires bubble listeners before capture listeners on the target node, which seems broken anyway. This polyfill fires capture before bubble.

Behavior differences

There is one major differences between native Mutation Events and this polyfill which uses Mutation Observer. Since Mutation Events are synchronous, they are fired during the mutation. In contrast, Mutation Observers are fired at microtask timing, which is after the mutation. One place where this leads to observable differences is during the DOMNodeRemoved event. Native DOMNodeRemoved events are fired before the node is removed from its parent, while this polyfill fires those after the removal is complete. That leads to the event needing to be fired two places - on the removed node and also on the observed target, because ordinarily the event bubbles from the former to the latter.

Additionally, the order of events is not always the same between native Mutation Events and the events dispatched by this polyfill. But they're close.

Finally, the relatedNode field of the dispatched events is often null when using the polyfill. Ordinarily, relatedNode points to e.g. the old parent element for DOMNodeRemoved, or the new parent element for DOMNodeInserted. While the polyfill attempts to set this field correctly, it misses in several cases. The tests do not currently check relatedNode for correctness.

Tests

The test/test.html file performs several DOM mutations and monitors the events fired on the node and a parent. The test will fall back to testing the native feature, if MutationEvent is supported. You can run tests directly from this repo, here.

Improvements / Bugs

If you find issues with the polyfill, feel free to file them here. Even better, if you would like to contribute to this polyfill, I'm happy to review pull requests. Thanks in advance!