JavaScript style guide
We use Airbnb's JavaScript Style Guide and it's accompanying linter to manage most of our JavaScript style guidelines.
In addition to the style guidelines set by Airbnb, we also have a few specific rules listed below.
Tip: You can run eslint locally by running
yarn eslint
Arrays
-
1.1 Avoid ForEach when mutating data Use
map
,reduce
orfilter
instead offorEach
when mutating data. This will minimize mutations in functions (which is aligned with Airbnb's style guide)// bad users.forEach((user, index) => { user.id = index; }); // good const usersWithId = users.map((user, index) => { return Object.assign({}, user, { id: index }); });
Functions
-
2.1 Limit number of parameters If your function or method has more than 3 parameters, use an object as a parameter instead.
// bad function a(p1, p2, p3) { // ... }; // good function a(p) { // ... };
Classes & constructors
-
3.1 Avoid side effects in constructors Avoid making some operations in the
constructor
, such as asynchronous calls, API requests and DOM manipulations. Prefer moving them into separate functions. This will make tests easier to write and code easier to maintain.// bad class myClass { constructor(config) { this.config = config; axios.get(this.config.endpoint) } } // good class myClass { constructor(config) { this.config = config; } makeRequest() { axios.get(this.config.endpoint) } } const instance = new myClass(); instance.makeRequest();
-
3.2 Avoid classes to handle DOM events If the only purpose of the class is to bind a DOM event and handle the callback, prefer using a function.
// bad class myClass { constructor(config) { this.config = config; } init() { document.addEventListener('click', () => {}); } } // good const myFunction = () => { document.addEventListener('click', () => { // handle callback here }); }
-
3.3 Pass element container to constructor When your class manipulates the DOM, receive the element container as a parameter. This is more maintainable and performant.
// bad class a { constructor() { document.querySelector('.b'); } } // good class a { constructor(options) { options.container.querySelector('.b'); } }
Type Casting & Coercion
-
4.1 Use ParseInt Use
ParseInt
when converting a numeric string into a number.// bad Number('10') // good parseInt('10', 10);
CSS Selectors
-
5.1 Use js prefix If a CSS class is only being used in JavaScript as a reference to the element, prefix the class name with
js-
// bad <button class="add-user"></button> // good <button class="js-add-user"></button>
Modules
-
6.1 Use absolute paths for nearby modules Use absolute paths if the module you are importing is less than two levels up.
// bad import GitLabStyleGuide from '~/guides/GitLabStyleGuide'; // good import GitLabStyleGuide from '../GitLabStyleGuide';
-
6.2 Use relative paths for distant modules If the module you are importing is two or more levels up, use a relative path instead of an absolute path.
// bad import GitLabStyleGuide from '../../../guides/GitLabStyleGuide'; // good import GitLabStyleGuide from '~/GitLabStyleGuide';
- 6.3 Do not add to global namespace
-
6.4 Do not use DOMContentLoaded in non-page modules Imported modules should act the same each time they are loaded.
DOMContentLoaded
events are only allowed on modules loaded in the/pages/*
directory because those are loaded dynamically with webpack.
Security
-
7.1 Avoid XSS Do not use
innerHTML
,append()
orhtml()
to set content. It opens up too many vulnerabilities.
ESLint
- 8.1 Disabling ESLint in new files Do not disable ESLint when creating new files. Existing files may have existing rules disabled due to legacy compatibility reasons but they are in the process of being refactored.
-
8.2 Disabling ESLint rule Do not disable specific ESLint rules. Due to technical debt, you may disable the following rules only if you are invoking/instantiating existing code modules
Note: Disable these rules on a per line basis. This makes it easier to refactor in the future. E.g. use
eslint-disable-next-line
oreslint-disable-line