Conventions de codage/JavaScript
Cette page documente un guide de développement de MediaWiki, construit au fil du temps par consensus des développeurs (ou parfois simplement par un des développeurs principaux) |
Cette page décrit les conventions de codage pour JavaScript dans la base de code MediaWiki. Voir aussi les conventions générales.
Linting
Nous utilisons ESLint comme outil de qualité du code, avec le préréglage eslint-config-wikimedia pour encoder la plupart de nos règles de style de codage et de qualité du code. Reportez-vous à Intégrations sur eslint.org pour trouver de nombreux éditeurs de texte ou IDE dotés de modules permettant de fournir un retour en direct pendant la saisie.
Configuration de Linter
Pour exclure des fichiers ou des répertoires de l'analyse (par exemple des bibliothèques tierces), vous pouvez configurer les modèles à ignorer dans ESLint, via un fichier .eslintignore
.[1]
Notez que node_modules
est exclu par défaut, donc la plupart des dépôts n'ont pas besoin de mettre en place des règles d'ignorance.
Chaque dépôt a besoin d'un fichier .eslintrc.json
dans le répertoire racine du dépôt.
L'exemple suivant montre un fichier de configuration ESLint :
{
"root": true,
"extends": [
"wikimedia/client",
"wikimedia/jquery",
"wikimedia/mediawiki"
],
"globals": {
// variables globales de niveau projet
},
"rules": {
// variantes des règles de niveau projet. A réduire au maximum.
}
}
Voir .eslintrc.json dans MediaWiki et l'ÉditeurVisuel pour des exemples concrets.
N'oubliez pas de définir "root": true
pour éviter un "héritage magique" involontaire des configurations d'eslint dans des répertoires parents non liés que vous ou le serveur CI pourriez avoir mis en place sur le disque (par exemple entre une extension MediaWiki et le noyau MediaWiki, ou entre votre répertoire de projet et quelque chose de votre répertoire personnel).
La préselection eslint-config-wikimedia fournit différents profils que les projets peuvent choisir à leur convenance, tel que les différentes langues, ou les varables d'environnement globales à l'exécution. Par exemple :
wikimedia/client
- pour le code du navigateur dans l'environnement ES par défaut actuel (actuellement ES6, donc un alias dewikimedia/client-es6
)wikimedia/client-es5
- pour le code du navigateur qui prévoit un support ES5wikimedia/client-es6
- pour le code du navigateur qui prévoit un support ES6
wikimedia/server
- pour le code Node.js 10+ et prévoit un support ES2018wikimedia/qunit
- un mixin pour les tests QUnit
Vous devez vous attendre à utiliser plusieurs fichiers .eslintrc.json
dans un répertoire pour définir différentes attentes environnementales pour différents sous-répertoires.
Cela permet de s'assurer que vous n'utilisez pas accidentellement les méthodes window
dans le code serveur que vous pensez exécuter sur le serveur ou que vous ne faites pas référence à QUnit dans le code de production.
Les fichiers .eslintrc.json
des sous-répertoires héritent automatiquement de la configuration du répertoire de leur parents, donc ils ne doivent contenir que les éléments spécifiques à leur dossier (fichier exemple).
Intégration continue
Nous encourageons les projets à forcer le passage de ESLint en l'incluant dans leur script npm test
via la commande test dans package.json
.
Voir Continuous integration/Entry points pour plus d'informations à ce sujet.
Si votre projet possède une chaîne de test conséquente, vous pouvez définir un script npm run lint
ou même npm run lint:js
dans package.json
pour faciliter l'exécution de ceux que vous pouvez lancer à partir de la ligne de commande pendant le développement local (de sorte à ne pas avoir à ouvrir chaque fichier dans l'éditeur et / ou attendre le CI).
Pour exposer les autres fonctionnalités du mode ligne de commande de ESLint (comme la possibilité de passer lint sur des fichiers individuels hors éditeur de texte, ou d'utiliser --fix), déclarez eslint par son propre script dans package.json sans argument. Vous pouvez ensuite l'invoquer à partir de la ligne de commande comme suit :
# le répertoire complet, récursif
$ npm run eslint -- .
$ npm run eslint -- resources/
# fichier unique
$ npm run eslint -- resources/ext.foo/bar.js
# correctif
$ npm run eslint -- --fix resources/ext.foo/
Espace blanc
Espaces
Nous utilisons les conventions suivantes :
- Indentation avec tabulations.
- Pas d'espace à la fin des lignes.
- Utilisez des lignes vides pour séparer des blocs de code indépendants.
- Un espace de chaque côté des opérateurs binaires et des opérateurs d'affectation.
- Les mots-clés suivis d'une "
(
" (parenthèse gauche) doivent être séparés par un espace. Cela permet de distinguer visuellement les mots-clés des appels de fonction. - Il ne doit pas y avoir d'espace entre le nom de la fonction et la parenthèse gauche d'une liste d'arguments.
- Il doit y avoir un espace à l'intérieur des parenthèses (comme dans les instructions if, les appels de fonction et les listes d'arguments).
- N'utilisez pas les opérateurs comme s'il s'agissait de fonctions (par exemple
delete
,void
,typeof
,new
,return
...).
Ces aspects et d'autres de notre guide de style sont appliqués avec ESLint.
Correct | Incorrect |
---|---|
a.foo = bar + baz;
if ( foo ) {
foo.bar = doBar();
}
function foo() {
return bar;
}
foo = function () {
return 'bar';
};
foo = typeof bar;
function baz( foo, bar ) {
return 'gaz';
}
baz( 'banana', 'pear' );
foo = bar[ 0 ];
foo = bar[ baz ];
foo = [ bar, baz ];
|
a.foo=bar+baz;
if( foo ){
foo.bar = doBar () ;
}
function foo () {
return bar;
};
foo = function() {
return('bar');
};
foo = typeof( bar );
function baz(foo, bar) {
return 'gaz';
}
baz('banana', 'pear');
foo = bar[0];
foo = bar[baz];
foo = [bar,baz];
|
Longueur de ligne
Les lignes ne doivent pas comporter plus de 80 à 100 caractères. Si une déclaration ne tient pas sur une seule ligne, répartissez-la sur plusieurs lignes. La suite d'une déclaration doit être indentée d'un niveau supplémentaire.
Les appels de fonction et les objets doivent être soit sur une seule ligne, soit répartis sur plusieurs lignes, avec une ligne pour chaque fragment. Évitez de fermer un appel de fonction ou un objet à un niveau d'indentation différent de celui de son ouverture.
Oui |
---|
// une ligne
if ( mw.foo.hasBar() && mw.foo.getThis() === 'that' ) {
return { first: 'Who', second: 'What' };
} else {
mw.foo( 'first', 'second' );
}
// plusieurs lignes (un composant par ligne)
if (
// début de la condition indenté d'un niveau
mw.foo.hasBar() &&
mw.foo.getThis() === 'that' &&
!mw.foo.getThatFrom( 'this' )
) {
// ↖ parenthèse fermante au même niveau que la parenthèse ouvrante.
return {
first: 'Who',
second: 'What',
third: 'I don\'t know'
};
} else {
mw.foo(
[ 'first', 'nested', 'value' ],
'second'
);
}
|
Non |
// mauvais : mélange d'une ligne seule et de plusieurs
if ( mw.foo.hasBar() && mw.foo.getThis() === 'that' &&
!mw.foo.getThatFrom( 'this' ) ) {
// mauvais : nombre variable de segments par ligne.
return { first: 'Who', second: 'What',
third: 'I don\'t know' };
} else {
mw.foo( 'first', 'second',
'third' );
// mauvais : les déclarations semblent être divisées sur plusieurs lignes mais c'est toujours la même.
// ressemble visuellement à un appel avec un paramètre, ou avec un tableau comme premier paramètre.
mw.foo(
'first', 'second', 'third'
);
mw.foo(
[ 'first', 'nested', 'value' ], 'second'
);
}
|
Structure
En résumé :
// variables ayant des valeurs initiales littérales et simples
const baz = 42;
const quux = 'apple';
// fonctions locales
function local( x ) {
return x * quux.length;
}
// déclarations principales
const foo = local( baz );
const bar = baz + foo;
Fermeture
Si l'archive d'un module ne peut pas être enregistrée - ou ne l'est pas encore - en utilisant les fichiers de paquet , alors chacun de ses fichiers JavaScript doit individuellement avoir son code inclus dans une closure globale de niveau fichier.[2] Ceci donne au code sa propre visibilité et évite la fuite des variables des autres fichiers même en mode debug, et cela d'une manière compréhensible par l'analyse statique. Ce modèle est appellé expression de fonction appelée immédiatement (immediately-invoked function expression — iffy).[3]
Pour les fichiers de paquets, cela n'est pas nécessaire, car ils sont exécutés comme un fichier de module plutôt qu'un fichier de script, qui ont naturellement leur propre domaine local de visibilité.
ESLint doit également être configuré en conséquence (définir "parserOptions": { "sourceType": "commonjs" }
, comme dans cet exemple).
Déclarations
Les variables doivent être déclarées avant leur utilisation. Chaque affectation doit être sur une ligne séparée. Les variables peuvent être déclarées à proximité ou lors de leur première affectation.
const waldo = 42;
const quux = 'apple';
let foo, bar;
const flob = [ waldo ];
if ( isFound( waldo ) ) {
foo = 1;
bar = waldo * 2;
} else {
foo = 0;
bar = 0;
}
for ( let i = 0; i < flob.length; i++ ) {
// ...
}
Les fonctions doivent être déclarées avant leur utilisation. Dans le corps de la fonction, les déclarations de la fonction doivent suivre la déclarations des variables et précéder les instructions principales.
Commentaires
Les commentaires doivent avoir leur propre ligne et précéder le code qu'ils décrivent.
Dans un commentaire, la syntaxe d'ouverture (par exemple, la double barre oblique //
ou la barre oblique suivie d'une étoile /*
) doit être séparée du texte par un seul espace, et le texte doit commencer par une lettre majuscule.
Si le commentaire est une phrase valide, il convient de mettre le caractère de fin.
Utiliser les lignes de commentaire (// foo
) dans les fonctions et les autres blocs de code (y compris pour les commentaires sur plusieurs lignes).
Utiliser les blocs de commentaire (/* foo */
) uniquement pour documenter les blocs.
Cela permet de maintenir cohérent le formatage des commentaires en ligne (par exemple, certains ne sont pas présentés sous forme de bloc et d'autres sont des commentaires multilignes, ou devant être convertis de l'un vers l'autre).
Il évite également de perturber les moteurs de documentation.
Il permet également de désactiver facilement des parties du code pendant le développement en déplaçant simplement la notation du commentaire final quelques lignes en bas, sans être interrompu par un commentaire de bloc en ligne.
Soyez généreux avec les commentaires et n'ayez pas peur de leur longueur quant à la taille du fichier. Tout le code est automatiquement réduit par ResourceLoader avant d'être utilisé.
Commentaires de documentation
- Le texte des blocs sous forme libre doit être sous forme de phrase (par exemple la description des méthodes, des paramètres, des valeurs de retour, etc.)
- Commencez les phrases par une lettre majuscule.
- Continuez les phrases appartenant à une annotation sur la ligne suivante, indentée par une espace supplémentaire.
/**
* Obtenir le nom d'utilisateur
*
* Créer dans un paragraphe supplémentaire après le premier résumé d'une ligne en
* mode impératif.
*
* @param {string} foo Description d'un paramètre qui s'étend sur la
* ligne suivante de commentaire
* @param {number} bar
* @return {string} Nom d'utilisateur
*/
Classes ES5
Pour documenter une classe qui utilise la syntaxe ES5 , avec la classe et le constructeur définis ensemble par function MyClass(…) {…}
, utiliser :
- une balise
@classdesc
pour documenter la classe - une balise
@description
pour documenter le constructeur
/**
* @classdesc Description de la classe.
*
* @description Description du constructeur.
*
* @param {string} monParamètre
* @return {string} Description
*/
Classes ES6
Pour documenter une classe qui utilise la syntaxe ES6 avec le constructeur défini par constructor()
, utiliser des commentaires séparés pour documenter la classe et le constructeur.
/**
* Description de la classe.
*/
class myClass {
/**
* Description du constructeur.
*
* @param {string} monParamètre
* @return {string} Description
*/
constructor() {...}
}
Documentation générée
Utiliser JSDock pour générer la documentation (voir doc.wikimedia.org). Pour configurer et publier la documentation JSDoc, voir JSDoc .
Égalité
- Utiliser les opérateurs d'égalité stricte (
===
et!==
) au lieu des opérateurs d'égalité (large)==
et!=
. Ces derniers réalisent la coercition des types. - N'utilisez pas les conditions Yoda.
Contrôles de type
- string:
typeof val === 'string'
- number:
typeof val === 'number'
- boolean:
typeof val === 'boolean'
- Function:
typeof val === 'function'
- object:
val === Object( val )
- plain object:
jQuery.isPlainObject( val )
- array:
Array.isArray( val )
- HTMLElement:
obj.nodeType === Node.ELEMENT_NODE
- null:
val === null
- undefined:
val === undefined
Chaînes
Utiliser des guillemets simples au lieu de guillemets doubles pour les chaînes de caractères.
Rappelez-vous qu'il n'y a pas de guillemets magiques en JavaScript, par exemple \n
et \t
fonctionnent partout.
Pour extraire un morceau d'une chaîne de caractères, utiliser la méthode slice()
pour la cohérence.
Évitez les méthodes substr()
et substring()
qui sont redondantes, faciles à confondre et peuvent avoir des effets secondaires inattendus.[4][5][6]
Exportation
Utilisez directement les variables globales exposées par le navigateur (telles que document, location, navigator) et non comme des propriétés de l'objet window.
Cela améliore la confidentialité dans le code par l'analyse statique et peut également servir à d'autres fonctionnalités de l'IDE.
Outre les variables globales du navigateur, seuls mw
, $
et OO
sont sûrs à utiliser.
Eviter de créer de nouvelles variables globales. Évitez de modifier les variables globales qui n'appartiennent pas à votre code. Par exemple, les variables globales embarquées telles que String ou Object ne doivent pas être étendues avec des méthodes d'utilité supplémentaires ; de même les fonctionnalités relatives à OOjs ou à jQuery ne doivent pas être assignées à ces variables globales.
Pour rendre une fonctionalité publique afin qu'elle soit réutilisée, utiliser module.exports
à partir des fichiers des paquets , et / ou assigner les propriétés présente dans la hiérarchie mw
, comme mw.echo.Foo
.
Noter que les variables de configuration exposées par MediaWiki doivent être accédées via mw.config
.
Environnement
Modifier des prototypes intégrés tels que Object.prototype
est considéré comme dangereux.
Cela n'est pas pris en charge dans le code de MediaWiki, et cassera probablement les fonctionnalités non liées.
Nommage
Toutes les variables doivent être nommées en utilisant la notation CamelCase avec la première lettre en minuscule, ou en utilisant que des majuscules (avec le caractère souligné '_' pour séparer les groupes de lettres) si la variable représente la valeur d'une certaine constante.
Toutes les fonctions doivent être nommées en utilisant la notation CamelCase, généralement avec la première lettre en minuscule sauf si la fonction est un constructeur de classe, auquel cas il faut commencer par une majuscule.
Il est préférable que les fonctions des méthodes commencent par un verbe comme par exemple getFoo()
au lieu de foo()
.
Abréviations
Les noms comportant des acronymes doivent traiter ces derniers comme un mot normal avec seulement la première lettre en majuscule si besoin.
Cela s'applique également aux abréviations sur deux lettres comme Id
.
Par exemple getHtmlApiSource
par opposition à getHTMLAPISource.
jQuery
Différencier les nœuds du DOM des objets jQuery en préfixant les variables avec le signe dollar '$' quand elles représentent un objet jQuery, comme $foo = $( '#bar' )
.
Ceci aide à réduire les erreurs où les tests utilisent des contrôles de condition incorrects, comme if ( foo )
au lieu de if ( $foo.length )
.
Là où les méthodes DOM retournent souvent nul (équivalent à faux), les méthodes jQuery retournent un objet de collection mais vide (qui, comme les tableaux natifs et les autres objets JavaScript, sont vrai).
npm
Lorsque vous publiez un projet indépendant sur npmjs.org, considérez que la publication se fait dans l'espace de noms @wikimedia
.
Notez que certains projets indépendants prévus pour être utilisés hors de la communauté Wikimedia ont un nom unique qui leur suffit et un nom de paquet actuel sans espace de noms dédié (comme « oojs » et « visualeditor »).
T239742
Création d'éléments
Pour créer un élément ordinaire, utilisez la syntaxe simple <tag>
dans le constructeur jQuery :
$hello = $( '<div>' )
.text( 'Hello' );
Lorsque vous créez des éléments basés sur le nom de la balise à partir d'une variable (pouvant contenir du code html arbitraire) :
// chercher 'span' ou 'div' etc.
tag = randomTagName();
$who = $( document.createElement( tag ) );
Utilisez $('<a title="valid html" href="#syntax">like this</a>');
uniquement lorsque vous devez analyser le HTML (par opposition à la création d'un élément simple).
Collections
Les différents types de collections ont parfois l'air similaire et ont un comportement différent; ils doivent être traités comme tels. Cette confusion vient principalement du fait que les tableaux JavaScript ressemblent aux tableaux des autres langages mais en réalité ils ne sont que des extensions de Object. Utilise les conventions suivantes :
Action | Tableaux | Objets à plat | Objets jQuery |
---|---|---|---|
Déclaration et initialisation vide | x = [];
|
x = {};
|
$x = $( [] );
|
Valeur accédée | x[ 0 ];
|
x.key;
|
element = $x[ 0 ]; or $y = $x.eq( 0 );
|
Taille | x.length;
|
Object.keys( x ).length;
|
$x.length;
|
Itération | for ( i = 0; i < x.length; i++ ) {} or: x.forEach( ( value, i ) => {} );
|
for ( key in x ) {}
|
$x.each( ( i, element ) => {} );
|
Évitez d'utiliser une boucle for-in
pour itérer sur un tableau (contrairement à un objet à plat), car for-in
entraînera de nombreux comportements inattendus, y compris : les clés en tant que chaînes, l'ordre d'itération instable, les indices pouvant sauter des valeurs, l'itération pouvant inclure d'autres propriétés non numériques.
Stockage
Les clés de localStorage et / ou de sessionStorage doivent être accédées via mw.storage
ou mw.storage.session
.
Clés
Les clés doivent commencer par mw
et utiliser le format camelcase et / ou des tirets.
Ne pas utiliser le catactère souligné '_' ni d'autres séparateurs.
Exemples de clés réelles :
mwuser-sessionId
mwedit-state-templatesUsed
mwpreferences-prevTab
Notez bien qu'à la différence des cookies via mw.cookie, il n'existe pas de préfixe de wiki ou de préfixe de cookie ajouté par défaut.
Si les valeurs sont fonction du wiki, vous devez inclure manuellement wgCookiePrefix
dans la clé.
Valeurs
Les valeurs doivent être des chaînes. Attention, si vous essayez de stocker d'autres types de valeurs, celles-ci seront castées en chaîne (par exemple false
deviendra "false"
).
L'espace est limité. Utiliser des valeurs courtes et concises sur les structures d'objets lorsque cela est possible. Quelques exemples :
- Pour l'état booléen (true/false, étendu/réduit), utiliser
1
ou0
. - Les valeurs toujours numériques doivent être stockées telles quelles et castées avec
Number
lors de leur utilisation (éviterparseInt
). - Pour les valeurs qui sont toujours des chaînes de caractères, conservez-les telles qu'elles sont.
- Pour les listes de valeurs définies par le logiciel, considérez les chaînes comme séparées par des virgules ',' ou par des barres verticales '|' afin de réduire l'espace et le coût de traitement.
- Pour les listes de valeurs pouvant être générées par l'utilisateur ou qui ont une nature complexe, utilisez JSON.
Stratégie d'éviction
Rappelez-vous que le stockage local n'a pas de stratégie d'évacuation par défaut. C'est pourquoi ceci doit être évité :
- Évitez d'utiliser des entrées générées par l'utilisateur pour construire des noms de clés.
- Évitez les clés qui contiennent des identifiants pour les entités générées par l'utilisateur (par exemple, les noms d'utilisateur, les noms de catégories, les identifiants de page ou les autres variables fournies par l'utilisateur ou par le système).
- D'une manière générale éviter les formes qui impliquent la création potentielle d'un grand nombre de clés de stockage.
Par exemple, si une fonctionnalité doit stocker l'état d'une entité variable (par exemple la page actuelle), il pourrait être logique d'utiliser une seule clé pour cette fonctionnalité globalement et limiter les informations stockées pour les dernières itérations (Last Recent Used). La légère augmentation du coût de récupération (clé entière au lieu de clés plus petites séparées) est considérée acceptable car autrement le nombre de clés augmenterait de manière démesurée.
Même si les clés ne dépendent pas de l'entrée utilisateur, vous pouvez toujours utiliser une seule clé pour votre fonctionnalité car sinon les versions précédentes de votre logiciel auront stocké des données que vous ne pourrez pas nettoyer. En utilisant une seule clé, vous pouvez revenir en arrière de manière à, naturellement, ne pas stocker les sous-propriétés inconnues.
L'utilisation d'une clé de suivi est également un anti-modèle et n'évite pas les problèmes ci-dessus, car cela ne fonctionnerait pas en raison des conditions de compétition sur le stockage web HTML5 partagé et non atomique entre plusieurs onglets ouverts du navigateur.
Lorsque l'utilisation du stockage local doit être supprimée pour la fonctionnalité, assurez-vous d'abord d'implémenter une stratégie d'évacuation pour nettoyer les anciennes valeurs. On utilise généralement mw.requestIdleCallback pour rechercher facilement la clé et la supprimer. Voir T121646 pour une approche qui soit plus en rapport.
Informations personnelles
Évitez de stocker des informations personnelles en local car elles restent quand un utilisateur se déconnecte ou ferme son navigateur. Utilisez plutôt le stockage de session. Voir T179752.
Code asynchrone
Le code asynchrone doit suivre et être compatible avec la norme Promise.
Si vous définissez une méthode comme asynchrone pour être appelée à partir du code, vous pouvez construire en interne l'objet thenable renvoyé soit en utilisant $.Deferred ou le Promise natif.
Lorsque vous appelez une méthode asynchrone, utilisez uniquement les méthodes classiques compatibles avec Promise telles que then()
et catch()
.
Évitez d'utiliser les méthodes spécifiques de jQuery comme done()
ou fail()
, qui pourraient cesser de fonctionner sans prévenir si la méthode que vous appelez passe en interne de $.Deferred au Promise natif.
Notez qu'il reste également des comportements anciens et subtils dans les fonctions de rappel done
et fail
.
Faites très attention lorsque vous migrez du code existant de done()
vers then()
car il peut ne plus fonctionner correctement.
Plus précisément, les procédures de rappel done
et fail
invoquent les votres de manière synchrone si Deferred a été utilisé au moment où vous les avez attachées.
Cela signifie que la fonction de rappel peut être appelée avant que l'instruction d'attachement n'ait eu le temps de se terminer.
Par exemple :
function getSqrt( num ) { return $.Deferred().resolve( Math.sqrt( num ) ); }
console.log( "A" );
getSqrt( 49 ).done( ( val ) => {
console.log( "C" ); // peut être A C B, ou, A B C
} );
console.log( "B" );
console.log( "A" );
getSqrt( 49 ).then( ( val ) => {
console.log( "C" ); // toujours A B C
} );
console.log( "B" );
const y = getSqrt( 49 ).then( ( val ) => {
console.log( y.state(), val ); // "résolu", 7
} );
const x = getSqrt( 49 ).done( ( val ) => {
console.log( x.state(), val ); // Type d'erreur non récupéré : x n'est pas défini
} );
const z = getSqrt( 49 );
z.done( ( val ) => {
console.log( x.state(), val ); // "résolu", 7
} );
jQuery
jQuery is still supported in MediaWiki and it is a useful tool, but it is slow and dated, and there are some functions and patterns to avoid. The following emit warnings or errors in eslint-config-wikimedia.
- Avoid functions in the jQuery library that are deprecated, since these will be removed from jQuery at some point or already have been. Examples:
.addSelf
,.bind
,.unbind
,.boxModel
,.browser
,.camelCase
,.context
,.delegate
,.undelegate
, etc.[7] - Avoid functions in the jQuery library that have ES5/ES6 equivalents. The ES5/ES6 equivalents are faster. Examples:
.each
,.grep
,.inArray
,.map
,.trim
,.error
,.extend
,.noop
.[8] - Avoid functions in the jQuery library that have CSS equivalents. The CSS equivalents are faster. Examples:
.animate
,.stop
,.finish
,.fadeIn
,.fadeOut
,.fadeTo
,.fadeToggle
,.slideDown
,.slideToggle
,.slideUp
, etc.[8] - Avoid using jQuery to query the DOM, for performance reasons and to avoid selecting incorrect elements by mistake. Prefer hooks such as
mw.hook( 'wikipage.content' ).add( ( $content ) => {
, which provides a$content
element that you can do.find()
s on. When you create elements, store them in a variable, then retrieve them later using the variable or$variable.find()
. - Avoid sizzle selectors, for performance reasons and because some sizzle syntax is already deprecated. For example, avoid
$( '#mw-specialmute-form input:checkbox' )
and$input.is( ':visible' )
. - Avoid
.globalEval
. - Generate complex HTML using multiple jQuery functions instead of just a string in the
$()
function. For example, prefer$( '<a>' ).attr( 'href', 'https://test.com' ).text( 'Test' )
to$( '<a href="https://test.com">Test</a>' )
. The latter is prone to errors that linters cannot detect, and triggers jQuery's HTML parser, which is slow.[11]
Notes finales
Réutiliser les modules ResourceLoader
Ne réinventez pas la roue. Beaucoup de fonctionnalités JavaScript et les utilitaires liés à MediaWiki sont fournis avec le noyau MediaWiki et sont stables et vous pouvez (littéralement) les utiliser dans vos dépendances. Voir ResourceLoader/Core modules avant de développer votre propre code.
Pièges
- Veillez à préserver la compatibilité des langues LTR qui s'écrivent de gauche à droite et les RTL qui s'écrivent de droite à gauche (commme
float: right
outext-align: left
), particulièrement quand vous formatez des conteneurs de texte. En mettant ces déclarations dans le fichier CSS, elles seront automatiquement inversées pour les langues RTL par CSSJanus en ResourceLoader . - Utiliser
attr()
etprop()
selon le cas.
Autres lectures : - En conséquence mettez des apostrophes autour les valeurs du sélecteur d'attributs :
[foo="bar"]
au lieu de[foo=bar]
(jqbug 8229). - À partir de jQuery 1.4 le constructeur jQuery a une nouvelle fonctionnalité qui permet de passer un objet dans le deuxième argument, comme :
$( '<div>', { foo: 'bar', click: () => {}, css: { .. } } );
. N'utilisez pas ceci. Ca rend le code plus difficile à suivre, échoue sur les attributs (tels que la taille 'size') qui sont aussi des méthodes, et c'est instable en raison de ce mélange de méthodes jQuery avec des attributs d'éléments. Une future méthode jQuery ou un greffon appelé « title » pourrait convertir un élément en titre, ce qui signifie que l'attribut titre ne peut plus être initialisé par cette méthode. Soyez explicite et appelez.attr()
,.prop()
,.on()
etc. directement.
Utiliser CSS pour styliser de nombreux éléments
N'appliquez pas de style à un grand nombre d'éléments à la fois car cela peut dégrader les performances.
Utilisez plutôt la classe d'un parent commun (ou ajoutez-en un) et appliquez le CSS dans un fichier .css
ou .less
.
Grâce à ResourceLoader, tout sera chargé dans la même requête HTTP, de sorte qu'il n'y a pas de dégradation des performances due à la présence d'un fichier CSS distinct.
Ne mettez pas de CSS dans les attributs "style" en ligne, n'insérez pas non plus d'éléments "style" à partir de JavaScript.
Références
- Guide de style pour JavaScript, contribution à jQuery
- Conventions de codage pour JavaScript, Douglas Crockford
- Le style de la programmation et votre cerveau, Douglas Crockford sur YouTube
- ↑ Décider de la méthode eslint ignore à utiliser, avril 2020.
- ↑ T50886: suppression des closure obsolètes dans les fichiers, avril 2019.
- ↑ http://benalman.com/news/2010/11/immediately-invoked-function-expression/
- ↑ Utiliser substr(), substring(), ou slice() ?
- ↑ Chaînes de caractères en JavaScript, Maîtriser le JS.
- ↑ Change 158108 - mediawiki/core, , gerrit.wikimedia.org
- ↑ https://github.com/wikimedia/eslint-config-wikimedia/blob/91e9a0ba09bc77471d21c1e92d24fa190109a08e/jquery.json#L8
- ↑ 8.0 8.1 https://github.com/wikimedia/eslint-config-wikimedia/blob/91e9a0ba09bc77471d21c1e92d24fa190109a08e/jquery.json#L11-L28
- ↑ https://github.com/wikimedia/eslint-plugin-no-jquery/blob/master/docs/rules/no-global-selector.md
- ↑ https://github.com/wikimedia/eslint-plugin-no-jquery/blob/master/docs/rules/no-class-state.md
- ↑ https://github.com/wikimedia/eslint-plugin-no-jquery/blob/master/docs/rules/no-parse-html-literal.md