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

passive-events-support

v1.1.0

Published

Passive Events Support

Downloads

15,380

Readme

Passive Events Support

Introduction

The Issue

How many times have you yourself forgotten to make an event listener as passive, or installed a library such as Bootstrap, jQuery or Materialize and suddenly in the Google Chrome you see:

[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as passive to make the page more responsive.

Or when running Lighthouse you get a lower score with a message:

Does not use passive listeners to improve scrolling performance

Consider marking your touch and wheel event listeners as passive to improve your page's scroll performance.

What's a passive option?

According to Official Documentation a passive option is:

A boolean value that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning.

Why is it necessary?

It is well docummented that:

According to the specification, the default value for the passive option is always false. However, this introduces the potential for event listeners handling certain touch events (among others) to block the browser's main thread while it is attempting to handle scrolling, resulting in possibly enormous reduction in performance during scroll handling.

See Improving scrolling performance with passive listeners to learn more.

The solution

Making event listeners as passive manually could be a repetetive and time consuming experience. Also if caused by a 3rd party, modifying it's source code should never be an option!

Here comes the Passive Events Support package! This is the package that will help you debug the source, solve the issue, but also improve the performance. It is flexible and highly configurable package!

How it works

When event listener does not have a passive option, it will be added and its value will depend on whether preventDefault() is being called in the handler or not.

When event listener is not calling preventDefault() and passive option is not passed, it will add a { passive: true }

element.addEventListener('touchstart', (e) => {}) // { passive: true }

When event listener is calling preventDefault() and passive option are not passed, it will add a { passive: false }

element.addEventListener('touchstart', (e) => { e.preventDefault() }) // { passive: false }

When passive or other option is passed, their values will not be overwritten

element.addEventListener('touchstart', handler) // { passive: true }
element.addEventListener('touchstart', handler, { passive: false }) // { passive: false }
element.addEventListener('touchstart', handler, { capture: true) // { capture: true, passive: true }
element.addEventListener('touchstart', handler, { capture: false, passive: false }) // { capture: false, passive: false }

Installation

yarn add passive-events-support

Usage

This package must be imported before any package or code that is causing an issue or Lighthouse warning.

// With JS
import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport({/*...*/})
<!-- With HTML -->
<script>
  window.passiveSupport = {/*...*/}
</script>
<script type="text/javascript" src="node_modules/passive-events-support/dist/main.js"></script>

By default, importing this package will not update non-passive event listeners. For this package to act, you must specify which event listeners should be made as passive. See the Configuration section below.

Configuration

It is highly recommended to configure and only pass the custom list of event listeners, that trigger the console or Lighthouse warning.

Configurable Options

| Option | Type | Default | | --- | --- | --- | | debug | boolean | false | | events | array | [] | | listeners | array | [] |

Option: debug

When enabled, all the non-passive event listeners will be console logged.

{
  debug: true
}

Console output

[Passive Events Support] Non-passive Event Listener
  element: div.some-element
  event: 'touchstart'
  handler:
    fn: ƒ (e)
    fnArgument: 'e'
    fnContent: 'console.log(e)'
    fnPrevented: false
  arguments: false
  updatedArguments: { passive: true }

The updatedArguments parameter will be shown only if the event listener was updated by this package.

Option: events

The list of events whose event listeners will have a passive option assigned with the value of true or false decided by the package as it is documented in the How It Works section.

Supported Events:

| Type | Events | | --- | --- | | Touch | touchstart, touchmove, touchenter, touchend, touchleave | | Wheel | wheel, mousewheel |

{
  events: ['touchstart', 'touchmove']
}

Events that are not supported will be ignored.

Known events option issue:

While this option enables the package to assign the correct passive option value to all the event listeners for the listed events it also might break certain event listeners. The issue appear when preventDefault() is not being called from the handler itself, but rather from the another method called by the handler. In this case this package loses the track of preventDefault() and it marks the event listener as passive. This causes the event listener to break prompting an error message:

Unable to preventDefault inside passive event listener invocation.

Luckilly, this can easilly be debugged in debug mode and fixed by the listeners configuration option!

Option: listeners (Recommended)

With this option, instead of certain events, you target certain event listeners.

When working altogether with events option, this option could be used to fix the event listeners broken by events option.

{
  listeners: [
    {
      element: '.select-choice',
      event: 'touchstart',
      prevented: true // (optional) will force { passive: false }
    },
    {
      element: '.select-choice',
      event: 'touchmove'
    }
  ]
}

When prevented option is not presented, the package will calculate the passive value automatically as it is documented in the How It Works section.

Events that are not supported will be ignored. See supported events list.

Browser Support

Even tho the passive option is not supported by all the browsers (see Browser compatibility), this package, by default, checks the browser support for passive option before assigning it.

Debugging the browser support

You can yourself access the variable indicating the support:

// With JS
import { passiveSupported } from 'passive-events-support/src/utils'
console.log(passiveSupported())
<!-- With HTML -->
<script type="text/javascript" src="node_modules/passive-events-support/dist/main.js"></script>
<script>
  console.log(window.passiveSupported)
</script>

Manually assigning the passive option

You, just like this package, yourself can manually add the passive option:

// use window.passiveSupported if imported with <script>
element.addEventListener('tocuhstart', handler, passiveSupported() ? { passive: true } : false)