Skip to content

Commit 433319d

Browse files
keithamuskoddsson
andcommitted
feat: add no-non-passive-high-frequency-events rule
Co-authored-by: Kristján Oddsson <koddsson@gmail.com>
1 parent 93dff8b commit 433319d

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# No Non Passive High Frequency Events
2+
3+
This rule disallows adding high frequency event listeners (`touchstart`, `touchmove`, `wheel`, `mousewheel`) without the `passive: true` option.
4+
5+
```js
6+
// bad
7+
window.addEventListener('touchstart', () => { /* ... */ })
8+
9+
// good
10+
window.addEventListener('touchstart', () => { /* ... */ }, { passive: true })
11+
```
12+
13+
## Why?
14+
15+
Adding these events listeners can block the main thread as it waits to find out if the callbacks call `preventDefault`. This can cause large amounts UI lag, which will be noticeable for users.
16+
17+
Adding `passive: true` informs the browser that this event will not be calling `preventDefault` and as such is safe to asynchronously dispatch, freeing up the main thread for lag-free operation.
18+
19+
## See Also
20+
21+
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const passiveEventListenerNames = new Set(['touchstart', 'touchmove', 'wheel', 'mousewheel'])
2+
3+
const propIsPassiveTrue = prop => prop.key && prop.key.name === 'passive' && prop.value && prop.value.value === true
4+
5+
module.exports = {
6+
meta: {
7+
docs: {}
8+
},
9+
10+
create(context) {
11+
return {
12+
['CallExpression[callee.property.name="addEventListener"]']: function(node) {
13+
const [name, listener, options] = node.arguments
14+
if (!listener) return
15+
if (name.type !== 'Literal') return
16+
if (!passiveEventListenerNames.has(name.value)) return
17+
if (options && options.type === 'ObjectExpression' && options.properties.some(propIsPassiveTrue)) return
18+
context.report(node, `High Frequency Events like "${name.value}" should be \`passive: true\``)
19+
}
20+
}
21+
}
22+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const rule = require('../lib/rules/no-non-passive-high-frequency-events')
2+
const RuleTester = require('eslint').RuleTester
3+
4+
const ruleTester = new RuleTester()
5+
6+
ruleTester.run('no-non-passive-high-frequency-events', rule, {
7+
valid: [
8+
{
9+
code: 'document.addEventListener("load", function(event) {})'
10+
},
11+
{
12+
code: 'document.addEventListener("click", function(event) {})'
13+
},
14+
{
15+
code: 'document.addEventListener("touchstart", function(event) {}, { passive: true })'
16+
},
17+
{
18+
code: 'el.addEventListener("touchstart", function(event) {}, { passive: true })'
19+
}
20+
],
21+
invalid: [
22+
{
23+
code: 'document.addEventListener("touchstart", function(event) {})',
24+
errors: [
25+
{
26+
message: 'High Frequency Events like "touchstart" should be `passive: true`',
27+
type: 'CallExpression'
28+
}
29+
]
30+
},
31+
{
32+
code: 'el.addEventListener("wheel", function(event) {})',
33+
errors: [
34+
{
35+
message: 'High Frequency Events like "wheel" should be `passive: true`',
36+
type: 'CallExpression'
37+
}
38+
]
39+
},
40+
{
41+
code: 'document.addEventListener("wheel", function(event) {})',
42+
errors: [
43+
{
44+
message: 'High Frequency Events like "wheel" should be `passive: true`',
45+
type: 'CallExpression'
46+
}
47+
]
48+
},
49+
{
50+
// Intentionally mispelled!
51+
code: 'document.addEventListener("wheel", function(event) {}, { pssive: true })',
52+
errors: [
53+
{
54+
message: 'High Frequency Events like "wheel" should be `passive: true`',
55+
type: 'CallExpression'
56+
}
57+
]
58+
},
59+
{
60+
code: 'document.addEventListener("wheel", function(event) {}, { passive: false })',
61+
errors: [
62+
{
63+
message: 'High Frequency Events like "wheel" should be `passive: true`',
64+
type: 'CallExpression'
65+
}
66+
]
67+
}
68+
]
69+
})

0 commit comments

Comments
 (0)