summaryrefslogtreecommitdiffstats
path: root/devtools/docs/contributor/contributing/javascript.md
blob: 25d1f1c251515ccda9d3217a9260e331bd675e25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# JavaScript coding standards

Probably the best piece of advice is **to be consistent with the rest of the code in the file**.

We use [ESLint](http://eslint.org/) to analyse JavaScript files automatically, either from within a code editor or from the command line. Here's [our guide to install and configure it](./eslint.md).

For quick reference, here are some of the main code style rules:

* file references to browser globals such as `window` and `document` need `/* eslint-env browser */` at the top of the file,
* lines should be 90 characters maximum,
* indent with 2 spaces (no tabs!),
* `camelCasePlease`,
* don't open braces on the next line,
* don't name function expressions: `let o = { doSomething: function doSomething() {} };`,
* use a space before opening paren for anonymous functions, but don't use one for named functions:
  * anonymous functions: `function () {}`
  * named functions: `function foo() {}`
  * anonymous generators: `function* () {}`
  * named generators: `function* foo() {}`
* aim for short functions, 24 lines max (ESLint has a rule that checks for function complexity too),
* `aArguments aAre the aDevil` (don't use them please),
* `"use strict";` globally per module,
* `semicolons; // use them`,
* no comma-first,
* consider using async/await for nice-looking asynchronous code instead of formatting endless `.then` chains,
* use ES6 syntax:
  * `function setBreakpoint({url, line, column}) { ... }`,
  * `(...args) => { }` rest args are awesome, no need for `arguments`,
  * `for..of` loops,
* don't use non-standard SpiderMonkey-only syntax:
  * no `for each` loops,
  * no `function () implicitReturnVal`,
  * getters / setters require { },
* only import specific, explicitly-declared symbols into your namespace:
  * `const { foo, bar } = require("foo/bar");`,
  * `const { foo, bar } = ChromeUtils.import("...");`,
* use Maps, Sets, WeakMaps when possible,
* use [template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) whenever possible to avoid concatenation, allow multi-line strings, and interpolation.


## Comments

Commenting code is important, but bad comments can hurt too, so it's important to have a few rules in mind when commenting:

* If the code can be rewritten to be made more readable, then that should be preferred over writing an explanation as a comment.
* Instead of writing a comment to explain the meaning of a poorly chosen variable name, then rename that variable.
* Avoid long separator comments like `// ****************** another section below **********`. They are often a sign that you should split a file in multiple files.
* Line comments go above the code they are commenting, not at the end of the line.
* Sentences in comments start with a capital letter and end with a period.
* Watch out for typos.
* Obsolete copy/pasted code hurts, make sure you update comments inside copy/pasted code blocks.
* A global comment at the very top of a file explaining what the file is about and the major types/classes/functions it contains is a good idea for quickly browsing code.
* If you are forced to employ some kind of hack in your code, and there's no way around it, then add a comment that explains the hack and why it is needed. The reviewer is going to ask for one anyway.
* Bullet points in comments should use stars aligned with the first comment to format each point
```javascript
// headline comment
// * bullet point 1
// * bullet point 2
```

## Asynchronous code

A lot of code in DevTools is asynchronous, because a lot of it relies on connecting to the DevTools server and getting information from there in an asynchronous fashion.

It's easy to make mistakes with asynchronous code, so here are a few guidelines that should help:

* Prefer [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) over callbacks.
* Use the `new Promise(() => {})` syntax.
* Don't forget to catch rejections by defining a rejection handler: `promise.then(() => console.log("resolved"), () => console.log("rejected"));` or `promise.catch(() => console.log("rejected"));`.
* Make use of [async and await](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function).

## React & Redux

There are React-specific code style rules in the .eslintrc file.

### Components

* Default to creating components as [stateless function components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions).
* If you need local state or lifecycle methods, use `React.createClass` instead of functions.
* Use React.DOM to create native elements. Assign it to a variable named `dom`, and use it like `dom.div({}, dom.span({}))`. You may also destructure specific elements directly: `const { div, ul } = React.DOM`.

### PropTypes

* Use [PropTypes](https://facebook.github.io/react/docs/reusable-components.html#prop-validation) to define the expected properties of your component. Each directly accessed property (or child of a property) should have a corresponding PropType.
* Use `isRequired` for any required properties.
* Place the propTypes definition at the top of the component. If using a stateless function component, place it above the declaration of the function.
* Where the children property is used, consider [validating the children](http://www.mattzabriskie.com/blog/react-validating-children).