You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/docs/develop/userscripts/best-practices.md
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,15 @@
1
1
---
2
-
title: Best practices for userscripts
2
+
title: Best Practices
3
3
description: Follow these best practices when writing or reviewing userscript code.
4
4
---
5
5
6
6
Follow these best practices when writing or reviewing userscript code.
7
7
8
8
9
-
###DOM manipulation
9
+
## DOM manipulation
10
10
11
11
12
-
####Use addEventListener instead of "onevent"
12
+
### Use addEventListener instead of "onevent"
13
13
14
14
Avoid setting "onevent" values on HTML elements, such as `onclick`. Instead, use `addEventListener`. This allows multiple addons to register the same event on the same element, without conflicting.
15
15
It is still valid to use "onevent", but only for elements that were created by the same addon that is registering the event.
Avoid using the `addon.tab.waitForElement` API if the element is guaranteed to exist. It will still work, and performance will not be heavily impacted, but it might confuse other developers that are reading the code. The usage of waitForElement should usually mean that there is at least 1 scenario where the element doesn't exist at that execution point.
82
82
For example, it's not necessary to use waitForElement when searching for forum posts, unless the userscript was declared with `"runAtComplete": false`. In those cases, simply use `document.querySelectorAll()` normally.
83
83
84
84
85
-
###JavaScript best practices
85
+
## JavaScript best practices
86
86
87
87
88
-
####Use modern JavaScript
88
+
### Use modern JavaScript
89
89
90
90
- Prefer newer APIs, such as `fetch()` over `XMLHttpRequest`.
91
91
- Never use `==` for comparisons. Use `===` instead.
@@ -94,7 +94,7 @@ For example, `document.querySelector(".remix-button")?.textContent`.
94
94
- Use `for ... of` loops or `.forEach()`.
95
95
Avoid C style loops like `for (let i = 0; i < arr.length; i++)`.
96
96
97
-
####Only use "let" over "const" if the variable may be reassigned
97
+
### Only use "let" over "const" if the variable may be reassigned
98
98
99
99
{{< admonition info >}}
100
100
We usually use `camelCase` to name variables, no matter if they're declared with "let" or "const".
@@ -114,7 +114,7 @@ const DEFAULT_ZOOM = 1.20;
114
114
People reading your code may assume that a variable that was declared through the "let" keyword might be reassigned at some other point of the script. If that's not the case, use the "const" keyword instead.
115
115
Remember that in JavaScript, declaring an object or an array as a "const", does not mean its values are frozen. Values in the object can still be changed, even if the variable itself cannot be reassigned.
116
116
117
-
####Do not set global variables
117
+
### Do not set global variables
118
118
119
119
Avoid setting properties on the global `window` object, unless you are polluting a global function such as `fetch()`.
120
120
If multiple addons need to share information or functions between each other, create a JS module file and import it from both userscripts.
@@ -126,13 +126,13 @@ window.isDarkMode = true;
126
126
```
127
127
{{< /admonition >}}
128
128
129
-
####Do not declare functions outside of the default export
129
+
### Do not declare functions outside of the default export
130
130
131
131
There's no reason to declare functions outside the `export default async function(){}` function. JavaScript allows functions to be declared inside other functions.
132
132
133
133
You may move functions to separate JS module files (which aren't declared as userscripts in the addon manifest) if appropriate, but keep in mind that those imported files won't have access to the `addon` object, unless you expose a setup function that accepts it as an argument, and call the function in the userscript entry point.
134
134
135
-
####Do not unpollute functions
135
+
### Do not unpollute functions
136
136
137
137
Multiple addons might want to pollute the same function, such as Scratch VM methods, `XMLHttpRequest`, `fetch()` or `FileReader()`.
138
138
In those cases, one of the userscripts will be polluting the real function, while the others will be polluting functions which were already polluted themselves. If, for example, the first userscript that polluted decides to unpollute (for example, by doing `window.fetch = realFetch`), then all other functions in the "pollution chain" are also lost, which is unexpected.
description: Tips to easily debug userscripts, and edge cases to consider.
4
4
---
5
5
6
6
Tips to easily debug userscripts, and edge cases to consider.
7
7
8
-
####Tips
8
+
## Tips
9
9
10
-
####It's not always necessary to reload the extension
10
+
### It's not always necessary to reload the extension
11
11
12
12
It's not necessary to reload the extension by going to `chrome://extensions` when changing the source of an already existing JavaScript or CSS files. In those cases, reloading the page is enough.
13
13
14
-
####Use the addon.* API from the console
14
+
### Use the addon.* API from the console
15
15
16
16
For development, you may choose to expose the `addon` object as a global variable, so that it can be accessed within the browser console.
The `debugger;` keyword in JavaScript will freeze the page when ran, if the developer tools are open. Setting breakpoints is useful to inspect the value of local variables during execution.
28
28
29
-
####Filter console messages by addon ID
29
+
### Filter console messages by addon ID
30
30
31
31
Enter the addon ID on the "filter" console search bar to only view logs and warnings, as well errors logged with `console.error()`. Keep in mind that this will hide all exceptions, unless you're explicitly logging them in your code.
32
32
33
33
34
-
###Edge cases
34
+
## Edge cases
35
35
36
36
37
-
####Scratch project page and editor
37
+
### Scratch project page and editor
38
38
39
39
40
-
#####The DOM is destroyed after going inside or outside the editor
40
+
#### The DOM is destroyed after going inside or outside the editor
41
41
42
42
Scratch creates all HTML elements each time the user clicks "see inside" or "see project page", and destroys the old ones.
43
43
This can usually be fixed by using `addon.tab.waitForElement` or the `urlChange` event.
44
44
45
-
#####The Scratch editor language can be changed without a reload
45
+
#### The Scratch editor language can be changed without a reload
46
46
47
47
Unlike the Scratch website, the Scratch editor will not reload when changing the language. When selecting a different language, Scratch might destroy and re-create some HTML elements.
48
48
49
-
#####Other situations to consider
49
+
#### Other situations to consider
50
50
51
51
- The project editor may be used without a defined project ID (for example, when logged out).
52
52
- The editor might switch from LTR to RTL (or viceversa) without requiring a page reload.
53
53
54
54
55
-
####Scratch website
55
+
### Scratch website
56
56
57
-
#####scratch-www pages don't reload after logging in
57
+
#### scratch-www pages don't reload after logging in
58
58
59
59
Unlike scratchr2 pages, scratch-www pages do not force a page reload after logging in. For example, if you go to a project page while being logged out, then log in, the page will not reload. This also affects studios, the messages page, etc.
60
60
In contrast, all Scratch pages reload after logging out.
61
61
62
-
#####Project pages never return 404s
62
+
#### Project pages never return 404s
63
63
64
64
Even if the project is unshared or doesn't exist, Scratch returns a 200 HTTP status code. The "our server is Scratch'ing its head" message is added dynamically to the page by Scratch.
65
65
66
-
#####Other situations to consider
66
+
#### Other situations to consider
67
67
68
68
- Each of the 4 tabs inside studios have different URLs, but do not trigger a browser navigation. Addons that affect any of the 4 pages should run, no matter the initial URL.
0 commit comments