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 🙏

© 2026 – Pkg Stats / Ryan Hefner

mount-polyfill

v0.0.0

Published

Author: Bruce B. Anderson

Readme

DOM orchestration: The mount api

Author: Bruce B. Anderson

Issues / pr's: mount-polyfill

Last Update: 2023-11-16

What follows is a more ambitious alternative to this proposal. The goals of the mount api are larger, and less focused on registering custom elements. In fact, this proposal is trying to address a large number of use cases in one api. It is basically mapping common filtering conditions in the DOM, to common actions, like importing a resource, or sharing some common element settings, resulting in lower bandwidth. The underlying theme is this api is meant to make it easy for the developer to do the right thing, by encouraging lazy loading and smaller footprints.

The extra flexibility this new primitive would provide could be quite useful to things other than custom elements, such as implementing custom enhancements as well as binding from a distance in userland.

To specify the equivalent of what the alternative proposal linked to above would do, we can do the following:

const observe = mount({
   sift:'my-element',
   import: './my-element.js',
   do: ({localName}, {module}) => customElements.define(localName, module.MyElement)
});

If no import is specified, it would go straight to do.

Why "mount"? It is shorter than "orchestrate" and is used quite a bit in current frameworks (whereas orchestrate isn't).

The word mount has multiple meanings, but the one that we are leveraging is "to organize and initiate (a campaign or other significant course of action)" which is precisely what we want to do with this api.

This only searches for elements matching 'my-element' outside any shadow DOM.

The import can also be a function, and sift can specify to search within a node:

const observe = mount({
   sift:{
      for: 'my-element',
      within: myRootNode,
   },
   import: async (matchingElement, {module}) => await import('./my-element.js')
});

which would work better with current bundlers, I suspect. Also, we can do interesting things like merge multiple imports into one "module".

This proposal would also include support for CSS, JSON, HTML module imports.

"sift" or "sift.for" is a css query, and could include multiple matches using the comma separator, i.e. no limitation on CSS expressions.

The "observer" constant above is a class instance that inherits from EventTarget, which means it can be subscribed to by outside interests.

As matches are found (for example, right away if matching elements are immediately found), the imports object would maintain a read-only array of weak references, along with the imported module:

interface MountContext {
    weakReferences:  readonly WeakRef<Element>[];
    module: any;
}

This allows code that comes into being after the matching elements were found, to "get caught up" on all the matches.

Benefits of this API

This api doesn't pry open some ability developers currently lack, with at least one possible exception. It is unclear how to use mutation observers to observe changes to custom state. Rather, it strives to make it easy to achieve what is currently common but difficult to implement functionality. The amount of code necessary to accomplish these common tasks designed to improve the user experience is significant. Building it into the platform would potentially:

  1. Give the developer a strong signal to do the right thing, by
    1. Making lazy loading easy, to the benefit of users with expensive networks.
    2. Supporting "binding from a distance" which can allow SSR to provide common, shared data using the "DRY" philosophy, similar to how CSS can reduce the amount of repetitive styling instructions found inline within the HTML Markup.
  2. Allow numerous components / libraries to leverage this common functionality, which could potentially significantly reduce bandwidth.
  3. Potentially by allowing the platform to do more work in the low-level (c/c++/rust?) code, without as much context switching into the JavaScript memory space, which may reduce cpu cycles as well.

Extra lazy loading

By default, the matches would be reported as soon as an element matching the criterion is found or added into the DOM, inside the node specified by rootNode.

However, we could make the loading even more lazy by specifying intersection options:

const observer = mount({
   sift:{
      for: 'my-element',
      within: document.body,
      mountIf:{
         rootMargin: "0px",
         threshold: 1.0,
      }
   }
   import: './my-element.js'
})

Media / container queries

Unlike traditional CSS @import, CSS Modules don't support specifying different imports based on media queries. That can be another condition we can attach (and why not throw in container queries, based on the rootNode?):

const observer = mount({
   sift:{
      for: 'my-element',
      within: myRootNode,
      whereMediaMatches: '(max-width: 1250px)',
      withContainerQuery: '(min-width: 700px)'
   }
   import: ['./my-element-small.css', {type: 'css'}]
})

Subscribing

Subscribing can be done via:

observer.addEventListener('import', e => {
  console.log({
      matchingElement: e.matchingElement, 
      module: e.module
   });
});

Preemptive downloading

There are two significant steps to imports, each of which imposes a cost:

  1. Downloading the resource.
  2. Loading the resource into memory.

What if we want to download the resource ahead of time, but only load into memory when needed?

The link rel=modulepreload option provides an already existing platform support for this, but the browser complains when no use of the resource is used within a short time span of page load. That doesn't really fit the bill for lazy loading custom elements and other resources.

So for this we add option:

const observer = mount({
   match: 'my-element',
   within: document.body,
   loading: 'eager',
   import: './my-element.js',
   callback: (matchingElement, {module}) => customElements.define(module.MyElement)
})

The value of "loading" is 'lazy' by default.

InstanceOf checks

const observer = mount({
   match: '*',
   within: document.body,
   ifInstanceOf: [HTMLMarqueeElement],
   import: './my-marquee-element-enhancement.js',
   callback: (matchingElement, {module}) => customEnhancements.define('myMarqueeElementEnhancement', module.MyMarqueeElementEnhancement)
})