:::: MENU ::::

AngularJs – RequireJs seed

Ayant commencé à utiliser AngularJs récemment, je dois dire que je suis largement conquis.
Outre la vision sympathique de surcharger le code Html et la facilité d’arriver rapidement à ce qu’on veut, l’organisation en modules réutilisables est très intéressante puisque propre et donc maintenable et surtout testable.
Inspiré par certaines vidéos sur egghead.io (que je recommande vivement), j’ai essayé de pousser encore un peu plus loin le concept de modules indépendants en utilisant RequireJs pour gérer le chargement.

Accompagné par un serveur http basé sur express, voici un template d’un mix AngularJs RequireJs et serveur Express avec les tests adaptés sur Testacular.

Présentation du template

Architecture

angular-seed-architecture

L’ensemble des sources de l’application ( serveur + client ) est dans le répertoire src.

app.js est un simple serveur http basé sur express qui pointe sur le répertoire public, le reste de l’application est coté client.

 Chargement de l’application

Index.html sert de base pour charger RequireJs. C’est la seule insertion de la balise script, tout le reste est géré par RequireJs.

<script data-main="js/main.js" src="js/lib/Require.js"></script>

Pour plus d’infos sur comment utiliser et débuter un projet avec RequireJs, je vous renvoie vers 2 excellents tutos, simples et efficaces.

Bien que je ne sois pas encore convaincu que RequireJs apporte réellement un plus au système déjà bien conçu de modules Angular par rapport à l’ajout de “complexité” dans la configuration, il permet néanmoins de garder une bonne organisation et laisse la possibilité d’utiliser r.js pour optimiser les sources.

Une fois l’index chargé, main.js configure RequireJs et exécute la fonction d’initialisation qui se trouve dans app.js ( celui du dossier public cette fois ci ).

C’est ici qu’on va activer Angularjs et charger les différents modules. Comme le chargement est différé, l’initialisation de l’application se fait à l’aide de la commande manuelle bootstrap d’Angular ( qui remplace <html ng-app> )

On retrouvera aussi le routage de nos vues en fonction de l’url. D’ailleurs, pour l’exemple, il n’y a rien dans l’index, tout se passe dans la vue située dans template/Main.html. Elle sera chargée lorsque l’url pointera sur / .

Ca tombe bien, on y est !

 

Vues et Controlleurs

La vue est chargée et s’affiche dans notre index grâce à la directive ng-view. Elle est gérée par le controleur MainCtrl qui ne fait que donner une valeur à la variable world.

Dans la vue Main.html on retrouvera différents exemples des “jouets” d’Angularjs à savoir : deux directives, un service et caché derrière, un filtre.

 

Directives

Les deux directives d’exemples se trouvent dans le dossier js/Directives/directives.js . Elle sont activées dans la vue Main soit par balise comme pour <mydirective></mydirective> soit comme un attribut avec app-version.
mydirective se contente seulement de placer du contenu renseigné dans un template alors que appversion va utiliser un service pour le générer.

 

Services

Même logique que pour le reste, un dossier Services qui regroupent nos services. Ici il y en a qu’un qui nous retourne un numéro de version.

 

Filtres

J’ai repris le même que dans l’exemple Angular-seed à savoir un filtre qui utilise le service de version pour remplacer une chaîne de caractère avec le numéro de version.
Au passage, l’initialisation est un peu différente que pour les directives ou les services, si vous avez un meilleur moyen de le faire, je suis preneur

 

Tests

Pour terminer, j’ai réécris quelques tests unitaires qu’on peut démarrer à l’aide des lanceurs situés à la racine du projet dans le dossier scripts.

Ces tests sont réalisés à partir de Testacular avec l’adaptateur Jasmine et RequireJs.

Comme c’est un peu plus complexe avec le chargement différé de RequireJs, ça peut être intéressant d’y jeter un oeuil.

