#Introduction
Ce guide est la traduction francaise de AngularJS style guide
Le but de ce style-guide est de présenter un ensemble de meilleures pratiques et lignes directrices pour une application AngularJS. Ces pratiques sont collectées à partir de:
- Le code source d'AngularJS.
- Le code source ou des articles que j'ai lu
- Ma propre expérience
** Note **: c'est encore un projet, son principal objectif est d'être piloter par les développements et développeurs AngularJS, donc combler les lacunes sera grandement appréciée par l'ensemble de la communauté.
Dans ce document, vous ne trouverez pas de lignes directrices communes pour le développement JavaScript. Tel que vous pouvez les trouver ici :
- Google's JavaScript style guide
- Mozilla's JavaScript style guide
- GitHub's JavaScript style guide
- Douglas Crockford's JavaScript style guide
Pour le développement de AngularJS, le guide recommandé est Google's JavaScript style guide.
Dans le wiki Github d'AngularJS, il y a une section similaire de ProLoser, vous pouvez la consulter ici.
#Table des matières
#General
Etant donné qu'une grande application AngularJS a beaucoup de composants, il est préférable de les structurer dans une hiérarchie de répertoires. Il existe deux approches principales:
- Créer une division de haut niveau par types de composants et une division inférieure par fonctionnalité.
De cette façon, la structure de répertoire va ressembler à :
.
├── app
│ ├── app.js
│ ├── controllers
│ │ ├── page1
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ └── page2
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── page1
│ │ │ └── directive1.js
│ │ └── page2
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ ├── page1
│ │ └── page2
│ └── services
│ ├── CommonService.js
│ ├── cache
│ │ ├── Cache1.js
│ │ └── Cache2.js
│ └── models
│ ├── Model1.js
│ └── Model2.js
├── lib
└── test
- Créer une division de haut niveau par fonctionnalité et de niveau inférieur par type de composants.
Ce qui donnera alors:
.
├── app
│ ├── app.js
│ ├── common
│ │ ├── controllers
│ │ ├── directives
│ │ ├── filters
│ │ └── services
│ ├── page1
│ │ ├── controllers
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ ├── directives
│ │ │ └── directive1.js
│ │ ├── filters
│ │ │ ├── filter1.js
│ │ │ └── filter2.js
│ │ └── services
│ │ ├── service1.js
│ │ └── service2.js
│ └── page2
│ ├── controllers
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ └── filter3.js
│ └── services
│ └── service3.js
├── lib
└── test
- Lors de la création d'une directive, il pourrait être utile de mettre tous les fichiers associés (Modèles, CSS / fichiers SASS, JavaScript) dans un seul dossier. Si vous choisissez d'utiliser ce style d'arborescence, soyez cohérent et utilisez le partout dans votre projet.
app
└── directives
├── directive1
│ ├── directive1.html
│ ├── directive1.js
│ └── directive1.sass
└── directive2
├── directive2.html
├── directive2.js
└── directive2.sass
Cette approche peut être combinée avec les deux structures de répertoires ci-dessus.
- Une plus légère variation de structures de répertoires est celle utilisée dans ng-boilerplate. Dans ce mode, les tests unitaires pour un composant donné sont en attente dans le dossier du composant. De cette façon, lorsque vous effectuez des modifications dans les composants, il est plus facile de trouver leurs tests. Les tests servent également de documentation et de cas d'exemple.
services
├── cache
│ ├── cache1.js
│ └── cache1.spec.js
└── models
├── model1.js
└── model1.spec.js
- Le fichier
app.js
contient les définitions de route, la configuration et/ou l'amorçage manuel (si nécessaire). - Chaque fichier JavaScript doit contenir un seul composant. Le fichier doit être nommé avec le nom du composant.
- Utilisez un modèle de structure de projet pour Angular comme Yeoman, ng-boilerplate.
Je préfère la première structure, car il rend les composants communs faciles à trouver.
les conventions sur le nommage des composants peuvent être trouvés dans chaque section des composants.
- Surveiller ($watch) seulement les variables les plus importantes (par exemple: lors de l'utilisation de communication en temps réel, ne pas provoquer une boucle dans chaque message reçu).
- Faire les calculs dans
$watch
aussi simple que possible. Faire des calculs lourds et lents dans un seul$watch
va ralentir l'ensemble de l'application (la boucle $digest se fait dans un seul thread en raison de la nature mono-thread de JavaScript).
- Utilisation:
$timeout
au lieu desetTimeout
$window
au lieu dewindow
$document
au lieu dedocument
$http
au lieu de$.ajax
Cela rendra vos tests plus facile et, dans certains cas, évitera les comportements inattendus (par exemple, si vous avez oublié $scope.$apply
dans setTimeout
).
-
Automatisez votre flux de travail en utilisant des outils comme: * Yeoman * Grunt * Bower
-
Utilisez des promises (
$q
) au lieu de rappels(callback). Il rendra votre code plus élégant, propre et simple à regarder, et vous sauvera de l'enfer des callbacks. -
Utilisez
$resource
au lieu de$http
quand cela est possible. Un niveau d'abstraction plus élevé vous permet d'économiser de la redondance. -
Utilisez un pré-minifier AngularJS (comme ngmin ou ng_annote) pour la prévention des problèmes après minification.
-
Ne pas utiliser de globales. Résoudre toutes les dépendances en utilisant l'injection de dépendances.
-
Ne pas polluer votre portée
$scope
. Ajouter uniquement des fonctions et des variables qui sont utilisés dans les modèles. -
Préférer l'utilisation de contrôleurs au lieu de
ngInit
. La seule utilisation appropriée dengInit
est pour initialiser des propriétés particulières dengRepeat
. Outre ce cas, vous devez utiliser les contrôleurs plutôt quengInit
pour initialiser les valeurs sur une portée. -
Ne pas utiliser le prefixe
$
pour les noms de variables, les propriétés et les méthodes. Ce préfixe est réservé pour un usage de AngularJS.
#Modules
Il ya deux façons communes pour structurer les modules:
- Par fonctionnalité
- Par type de composant
Actuellement il n'y a pas une grande différence, mais la première méthode semble plus propre. En outre, si le chargement de modules en lazy-loading est mis en œuvre (pas dans la feuille de route AngularJS), il permettra d'améliorer la performance de l'application.
#Controllers
- Ne pas manipuler le DOM dans vos contrôleurs. Cela rendrait vos contrôleurs plus difficile pour les tests et viole le [Principe de séparation des couches] (https://en.wikipedia.org/wiki/Separation_of_concerns). Utilisez des directives à la place.
- La désignation du contrôleur se fait en utilisant la fonctionnalité du contrôleur (par exemple panier, page d'accueil, panneau d'administration) ave la chaîne
Ctrl
à la fin. Les contrôleurs sont nommés en UpperCamelCase (HomePageCtrl
,ShoppingCartCtrl
,AdminPanelCtrl
, etc.) - Les contrôleurs ne doivent pas être définis comme globales (aucune méthode AngularJS ne le permet, c'est une mauvaise pratique qui va polluer l'espace de noms global).
- Utilisez la syntaxe de tableau pour les définitions de contrôleur:
module.controller('MyCtrl', ['dependency1', 'dependency2', ..., 'dependencyn', function (dependency1, dependency2, ..., dependencyn) {
//...body
}]);
L'utilisation de ce type de définition évite les problèmes avec minification. Vous pouvez générer automatiquement la définition du champ à l'aide des outils comme ng-annotate et tâche grunt grunt-ng-annotate).
- Utilisez les noms d'origine des dépendances du contrôleur. Cela vous aidera à produire un code plus lisible:
module.controller('MyCtrl', ['$scope', function (s) {
//...body
}]);
est moins lisible que :
module.controller('MyCtrl', ['$scope', function ($scope) {
//...body
}]);
Cela s'applique en particulier à un fichier qui a tellement de code que vous aurez besoin de scroller pour faire défiler. Cela peut vous faire oublier la variable qui est lié à la dépendance.
- Faire les contrôleurs aussi mince que possible. Eviter les fonctions abstraites couramment utilisées dans un service.
- Communiquer entre les différents contrôleurs en utilisant la méthode invocation (possible lorsque les enfants veulent communiquer avec un parent) ou
$emit
,$broadcast
et$on
. Les messages émis et diffusés doivent être réduites au minimum. - Faites une liste de tous les messages qui sont transmis en utilisant
$emit
,$broadcast
et gérez les avec précaution car des conflits de noms sont possibles et sources d'éventuels bugs. - Si vous devez formater les données alors encapsulez la logique de mise en forme dans un filter et déclarez-le comme dépendance:
module.filter('myFormat', function () {
return function () {
//body...
};
});
module.controller('MyCtrl', ['$scope', 'myFormatFilter', function ($scope, myFormatFilter) {
//body...
}]);
#Directives
- Nommez vos directives en lowerCamelCase
- Utilisez
scope
au lieu de$scope
dans votre fonction de lien. Dans la compilation, les fonctions de liaison pré/post compilation, vous avez déjà les arguments qui sont passés lorsque la fonction est appelée, vous ne serez pas en mesure de les modifier à l'aide de DI. Ce style est également utilisé dans le code source de AngularJS. - Utilisez les préfixes personnalisés pour vos directives pour éviter les collisions de noms de bibliothèques tierces.
- Ne pas utiliser
ng
ouui
comme préfixe car ils sont réservés pour AngularJS et l'utilisation de AngularJS UI. - Les manipulations du DOM doivent être effectués uniquement avec des directives.
- Créer un scope isolé lorsque vous développez des composants réutilisables.
- Utilisez des directives comme des attributs ou des éléments au lieu de commentaires ou de classes, cela va rendre le code plus lisible.
- Utilisez
$scope.$on('$destroy, fn)
pour le nettoyage de vos objects/variables. Ceci est particulièrement utile lorsque vous utilisez des plugins tiers comme directives. - Ne pas oublier d'utiliser
$sce
lorsque vous devez faire face à un contenu non approuvé.
#Filters
- Nommez vos filtres en lowerCamelCase
- Faites vos filtres aussi léger que possible. Ils sont souvent appelés lors de la boucle
$digest
donc créer un filtre lent va ralentir votre application.
#Services
- Utilisez camelCase (inférieure ou supérieure) pour nommer vos services.
- Encapsuler la logique métier dans des services.
- Les services sont préférables à une
factory
. De cette façon, nous pouvons profiter de l'héritage "classice" plus facilement
function Human() {
//body
}
Human.prototype.talk = function () {
return "I'm talking";
};
function Developer() {
//body
}
Developer.prototype = Object.create(Human.prototype);
Developer.prototype.code = function () {
return "I'm codding";
};
myModule.service('Human', Human);
myModule.service('Developer', Developer);
- Pour un cache au niveau de la session, utilisez
$cacheFactory
. Cela doit être utilisé pour mettre en cache les résultats des requêtes ou des calculs lourds.
#Templates
- Utilisez
ng-bind
oung-cloak
au lieu de simples{{ }}
pour prévenir les collisions de contenus - Eviter d'écrire du code complexe dans les modèles
- Quand vous avez besoin de définir le
src
d'une image dynamiquement, utilisezng-src
au lieu desrc
avec{{}}
dans le modèle. Ceci pour permettre un refresh dynamique ? (NLDT) - Au lieu d'utiliser la variable $scope en tant que chaîne et de l'utiliser avec l'atribut
style
et{{}}
, utilisez la directiveng-style
avec les paramètres de l'objet comme et les variables de scope comme valeurs:
<script>
...
$scope.divStyle = {
width: 200,
position: 'relative'
};
...
</script>
<div ng-style="divStyle">my beautifully styled div which will work in IE</div>;
#Routing
- Utilisez
resolve
pour résoudre les dépendances avant que la vue ne soit affichée.
#Testing
TBD
#Contribution
Puisque le but de ce guide est d'être axé sur la communauté, les contributions sont grandement appréciées. Par exemple, vous pouvez contribuer par l'extension de la section de contrôle ou par la traduction du guide de style à votre langue.