diff --git a/.gitignore b/.gitignore index 3c3629e647..eb79dd5fc7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.idea diff --git a/README.md b/README.md index 572efb257c..ae59d61b53 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,10 @@ -# Airbnb JavaScript Style Guide() { +# RenewFinancial JavaScript Style Guide -*A mostly reasonable approach to JavaScript* - -[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) -[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +*A mostly reasonable approach to JavaScript (mostly borrowed from [Airbnb](https://github.com/airbnb/javascript))* Other Style Guides - [ES5 (Deprecated)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5) - [React](react/) - - [CSS-in-JavaScript](css-in-javascript/) - - [CSS & Sass](https://github.com/airbnb/css) - - [Ruby](https://github.com/airbnb/ruby) ## Table of Contents @@ -38,18 +31,6 @@ Other Style Guides 1. [Type Casting & Coercion](#type-casting--coercion) 1. [Naming Conventions](#naming-conventions) 1. [Accessors](#accessors) - 1. [Events](#events) - 1. [jQuery](#jquery) - 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) - 1. [ECMAScript 6+ (ES 2015+) Styles](#ecmascript-6-es-2015-styles) - 1. [Testing](#testing) - 1. [Performance](#performance) - 1. [Resources](#resources) - 1. [In the Wild](#in-the-wild) - 1. [Translation](#translation) - 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) - 1. [Chat With Us About JavaScript](#chat-with-us-about-javascript) - 1. [Contributors](#contributors) 1. [License](#license) ## Types @@ -155,7 +136,7 @@ Other Style Guides ``` - - [3.4](#es6-computed-properties) Use computed property names when creating objects with dynamic property names. + - [3.2](#es6-computed-properties) Use computed property names when creating objects with dynamic property names. > Why? They allow you to define all the properties of an object in one place. @@ -181,7 +162,7 @@ Other Style Guides ``` - - [3.5](#es6-object-shorthand) Use object method shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) + - [3.3](#es6-object-shorthand) Use object method shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) ```javascript // bad @@ -204,7 +185,7 @@ Other Style Guides ``` - - [3.6](#es6-object-concise) Use property value shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) + - [3.4](#es6-object-concise) Use property value shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) > Why? It is shorter to write and descriptive. @@ -223,7 +204,7 @@ Other Style Guides ``` - - [3.7](#objects--grouped-shorthand) Group your shorthand properties at the beginning of your object declaration. + - [3.5](#objects--grouped-shorthand) Group your shorthand properties at the beginning of your object declaration. > Why? It's easier to tell which properties are using the shorthand. @@ -253,7 +234,7 @@ Other Style Guides ``` - - [3.8](#objects--quoted-props) Only quote properties that are invalid identifiers. eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html) jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects) + - [3.6](#objects--quoted-props) Only quote properties that are invalid identifiers. eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html) jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects) > Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines. @@ -274,7 +255,7 @@ Other Style Guides ``` - - [3.9](#objects--prototype-builtins) Do not call `Object.prototype` methods directly, such as `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`. + - [3.7](#objects--prototype-builtins) Do not call `Object.prototype` methods directly, such as `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`. > Why? These methods may be shadowed by properties on the object in question - consider `{ hasOwnProperty: false }` - or, the object may be a null object (`Object.create(null)`). @@ -483,29 +464,8 @@ Other Style Guides const name = 'Capt. Janeway'; ``` - - - [6.2](#strings--line-length) Strings that cause the line to go over 100 characters should not be written across multiple lines using string concatenation. - - > Why? Broken strings are painful to work with and make code less searchable. - - ```javascript - // bad - const errorMessage = 'This is a super long error that was thrown because \ - of Batman. When you stop to think about how Batman had anything to do \ - with this, you would get nowhere \ - fast.'; - - // bad - const errorMessage = 'This is a super long error that was thrown because ' + - 'of Batman. When you stop to think about how Batman had anything to do ' + - 'with this, you would get nowhere fast.'; - - // good - const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; - ``` - - - [6.4](#es6-template-literals) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](http://eslint.org/docs/rules/template-curly-spacing) jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings) + - [6.2](#es6-template-literals) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](http://eslint.org/docs/rules/template-curly-spacing) jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings) > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. @@ -532,10 +492,10 @@ Other Style Guides ``` - - [6.5](#strings--eval) Never use `eval()` on a string, it opens too many vulnerabilities. + - [6.3](#strings--eval) Never use `eval()` on a string, it opens too many vulnerabilities. - - [6.6](#strings--escaping) Do not unnecessarily escape characters in strings. eslint: [`no-useless-escape`](http://eslint.org/docs/rules/no-useless-escape) + - [6.4](#strings--escaping) Do not unnecessarily escape characters in strings. eslint: [`no-useless-escape`](http://eslint.org/docs/rules/no-useless-escape) > Why? Backslashes harm readability, thus they should only be present when necessary. @@ -544,8 +504,8 @@ Other Style Guides const foo = '\'this\' \i\s \"quoted\"'; // good - const foo = '\'this\' is "quoted"'; - const foo = `'this' is "quoted"`; + const foo = 'this is "quoted"'; + const foo = `and 'this' is also "quoted"`; ``` **[⬆ back to top](#table-of-contents)** @@ -554,9 +514,9 @@ Other Style Guides ## Functions - - [7.1](#functions--declarations) Use named function expressions instead of function declarations. eslint: [`func-style`](http://eslint.org/docs/rules/func-style) jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations) + - [7.1](#functions--declarations) Use function declarations. eslint: [`func-style`](http://eslint.org/docs/rules/func-style) jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations) - > Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to name the expression - anonymous functions can make it harder to locate the problem in an Error's call stack. + > Why? Because life's too short, you are smart enough to figure out hoisting, and cause Schwalbe. ```javascript // bad @@ -564,12 +524,14 @@ Other Style Guides }; // bad + const foo = function bar() { + }; + + // good function foo() { } - // good - const foo = function bar() { - }; + ``` @@ -585,7 +547,7 @@ Other Style Guides ``` - - [7.3](#functions--in-blocks) Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html) + - [7.3](#functions--in-blocks) Never declare a function in a non-function block (if, while, etc). [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html) - [7.4](#functions--note-on-blocks) **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). @@ -598,7 +560,7 @@ Other Style Guides } } - // good + // bad let test; if (currentUser) { test = () => { @@ -719,17 +681,16 @@ Other Style Guides ```javascript // bad - const f = function(){}; - const g = function (){}; - const h = function() {}; + function bad(){} + function bad (){} + function bad () {} // good - const x = function () {}; - const y = function a() {}; + function good() {} ``` - - [7.12](#functions--mutate-params) Never mutate parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) + - [7.12](#functions--mutate-params) Never mutate parameters in React (and do your best with Angular). eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) > Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller. @@ -737,11 +698,14 @@ Other Style Guides // bad function f1(obj) { obj.key = 1; + ... }; // good function f2(obj) { - const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; + const newObj = _.clone(obj); + newObj.key = 1; + ... }; ``` @@ -824,7 +788,7 @@ Other Style Guides // bad [1, 2, 3].map(number => { const nextNumber = number + 1; - `A string containing the ${nextNumber}.`; + return `A string containing the ${nextNumber}.`; }); // good @@ -905,9 +869,6 @@ Other Style Guides // bad const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; - // good - const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize); - // good const itemHeight = (item) => { const { height, largeSize, smallSize } = item; @@ -1044,11 +1005,28 @@ Other Style Guides } } + // good + class Jedi { + getName() { + return this.name; + } + } + // bad class Rey extends Jedi { constructor(...args) { super(...args); } + getbBDash8() { + return this.bBDash8; + } + } + + // good + class Rey extends Jedi { + getbBDash8() { + return this.bBDash8; + } } // good @@ -1057,6 +1035,9 @@ Other Style Guides super(...args); this.name = 'Rey'; } + getbBDash8() { + return this.bBDash8; + } } ``` @@ -1101,40 +1082,67 @@ Other Style Guides // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; - export default AirbnbStyleGuide.es6; + const es6 = AirbnbStyleGuide.es6; + export { es6 }; // best import { es6 } from './AirbnbStyleGuide'; - export default es6; + export { es6 }; ``` - - - [10.2](#modules--no-wildcard) Do not use wildcard imports. - - > Why? This makes sure you have a single default export. + + - [10.2](#modules--define-api) Always define your module's API at the bottom of the file. ```javascript - // bad - import * as AirbnbStyleGuide from './AirbnbStyleGuide'; + // bad named exports + export const foo = 23; + export const bar = 42; - // good - import AirbnbStyleGuide from './AirbnbStyleGuide'; + // good named exports + const foo = 23; + const bar = 42; + export { foo, bar }; + + // bad named export + export const foo = 23; // not the last thing in the file + ... + + // good named export + ... + export const foo = 23; // the last thing and the only exported thing + + // also good named export + ... + const foo = 23; + export { foo }; + + // bad default export + export default function Foo() { ... } + ... + + // good default export + ... + export default function Foo() { ... } + + // also good default export + function Foo() { ... } + export default Foo; ``` - - [10.3](#modules--no-export-from-import) And do not export directly from an import. + - [10.3](#modules--no-export-from-import) Do not export directly from an import. > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. ```javascript // bad // filename es6.js - export { es6 as default } from './airbnbStyleGuide'; + export { es6 } from './airbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; - export default es6; + export es6; ``` @@ -1173,16 +1181,28 @@ Other Style Guides export { foo } ``` - - - [10.6](#modules--prefer-default-export) In modules with a single export, prefer default export over named export. + + - [10.6](#modules--named-export) In general, excluding React Component and Reducer files, named exports should be preferred. eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md) ```javascript // bad - export function foo() {} - - // good + ... export default function foo() {} + + // good + ... + export function foo() {} + + // also good + ... + function foo() {} + export foo; + + // also good + ... + function foo() {} + export { foo }; ``` @@ -1204,12 +1224,32 @@ Other Style Guides foo.init(); ``` + + - [10.8](#modules--multiline-imports) For imports that don't fit in one line, put all imports on their own line. If imports fit in one line, they can stay in one line. + + ```javascript + //bad + import { a, b + c, d } from 'module'; + + //good + import { + a, + b, + c, + d, + } from 'module'; + + //good + import { a, b } from 'module'; + ``` + **[⬆ back to top](#table-of-contents)** ## Iterators and Generators - - [11.1](#iterators--nope) Don't use iterators. Prefer JavaScript's higher-order functions instead of loops like `for-in` or `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](http://eslint.org/docs/rules/no-restricted-syntax) + - [11.1](#iterators--nope) Prefer JavaScript's higher-order functions instead of loops like `for-in` or `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](http://eslint.org/docs/rules/no-restricted-syntax) > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects. @@ -1237,12 +1277,12 @@ Other Style Guides ``` - - [11.2](#generators--nope) Don't use generators for now. + - [11.2](#generators--nope) We are going to use generators for now, despite AirBnb's advice. - > Why? They don't transpile well to ES5. + > They don't transpile well to ES5, which is why AirBnb recommends against them. - - [11.3](#generators--spacing) If you must use generators, or if you disregard [our advice](#generators--nope), make sure their function signature is spaced properly. eslint: [`generator-star-spacing`](http://eslint.org/docs/rules/generator-star-spacing) + - [11.3](#generators--spacing) If you use generators, make sure their function signature is spaced properly. eslint: [`generator-star-spacing`](http://eslint.org/docs/rules/generator-star-spacing) > Why? `function` and `*` are part of the same conceptual keyword - `*` is not a modifier for `function`, `function*` is a unique construct, different from `function`. @@ -1361,34 +1401,8 @@ Other Style Guides const dragonball = 'z'; ``` - - - [13.3](#variables--const-let-group) Group all your `const`s and then group all your `let`s. - - > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. - - ```javascript - // bad - let i, len, dragonball, - items = getItems(), - goSportsTeam = true; - - // bad - let i; - const items = getItems(); - let dragonball; - const goSportsTeam = true; - let len; - - // good - const goSportsTeam = true; - const items = getItems(); - let dragonball; - let i; - let length; - ``` - - - [13.4](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable place. + - [13.3](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable place. > Why? `let` and `const` are block scoped and not function scoped. @@ -1426,7 +1440,7 @@ Other Style Guides } ``` - - [13.5](#variables--no-chain-assignment) Don't chain variable assignments. + - [13.4](#variables--no-chain-assignment) Don't chain variable assignments. > Why? Chaining variable assignments creates implicit global variables. @@ -1458,36 +1472,6 @@ Other Style Guides // the same applies for `const` ``` - - - [13.6](#variables--unary-increment-decrement) Avoid using unary increments and decrements (++, --). eslint [`no-plusplus`](http://eslint.org/docs/rules/no-plusplus) - - > Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like `num += 1` instead of `num ++`. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs. - - ```javascript - // bad - - let array = [1, 2, 3]; - let num = 1; - let increment = num ++; - let decrement = -- num; - - for(let i = 0; i < array.length; i++){ - let value = array[i]; - ++value; - } - - // good - - let array = [1, 2, 3]; - let num = 1; - let increment = num += 1; - let decrement = num -= 1; - - array.forEach((value) => { - value += 1; - }); - ``` - **[⬆ back to top](#table-of-contents)** @@ -1786,38 +1770,8 @@ Other Style Guides ## Comments - - - [17.1](#comments--multiline) Use `/** ... */` for multi-line comments. - - ```javascript - // bad - // make() returns a new element - // based on the passed in tag name - // - // @param {String} tag - // @return {Element} element - function make(tag) { - - // ...stuff... - - return element; - } - - // good - /** - * make() returns a new element - * based on the passed-in tag name - */ - function make(tag) { - - // ...stuff... - - return element; - } - ``` - - - [17.2](#comments--singleline) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it's on the first line of a block. + - [17.1](#comments--singleline) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it's on the first line of a block. ```javascript // bad @@ -1856,10 +1810,10 @@ Other Style Guides ``` - - [17.3](#comments--actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`. + - [17.2](#comments--actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`. - - [17.4](#comments--fixme) Use `// FIXME:` to annotate problems. + - [17.3](#comments--fixme) Use `// FIXME:` to annotate problems. ```javascript class Calculator extends Abacus { @@ -1873,7 +1827,7 @@ Other Style Guides ``` - - [17.5](#comments--todo) Use `// TODO:` to annotate solutions to problems. + - [17.4](#comments--todo) Use `// TODO:` to annotate solutions to problems. ```javascript class Calculator extends Abacus { @@ -2018,10 +1972,10 @@ Other Style Guides // good $('#items') .find('.selected') - .highlight() - .end() + .highlight() + .end() .find('.open') - .updateCount(); + .updateCount(); // bad const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) @@ -2031,13 +1985,13 @@ Other Style Guides // good const leds = stage.selectAll('.led') - .data(data) + .data(data) .enter().append('svg:svg') - .classed('led', true) - .attr('width', (radius + margin) * 2) + .classed('led', true) + .attr('width', (radius + margin) * 2) .append('svg:g') - .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') - .call(tron.led); + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); // good const leds = stage.selectAll('.led').data(data); @@ -2184,7 +2138,7 @@ Other Style Guides ``` - - [18.12](#whitespace--max-len) Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per [above](#strings--line-length), long strings are exempt from this rule, and should not be broken up. eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength) + - [18.12](#whitespace--max-len) Avoid having lines of code that are longer than 120 characters (including whitespace): [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength) > Why? This ensures readability and maintainability. @@ -2445,6 +2399,9 @@ Other Style Guides // good const thisIsMyObject = {}; function thisIsMyFunction() {} + + // exception + const CONSTANT_VALUE = 'hello'; ``` @@ -2515,44 +2472,8 @@ Other Style Guides } ``` - - - [22.6](#naming--filename-matches-export) A base filename should exactly match the name of its default export. - - ```javascript - // file 1 contents - class CheckBox { - // ... - } - export default CheckBox; - - // file 2 contents - export default function fortyTwo() { return 42; } - - // file 3 contents - export default function insideDirectory() {} - - // in some other file - // bad - import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename - import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export - import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export - - // bad - import CheckBox from './check_box'; // PascalCase import/export, snake_case filename - import forty_two from './forty_two'; // snake_case import/filename, camelCase export - import inside_directory from './inside_directory'; // snake_case import, camelCase export - import index from './inside_directory/index'; // requiring the index file explicitly - import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly - - // good - import CheckBox from './CheckBox'; // PascalCase export/import/filename - import fortyTwo from './fortyTwo'; // camelCase export/import/filename - import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" - // ^ supports both insideDirectory.js and insideDirectory/index.js - ``` - - - [22.7](#naming--camelCase-default-export) Use camelCase when you export-default a function. Your filename should be identical to your function's name. + - [22.6](#naming--camelCase-default-export) Use camelCase when you export-default a function. ```javascript function makeStyleGuide() { @@ -2562,7 +2483,7 @@ Other Style Guides ``` - - [22.8](#naming--PascalCase-singleton) Use PascalCase when you export a constructor / class / singleton / function library / bare object. + - [22.7](#naming--PascalCase-singleton) Use PascalCase when you export a constructor / class / singleton / function library / bare object. ```javascript const AirbnbStyleGuide = { @@ -2647,377 +2568,6 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** -## Events - - - - [24.1](#events--hash) When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: - - ```javascript - // bad - $(this).trigger('listingUpdated', listing.id); - - ... - - $(this).on('listingUpdated', (e, listingId) => { - // do something with listingId - }); - ``` - - prefer: - - ```javascript - // good - $(this).trigger('listingUpdated', { listingId: listing.id }); - - ... - - $(this).on('listingUpdated', (e, data) => { - // do something with data.listingId - }); - ``` - - **[⬆ back to top](#table-of-contents)** - - -## jQuery - - - - [25.1](#jquery--dollar-prefix) Prefix jQuery object variables with a `$`. jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment) - - ```javascript - // bad - const sidebar = $('.sidebar'); - - // good - const $sidebar = $('.sidebar'); - - // good - const $sidebarBtn = $('.sidebar-btn'); - ``` - - - - [25.2](#jquery--cache) Cache jQuery lookups. - - ```javascript - // bad - function setSidebar() { - $('.sidebar').hide(); - - // ...stuff... - - $('.sidebar').css({ - 'background-color': 'pink' - }); - } - - // good - function setSidebar() { - const $sidebar = $('.sidebar'); - $sidebar.hide(); - - // ...stuff... - - $sidebar.css({ - 'background-color': 'pink' - }); - } - ``` - - - - [25.3](#jquery--queries) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - - - [25.4](#jquery--find) Use `find` with scoped jQuery object queries. - - ```javascript - // bad - $('ul', '.sidebar').hide(); - - // bad - $('.sidebar').find('ul').hide(); - - // good - $('.sidebar ul').hide(); - - // good - $('.sidebar > ul').hide(); - - // good - $sidebar.find('ul').hide(); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## ECMAScript 5 Compatibility - - - - [26.1](#es5-compat--kangax) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](https://kangax.github.io/es5-compat-table/). - -**[⬆ back to top](#table-of-contents)** - - -## ECMAScript 6+ (ES 2015+) Styles - - - - [27.1](#es6-styles) This is a collection of links to the various ES6 features. - -1. [Arrow Functions](#arrow-functions) -1. [Classes](#classes--constructors) -1. [Object Shorthand](#es6-object-shorthand) -1. [Object Concise](#es6-object-concise) -1. [Object Computed Properties](#es6-computed-properties) -1. [Template Strings](#es6-template-literals) -1. [Destructuring](#destructuring) -1. [Default Parameters](#es6-default-parameters) -1. [Rest](#es6-rest) -1. [Array Spreads](#es6-array-spreads) -1. [Let and Const](#references) -1. [Iterators and Generators](#iterators-and-generators) -1. [Modules](#modules) - - - - [27.2](#tc39-proposals) Do not use [TC39 proposals](https://github.com/tc39/proposals) that have not reached stage 3. - - > Why? [They are not finalized](https://tc39.github.io/process-document/), and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet. - -**[⬆ back to top](#table-of-contents)** - -## Testing - - - - [28.1](#testing--yup) **Yup.** - - ```javascript - function foo() { - return true; - } - ``` - - - - [28.2](#testing--for-real) **No, but seriously**: - - Whichever testing framework you use, you should be writing tests! - - Strive to write many small pure functions, and minimize where mutations occur. - - Be cautious about stubs and mocks - they can make your tests more brittle. - - We primarily use [`mocha`](https://www.npmjs.com/package/mocha) at Airbnb. [`tape`](https://www.npmjs.com/package/tape) is also used occasionally for small, separate modules. - - 100% test coverage is a good goal to strive for, even if it's not always practical to reach it. - - Whenever you fix a bug, _write a regression test_. A bug fixed without a regression test is almost certainly going to break again in the future. - -**[⬆ back to top](#table-of-contents)** - - -## Performance - - - [On Layout & Web Performance](https://www.kellegous.com/j/2013/01/26/layout-performance/) - - [String vs Array Concat](https://jsperf.com/string-vs-array-concat/2) - - [Try/Catch Cost In a Loop](https://jsperf.com/try-catch-in-loop-cost) - - [Bang Function](https://jsperf.com/bang-function) - - [jQuery Find vs Context, Selector](https://jsperf.com/jquery-find-vs-context-sel/13) - - [innerHTML vs textContent for script text](https://jsperf.com/innerhtml-vs-textcontent-for-script-text) - - [Long String Concatenation](https://jsperf.com/ya-string-concat) - - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta) - - Loading... - -**[⬆ back to top](#table-of-contents)** - - -## Resources - -**Learning ES6** - - - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html) - - [ExploringJS](http://exploringjs.com/) - - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/) - - [Comprehensive Overview of ES6 Features](http://es6-features.org/) - -**Read This** - - - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) - -**Tools** - - - Code Style Linters - + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) - + [JSHint](http://jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc) - + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) - -**Other Style Guides** - - - [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml) - - [jQuery Core Style Guidelines](https://contribute.jquery.org/style-guide/js/) - - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js) - -**Other Styles** - - - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen - - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen - - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun - - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman - -**Further Reading** - - - [Understanding JavaScript Closures](https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll - - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer - - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz - - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban - - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock - -**Books** - - - [JavaScript: The Good Parts](https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford - - [JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov - - [Pro JavaScript Design Patterns](https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz - - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders - - [Maintainable JavaScript](https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas - - [JavaScript Web Applications](https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw - - [Pro JavaScript Techniques](https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig - - [Smashing Node.js: JavaScript Everywhere](https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch - - [Secrets of the JavaScript Ninja](https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault - - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg - - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy - - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon - - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov - - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman - - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke - - [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson - -**Blogs** - - - [DailyJS](http://dailyjs.com/) - - [JavaScript Weekly](http://javascriptweekly.com/) - - [JavaScript, JavaScript...](https://javascriptweblog.wordpress.com/) - - [Bocoup Weblog](https://bocoup.com/weblog) - - [Adequately Good](http://www.adequatelygood.com/) - - [NCZOnline](https://www.nczonline.net/) - - [Perfection Kills](http://perfectionkills.com/) - - [Ben Alman](http://benalman.com/) - - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) - - [Dustin Diaz](http://dustindiaz.com/) - - [nettuts](http://code.tutsplus.com/?s=javascript) - -**Podcasts** - - - [JavaScript Air](https://javascriptair.com/) - - [JavaScript Jabber](https://devchat.tv/js-jabber/) - - -**[⬆ back to top](#table-of-contents)** - -## In the Wild - - This is a list of organizations that are using this style guide. Send us a pull request and we'll add you to the list. - - - **4Catalyzer**: [4Catalyzer/javascript](https://github.com/4Catalyzer/javascript) - - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) - - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) - - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) - - **Ascribe**: [ascribe/javascript](https://github.com/ascribe/javascript) - - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/javascript) - - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - - **Bisk**: [bisk/javascript](https://github.com/Bisk/javascript/) - - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) - - **Brainshark**: [brainshark/javascript](https://github.com/brainshark/javascript) - - **Chartboost**: [ChartBoost/javascript-style-guide](https://github.com/ChartBoost/javascript-style-guide) - - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript-style-guide) - - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) - - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) - - **DoSomething**: [DoSomething/eslint-config](https://github.com/DoSomething/eslint-config) - - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) - - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) - - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) - - **Evolution Gaming**: [evolution-gaming/javascript](https://github.com/evolution-gaming/javascript) - - **EvozonJs**: [evozonjs/javascript](https://github.com/evozonjs/javascript) - - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) - - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) - - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) - - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) - - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) - - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) - - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) - - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript-style-guide) - - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) - - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) - - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) - - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) - - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) - - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) - - **JeopardyBot**: [kesne/jeopardy-bot](https://github.com/kesne/jeopardy-bot/blob/master/STYLEGUIDE.md) - - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) - - **KickorStick**: [kickorstick/javascript](https://github.com/kickorstick/javascript) - - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/Javascript-style-guide) - - **M2GEN**: [M2GEN/javascript](https://github.com/M2GEN/javascript) - - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) - - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) - - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript) - - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) - - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) - - **Muber**: [muber/javascript](https://github.com/muber/javascript) - - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) - - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) - - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) - - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) - - **OutBoxSoft**: [OutBoxSoft/javascript](https://github.com/OutBoxSoft/javascript) - - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) - - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) - - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) - - **React**: [/facebook/react/blob/master/CONTRIBUTING.md#style-guide](https://github.com/facebook/react/blob/master/CONTRIBUTING.md#style-guide) - - **REI**: [reidev/js-style-guide](https://github.com/rei/code-style-guides/blob/master/docs/javascript.md) - - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) - - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) - - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) - - **Springload**: [springload/javascript](https://github.com/springload/javascript) - - **StratoDem Analytics**: [stratodem/javascript](https://github.com/stratodem/javascript) - - **SteelKiwi Development**: [steelkiwi/javascript](https://github.com/steelkiwi/javascript) - - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript) - - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide) - - **Syzygy Warsaw**: [syzygypl/javascript](https://github.com/syzygypl/javascript) - - **Target**: [target/javascript](https://github.com/target/javascript) - - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) - - **The Nerdery**: [thenerdery/javascript-standards](https://github.com/thenerdery/javascript-standards) - - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) - - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) - - **WeBox Studio**: [weboxstudio/javascript](https://github.com/weboxstudio/javascript) - - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) - - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) - - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) - -**[⬆ back to top](#table-of-contents)** - -## Translation - - This style guide is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) - - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) - - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) - - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese (Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) - - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) - - ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnam**: [giangpii/javascript-style-guide](https://github.com/giangpii/javascript-style-guide) - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - -## Chat With Us About JavaScript - - - Find us on [gitter](https://gitter.im/airbnb/javascript). - -## Contributors - - - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) - - ## License (The MIT License) @@ -3045,8 +2595,3 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **[⬆ back to top](#table-of-contents)** -## Amendments - -We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. - -# }; diff --git a/css-in-javascript/README.md b/css-in-javascript/README.md deleted file mode 100644 index 59c1c7bcbd..0000000000 --- a/css-in-javascript/README.md +++ /dev/null @@ -1,433 +0,0 @@ -# Airbnb CSS-in-JavaScript Style Guide - -*A mostly reasonable approach to CSS-in-JavaScript - -## Table of Contents - -1. [Naming](#naming) -1. [Ordering](#ordering) -1. [Nesting](#nesting) -1. [Inline](#inline) -1. [Themes](#themes) - -## Naming - - - Use camelCase for object keys (i.e. "selectors"). - - > Why? We access these keys as properties on the `styles` object in the component, so it is most convenient to use camelCase. - - ```js - // bad - { - 'bermuda-triangle': { - display: 'none', - }, - } - - // good - { - bermudaTriangle: { - display: 'none', - }, - } - ``` - - - Use an underscore for modifiers to other styles. - - > Why? Similar to BEM, this naming convention makes it clear that the styles are intended to modify the element preceded by the underscore. Underscores do not need to be quoted, so they are preferred over other characters, such as dashes. - - ```js - // bad - { - bruceBanner: { - color: 'pink', - transition: 'color 10s', - }, - - bruceBannerTheHulk: { - color: 'green', - }, - } - - // good - { - bruceBanner: { - color: 'pink', - transition: 'color 10s', - }, - - bruceBanner_theHulk: { - color: 'green', - }, - } - ``` - - - Use `selectorName_fallback` for sets of fallback styles. - - > Why? Similar to modifiers, keeping the naming consistent helps reveal the relationship of these styles to the styles that override them in more adequate browsers. - - ```js - // bad - { - muscles: { - display: 'flex', - }, - - muscles_sadBears: { - width: '100%', - }, - } - - // good - { - muscles: { - display: 'flex', - }, - - muscles_fallback: { - width: '100%', - }, - } - ``` - - - Use a separate selector for sets of fallback styles. - - > Why? Keeping fallback styles contained in a separate object clarifies their purpose, which improves readability. - - ```js - // bad - { - muscles: { - display: 'flex', - }, - - left: { - flexGrow: 1, - display: 'inline-block', - }, - - right: { - display: 'inline-block', - }, - } - - // good - { - muscles: { - display: 'flex', - }, - - left: { - flexGrow: 1, - }, - - left_fallback: { - display: 'inline-block', - }, - - right_fallback: { - display: 'inline-block', - }, - } - ``` - - - Use device-agnostic names (e.g. "small", "medium", and "large") to name media query breakpoints. - - > Why? Commonly used names like "phone", "tablet", and "desktop" do not match the characteristics of the devices in the real world. Using these names sets the wrong expectations. - - ```js - // bad - const breakpoints = { - mobile: '@media (max-width: 639px)', - tablet: '@media (max-width: 1047px)', - desktop: '@media (min-width: 1048px)', - }; - - // good - const breakpoints = { - small: '@media (max-width: 639px)', - medium: '@media (max-width: 1047px)', - large: '@media (min-width: 1048px)', - }; - ``` - -## Ordering - - - Define styles after the component. - - > Why? We use a higher-order component to theme our styles, which is naturally used after the component definition. Passing the styles object directly to this function reduces indirection. - - ```jsx - // bad - const styles = { - container: { - display: 'inline-block', - }, - }; - - function MyComponent({ styles }) { - return ( -
- Never doubt that a small group of thoughtful, committed citizens can - change the world. Indeed, it’s the only thing that ever has. -
- ); - } - - export default withStyles(() => styles)(MyComponent); - - - // good - function MyComponent({ styles }) { - return ( -
- Never doubt that a small group of thoughtful, committed citizens can - change the world. Indeed, it’s the only thing that ever has. -
- ); - } - - export default withStyles(() => ({ - container: { - display: 'inline-block', - }, - }))(MyComponent); - ``` - -## Nesting - - - Leave a blank line between adjacent blocks at the same indentation level. - - > Why? The whitespace improves readability and reduces the likelihood of merge conflicts. - - ```js - // bad - { - bigBang: { - display: 'inline-block', - '::before': { - content: "''", - }, - }, - universe: { - border: 'none', - }, - } - - // good - { - bigBang: { - display: 'inline-block', - - '::before': { - content: "''", - }, - }, - - universe: { - border: 'none', - }, - } - ``` - -## Inline - - - Use inline styles for styles that have a high cardinality (e.g. uses the value of a prop) and not for styles that have a low cardinality. - - > Why? Generating themed stylesheets can be expensive, so they are best for discrete sets of styles. - - ```jsx - // bad - export default function MyComponent({ spacing }) { - return ( -
- ); - } - - // good - function MyComponent({ styles, spacing }) { - return ( -
- ); - } - export default withStyles(() => ({ - periodic: { - display: 'table', - }, - }))(MyComponent); - ``` - -## Themes - - - Use an abstraction layer such as [react-with-styles](https://github.com/airbnb/react-with-styles) that enables theming. *react-with-styles gives us things like `withStyles()`, `ThemedStyleSheet`, and `css()` which are used in some of the examples in this document.* - - > Why? It is useful to have a set of shared variables for styling your components. Using an abstraction layer makes this more convenient. Additionally, this can help prevent your components from being tightly coupled to any particular underlying implementation, which gives you more freedom. - - - Define colors only in themes. - - ```js - // bad - export default withStyles(() => ({ - chuckNorris: { - color: '#bada55', - }, - }))(MyComponent); - - // good - export default withStyles(({ color }) => ({ - chuckNorris: { - color: color.badass, - }, - }))(MyComponent); - ``` - - - Define fonts only in themes. - - ```js - // bad - export default withStyles(() => ({ - towerOfPisa: { - fontStyle: 'italic', - }, - }))(MyComponent); - - // good - export default withStyles(({ font }) => ({ - towerOfPisa: { - fontStyle: font.italic, - }, - }))(MyComponent); - ``` - - - Define fonts as sets of related styles. - - ```js - // bad - export default withStyles(() => ({ - towerOfPisa: { - fontFamily: 'Italiana, "Times New Roman", serif', - fontSize: '2em', - fontStyle: 'italic', - lineHeight: 1.5, - }, - }))(MyComponent); - - // good - export default withStyles(({ font }) => ({ - towerOfPisa: { - ...font.italian, - }, - }))(MyComponent); - ``` - - - Define base grid units in theme (either as a value or a function that takes a multiplier). - - ```js - // bad - export default withStyles(() => ({ - rip: { - bottom: '-6912px', // 6 feet - }, - }))(MyComponent); - - // good - export default withStyles(({ units }) => ({ - rip: { - bottom: units(864), // 6 feet, assuming our unit is 8px - }, - }))(MyComponent); - - // good - export default withStyles(({ unit }) => ({ - rip: { - bottom: 864 * unit, // 6 feet, assuming our unit is 8px - }, - }))(MyComponent); - ``` - - - Define media queries only in themes. - - ```js - // bad - export default withStyles(() => ({ - container: { - width: '100%', - - '@media (max-width: 1047px)': { - width: '50%', - }, - }, - }))(MyComponent); - - // good - export default withStyles(({ breakpoint }) => ({ - container: { - width: '100%', - - [breakpoint.medium]: { - width: '50%', - }, - }, - }))(MyComponent); - ``` - - - Define tricky fallback properties in themes. - - > Why? Many CSS-in-JavaScript implementations merge style objects together which makes specifying fallbacks for the same property (e.g. `display`) a little tricky. To keep the approach unified, put these fallbacks in the theme. - - ```js - // bad - export default withStyles(() => ({ - .muscles { - display: 'flex', - }, - - .muscles_fallback { - 'display ': 'table', - }, - }))(MyComponent); - - // good - export default withStyles(({ fallbacks }) => ({ - .muscles { - display: 'flex', - }, - - .muscles_fallback { - [fallbacks.display]: 'table', - }, - }))(MyComponent); - - // good - export default withStyles(({ fallback }) => ({ - .muscles { - display: 'flex', - }, - - .muscles_fallback { - [fallback('display')]: 'table', - }, - }))(MyComponent); - ``` - - - Create as few custom themes as possible. Many applications may only have one theme. - - - Namespace custom theme settings under a nested object with a unique and descriptive key. - - ```js - // bad - ThemedStyleSheet.registerTheme('mySection', { - mySectionPrimaryColor: 'green', - }); - - // good - ThemedStyleSheet.registerTheme('mySection', { - mySection: { - primaryColor: 'green', - }, - }); - ``` - ---- - -CSS puns adapted from [Saijo George](http://saijogeorge.com/css-puns/). diff --git a/react/README.md b/react/README.md index d672e56b16..eb7c7fbdca 100644 --- a/react/README.md +++ b/react/README.md @@ -1,6 +1,6 @@ -# Airbnb React/JSX Style Guide +# RenewFinancial React/JSX Style Guide -*A mostly reasonable approach to React and JSX* +*A mostly reasonable approach to React and JSX (mostly borrowed from [Airbnb](https://github.com/airbnb/javascript))* ## Table of Contents @@ -12,6 +12,7 @@ 1. [Quotes](#quotes) 1. [Spacing](#spacing) 1. [Props](#props) + 1. [Proptypes](#proptypes) 1. [Refs](#refs) 1. [Parentheses](#parentheses) 1. [Tags](#tags) @@ -22,9 +23,10 @@ ## Basic Rules - Only include one React component per file. - - However, multiple [Stateless, or Pure, Components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) are allowed per file. eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless). - - Always use JSX syntax. - - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. + - eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless) + - Always use JSX syntax + - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX + - Use default exports for Component and Reducer files, use named exports for everything else. ## Class vs `React.createClass` vs stateless @@ -72,7 +74,7 @@ ## Naming - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Filename**: Use lower-case-kabob for filenames. E.g., `reservation-card.jsx`. - **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) ```jsx @@ -89,44 +91,16 @@ const reservationItem = ; ``` - - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: + - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`: ```jsx // bad - import Footer from './Footer/Footer'; - - // bad - import Footer from './Footer/index'; + import Bootsie from './Footer'; // good import Footer from './Footer'; ``` - - **Higher-order Component Naming**: Use a composite of the higher-order component's name and the passed-in component's name as the `displayName` on the generated component. For example, the higher-order component `withFoo()`, when passed a component `Bar` should produce a component with a `displayName` of `withFoo(Bar)`. - - > Why? A component's `displayName` may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening. - - ```jsx - // bad - export default function withFoo(WrappedComponent) { - return function WithFoo(props) { - return ; - } - } - - // good - export default function withFoo(WrappedComponent) { - function WithFoo(props) { - return ; - } - - const wrappedComponentName = WrappedComponent.displayName - || WrappedComponent.name - || 'Component'; - WithFoo.displayName = `withFoo(${wrappedComponentName})`; - return WithFoo; - } - ``` ## Declaration - Do not use `displayName` for naming components. Instead, name the component by reference. @@ -325,6 +299,74 @@ ))} ``` +## Proptypes + - Always use `PropTypes.shape` to define object proptypes. Avoid `PropTypes.object`. + ``` + UserDisplay.propTypes = { + user: PropTypes.shape({ + name: PropTypes.string, + email: PropTypes.string, + birthday: PropTypes.instanceOf(Date), + }), + }; + ``` + - When a component's proptypes can be used in multiple (3 or more) components, export it as a `const` from the component file. + ``` + export const statusPropTypes = { + active: PropTypes.bool.isRequired, + message: PropTypes.string.isRequired, + }; + StatusMessage.propTypes = statusPropTypes; + export default StatusMessage; + ``` + + Usage: + ``` + import StatusMessage, { statusPropTypes } from './status-message'; + + class AppContainer { }; + AppContainer.propTypes = { + status: statusPropTypes, + data: PropTypes.string.isRequired, + }; + ``` + - When a subset of a component's proptypes can be used in multiple (3 or more) components, export it as a `const` from the component file. + + ``` + export const partialFilterPropTypes = { + searchString: PropTypes.string, + onFilter: PropTypes.func, + }; + FilterData.propTypes = { + ...partialFilterPropTypes, + isFilterActive: PropTypes.bool.isRequired, + }; + ``` + - When describing a shape that is associated with multiple (3 or more) components, define the shape in a `constants/proptypes.js` file. Example: + *constants/proptypes.js* + ``` + export const userDataPropTypes = { + name: PropTypes.string, + email: PropTypes.string, + birthday: PropTypes.instanceOf(Date), + } + ``` + + *Users.jsx* + ``` + Users.propTypes = { + users: PropTypes.arrayOf(PropTypes.shape(userDataPropTypes)).isRequired, + }; + ``` + + *UserDisplay.jsx* + ``` + UserDisplay.propTypes = { + user: PropTypes.shape(userDataPropTypes).isRequired, + }; + ``` + + ## Refs - Always use ref callbacks. eslint: [`react/no-string-refs`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md) @@ -482,7 +524,7 @@ // good render() { - return (
); + return
; } ``` @@ -568,14 +610,4 @@ [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html -## Translation - - This JSX/React style guide is also available in other languages: - - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [JasonBoy/javascript](https://github.com/JasonBoy/javascript/tree/master/react) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [pietraszekl/javascript](https://github.com/pietraszekl/javascript/tree/master/react) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [apple77y/javascript](https://github.com/apple77y/javascript/tree/master/react) - - ![Br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Portuguese**: [ronal2do/javascript](https://github.com/ronal2do/airbnb-react-styleguide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide/tree/master/react) - **[⬆ back to top](#table-of-contents)**