Au passage, pour ceux qui auraient des erreurs du type “Cannot start Chrome
“, il ne faut pas oublier de définir le lien vers l’executable dans le PATH. Plus d’infos par ici ( http://testacular.github.com/0.6.0/intro/troubleshooting.html ). Pareil pour des tests avec PhantomJS.

 

Améliorations

Ce Template est un exemple d’architecture d’application AngularJS / RequireJS mais ce n’est pas nécessairement la meilleur solution. Comme j’expliquais précédemment, AngularJs est déjà bien construit et ne nécessite pas forcément l’utilisation d’un système de module parallèle. De plus, cet exemple ne tient pas compte d’une éventuelle optimisation de code. Pour s’éviter tout problème, il faut déclarer explicitement les dépendances lors d’une injection pour conserver le nom de ses fonctions intact .

Par exemple :

myController.$inject = ['$location', '$log'];

 

Les sources

Vous pouvez cloner le projet qui se trouve sur github à l’adresse suivante :

https://github.com/maxdow/angularjs-requirejs-seed

 

N’hésiter pas à faire des commentaires ou proposer des améliorations .

 

 

 


6 Comments

  • Répondre Thomas Belin |

    J’ai publié très récemment mon blog en AngularJS en utilisant RequireJS et je me rend compte que mon architecture globale est très similaire à celle que tu as adoptée sur ton repo Github :)

    Je suis très convaincu de l’utilité de RequireJS et je trouve qu’il complète parfaitement le système de module d’Angular. Je ne suis pas vraiment d’accord quand tu dis qu’Angular « ne nécessite pas forcément d’un système de module parallèle » puisque tout ce qui est : chargement des sources asynchrone, modularisation des librairies externes et compilation du code (dont tu parles d’ailleurs) ne pourrait pas marcher avec Angular seul.

    Je t’invite à lire mon article sur le sujet et à me faire des retours éventuellement ( http://thomasbelin.fr/#!/posts/Single-Page-App-Blog-combiner-la-puissance-dAngularJS-avec-la-modularisation-de-RequireJS )

    En tout cas très bon article

    • Répondre maxdow |

      Merci :) J’ai justement découvert ton blog avec l’article dont tu parles ( d’ailleurs le lien ne semble pas fonctionner ? ) mais tu as anticipé mes commentaires ;)

      Justement je me pose encore la question de l’utilité ou pas de Require dans un développement sous Angular. Je pense qu’on a la même vision en ce qui concerne le fait de rendre l’architecture globale propre ( le coup de l’unique c’est aussi ce que je recherchais ). Ce qui m’embête plus c’est éventuellement le fait d’utiliser une solution un peu overkill sur un petit projet, du fait de la modularité naturelle d’Angular. Il existe en plus d’autres moyen de faire de l’asynchrone comme illustré dans le template seed d’angular (async_index.html je crois).

      Il y a quelques discussions autour du sujet déjà ( par exemple http://comments.gmane.org/gmane.comp.lang.javascript.angularjs/1265 ) mais pas vraiment de conclusion.

      Je pense que si on veut utiliser des librairies externes, la compilation de code avec r.js ( bien que du grunt peu faire le job ) c’est totalement justifié. Ensuite c’est une question d’organisation. J’aime bien la manière de travailler avec Require mais comme il ajoute une couche de complexité (surtout pour les tests) je pense que ça mérite réflexion.

        • Répondre Thomas Belin |

          Pour le lien, je pense que c’est parce que j’avais collé ma parenthèse fermante et que Disqus l’a inclue dedans (je l’ai corrigé un peu plus tard).

          En effet, la discussion sur l’utilité de RequireJS pour un petit projet peut se poser. Je dois dire que je n’ai pas vraiment d’arguments pour affirmer que RequireJS est indispensable pour un projet Angular, mais je trouve que c’est un confort en plus.
          Après, je te l’accorde, c’est un point de vue très personnel.

          Pour ce qui est des tests, je dois avouer que je ne me suis pas encoré penché sur le problème (pas bien je sais surtout qu’Angular à l’air taillé pour les tests), ça sera ma prochaine étape.

          • Vincent Kammerer |

            Un des atouts de require.js est aussi de pouvoir utiliser almond avec grunt, qui permet de n’avoir qu un seul et unique fichier js en prod

So, what do you think ?