It is important to note that JavaScript should be used to enhance the user's experience by adding engaging and interactive functionality. It is acceptable to use JavaScript to create an interactive widget (for example, a carousel or a lightbox), but it is not acceptable to use JavaScript where non-dynamic or "plain" HTML and CSS would in normal circumstances suffice - that is to say, JavaScript MUST be used only where it is strictly necessary. Examples of unnecessary JavaScript:
It's recommended that you implement Prettier to automatically lint and format your code during editing.
In common with the file formats and encodings conventions, indent with two spaces. Tabs MUST NOT be used. Lines SHOULD be kept to a reasonable length; < 100 characters is preferable. An editorConfig file should be included in a project to define the acceptable formatting rule for other developers.
Use of Standard JS or Prettier is recommended
for code. This allows consistent and predictable layout and formatting.
Formatting rules should be defined in a project's .prettierrc
or .eslintrc
file to ensure that each developer uses the same set of rules & settings.
{ "semi": true, "singleQuote": true}
Generally - two spaces for indentation, use semicolons, use single quotes are the preferred set of simple sub-rules for formatting. However set and maintain formatting standards on a project-by-project basis as appropriate.
Variables and functions SHOULD have concise but meaningful names. When
referring to a jQuery wrapped object (for example, a collection returned
from a query selector), it is a common and very useful practice to
prefix the variable name with the jQuery $
sigil.
In short:
camelCase
for variables & functionsUpperCamelCase
for constructors and prototype objectsCAPITALS_WITH_UNDERSCORES
for constants.Keeping scope small decreases the possibility of namespace collisions.
// this is the global scope(function () { function foo() { var x = 1; }})();
The following style of indentation MUST be used for functions (this is referred to as the One True Brace Style and is a variant of that used by Kernighan and Ritchie):
function func(arg1, arg2) { // body if (condition) { // action } else { // reaction }}
Indentation and bracketing style should be enforced on save or pre-commit through an automated linting rule, such as in use for this documentation.
Prettier as a code-quality tool is both highly opinionated and also automated so if it is implemented in a project, the code style enforcement looks after itself.
As of v7, Babel have deprecated the official Stage presets. It's
recommended to use babel-preset-env
It's recommended that you use a .browserslistrc
file to mandate the support
level for any transpilation but also to declare in version control the mandated
support level for your project, based on that stated in the technical
specification.
Babel upgrade can be used in existing projects to project them into the right state for Babel 7 support. The table of language features as they stood at the point of being deprecated is as follows:
It is recommended to use @babel/preset-env
(docs) in projects,
in combination with a browserlist file to control transpilation.
Frameworks in common use also offer ready-made Babel configurations and these are excellent and provide a consistent baseline for transpilation of JavaScript for use in browsers.
Generally, per the recommendations from Douglas Crockford, the following language constructs should be avoided;
However, contrary to his advice, we like arrow functions. Be careful though if you're just using the keystroke saving and end up writing difficult-to-parse code.
Remember the arrow-function gotchas; there's no arguments
object inside an arrow
function, and be careful when returning an object literal; it must be wrapped in
parentheses.
(() => console.log(arguments))(1, 2); // will raise ReferenceError: arguments is not defined(() => { foo: 1;})(); // this will return undefined. 'foo: 1' is interpreted as a statement composed of a label and the literal 1
for
use array.forEach
and its sistersfor in
. Use Object.keys(object).forEach
/** * Represents a book. * @constructor * @param {string} title - The title of the book. * @param {string} author - The author of the book. */function Book(title, author) { const $el = $(options.parentElement); // The parent of the widget}
At project inception an agreement should be in place as to the frameworks and/or libraries of use. Even if no library is to be used, the specification should identify a consistent pattern (beyond just linting rules) to be used for the organisation of JavaScript within a project.
Follow the Airbnb React/JSX Style Guide. Except where it conflicts with Prettier.
It's recommended that you use the importable config setting from NPM, to ensure conformance with industry standards.
npm install --save-dev eslint-config-react-app @typescript-eslint/eslint-plugin@^4.0.0 @typescript-eslint/parser@^4.0.0 babel-eslint@^10.0.0 eslint@^7.5.0 eslint-plugin-flowtype@^5.2.0 eslint-plugin-import@^2.22.0 eslint-plugin-jsx-a11y@^6.3.1 eslint-plugin-react@^7.20.3 eslint-plugin-react-hooks@^4.0.8
builletproof-react is a useful collection of react programming best-practice, and is useful additional reading.
We have not historically used this monolithic framework. But if a project requires it, follow the official Angular style guide.
If you're using jQuery for a project in 2021 the implementation of the framework should be cleared with senior technologists. You MUST use version 3.6 or higher.
Use of the jQuery UI Widget factory is recommended for robust organisation of your code. Each UI element should be initialised as a widget.
Use single file components to organise the components in your project. The official Vue style guide should be followed.
There's a useful article on setting up your IDE for use with Vue and eslint on Medium.
The following list of useful best practices is based on Vue Best Practices by Riccardo Polacci
Ahh memory leaks. Remember to remove listeners created with $on
by use of
$off
when destroyed()
Events are transformed automatically into lower case so declare as they will be listened to.
// Emittingthis.$emit( 'my-event') // Listening // instead of myEvent`v-on:my-event`;
Don't use the same method in two places, instead make use of the immediate
flag on a component to force the watch handler to run on initiation. You can
also implement the handler()
method inside the watch if it's not required
elsewhere in your component.
watch: { myProperty: { immediate: true, // forcing handler on initial status handler() { this.doSomething(); } }},methods: { doSomething() { console.log('doing something...'); }},// Even better solutionwatch: { myProperty: { immediate: true, // forcing handler on initial status handler() { console.log('doing something...'); // a function on methods for 1 use case } }},
:key
in v-for
loopsYour IDE should warn about this if configured properly. But always add a key to your loops.
$_
for mixin propertiesWhen you add a mixin to a component, the mixin code is merged to the component
and the component has priority. This can lead to overlapping property issues.
Prepend mixin properties with $_
to avoid this namespace clash. It's a
convention from the VueJs style guide.
However in the style guide they suggest also adding the mixin name. i.e.
$_MixinName_methodName
however this can negatively impact readability. It
should be enough simply to prepend $_
.
If we create a mixin which uses a value from the store but the value is not defined or grabbed from the store inside the mixin then the Component where the mixin is defined has to contain the property.
This is error prone. In order to avoid this, the value should be grabbed inside the mixin. Vue is clever enough to avoid duplication of work.
Pascal case has better integration with IDEs so use of this standard gives better QoL for devs, kebab-case is only a consideration in case insensitive operating systems.
Presentational dumb or pure components should have a prefix in your project which distinguishes them from other non pure components.
PascalCase is the convention for constructors and classes. It makes sense to also use this for Vue components.
Follow the same order for all options across your project. The VueJs convention can be found in the style guide.
If you do this, the whole list will have to be iterated through by your code in order to render the output of a component. It's a big performance sink.
Vuex actions use async/await and promises. Not returning from an action will result in unpredictable code execution order.
/** BAD! */// Store[SOME_ACTION] () { // Doing stuff that takes a while console.log('Action done');}// Consuming actionasync doSomething() { await dispatch(SOME_ACTION); console.log('Do stuff now');}`This will output:Do stuff nowAction done`
Instead do this;
// Store[SOME_ACTION] () { // Doing stuff that takes a while console.log('Action done'); Promise.resolve();}// Consuming actionasync doSomething() { await dispatch(SOME_ACTION); console.log('Do stuff now');}`This will output:// Action done// Do stuff now`
We create selectors for a reason, not only to be used all around the app, but also within the Vuex Store.
You may not need underscore/lodash. If you're targeting modern browsers there are a number of native methods you can use instead of the utility methods it supplies. However it does provide a uniform interface and API and therefore is supported for use in projects.
We have not fully evaluated Svelte for use in production projects. It's recommended to use Vue or React until the framework is fully reviewed.
No evaluation has yet been made on SolidJS. Until it has progressed through evaluation in to recommendation, It's recommended to use Vue or React.