AngularJS et Browserify : le duo gagnant
⏲️ ~6 min de lecture
Publié le
par
Adrien
Angularjs
Browserify
Dans cet article, nous allons créer une petite application AngularJS à l'aide de Browserify qui va permettre de modulariser facilement notre code et donner accès aux nombreux paquets npm dans notre navigateur.
Browserify all the things #
Browserify est un outil qui permet de gérer vos dépendances JavaScript à la manière du require('dependency')
de Node qui fonctionne en chargeant le module demandé via un fichier éponyme ayant une extension .js
/ .json
/ .node
.
À l'aide de Browserify, nous allons amener ce comportement dans notre navigateur et pouvoir utiliser à la fois des paquets npm et nos propres modules dans notre application AngularJS.
Pour installer Browserify, rien de plus simple :
npm install -g browserify
Et maintenant un petit exemple d'utilisation, l'objectif étant ici d'utiliser à la fois un paquet npm et un module construit par nos soins :
var square = require('./square'); var unique = require('uniq'); var data = [1, 2, 2, 3, 4, 5, 5, 5]; var result = unique(data).map(square); console.log(result);
On installe le module uniq
via npm :
npm install uniq
On passe maintenant à la création du fichier square.js :
function square(n) { return n * n; } module.exports = square;
Et finalement on compile avec la commande browserify
, celle-ci va créer un fichier qui va intégrer nos différentes dépendances :
browserify app.js -o bundle.js
Un node bundle.js
plus tard et voila le résultat :
[ 1, 4, 9, 16, 25 ]
Avec AngularJS #
L'utilisation de Browserify combinée à la syntaxe Controller As va permettre de mettre en place des POJO réutilisables au travers de nos différentes applications JavaScript.
Passons à la création d'une petite application AngularJS (un repository github est disponible : ang-browserify-sample).
Pour commencer, nous allons inclure AngularJS dans notre projet, celui-ci est disponible au travers d'un packet npm
npm-angular :
npm install angular --save
Il suffira ensuite de l'inclure dans notre projet :
var angular = require('angular');
Il est également possible d'utiliser directement les sources, ce qui permet d'avoir une version à jour, le package npm n'utilisant pas la dernière version disponible d'Angular. Au moment de l'écriture de l'article, le paquet npm utilise la version 1.2.23 alors que la version 1.2.25 est la dernière version disponible.
Pour une version à jour nous allons définir un nouveau module utilisable par Browserify. Pour cela, il faut le déclarer dans le package.json
après l'avoir exporté en tant que module.
Dans un fichier angular.browserify.js
:
require('./angular.min'); module.exports = angular;
Dans le package.json :
"browser": { "angular-latest": "./vendors/angular.browserify.js" }
Désormais on peut inclure notre module AngularJS tout neuf avec :
var angular = require('angular-latest');
Et le tour est joué.
Maintenant nous allons commencer à utiliser browserify pour découper notre application Angular et déclarer nos différentes dépendances. Commençons par déclarer notre application AngularJS :
var angular = require('angular-latest'); var modules = [require('angular-ui-router')]; var app = angular.module('app', modules);
Jusque ici, pas grand chose de nouveau, là où les choses deviennent intéressantes, c'est lorsque l'on commence à externaliser nos contrôleurs, services et factories :
app.config(['$stateProvider', '$urlRouterProvider', require('./configs').router]); app.factory('Contact', [require('./factories/contact.js')]); app.service('ContactService', ['Contact', require('./services/contactService.js')]); app.controller('ContactCtrl', ['ContactService', require('./controllers/contactCtrl.js')]);
Chacune des fonctions de retour que nous déclarions auparavant directement dans un composant AngularJS peut maintenant étre extraite dans un fichier différent et facilement appelée au moment de l'initialisation de nos contrôleur, services et factories.
Créons maintenant les différents fichiers appelés par notre application :
config.js
, c'est le fichier de configuration de l'application, il contient ici uniquement le routing (j'utilise ici ui-router) :
var Configs = { router: function($stateProvider, $urlRouterProvider) { this.contacts = { name: 'contacts', url: '', templateUrl: 'views/contacts.html', controller: 'ContactCtrl as Contact' }; this.contactsInfo = { name: 'contacts.info', parent: 'contacts', url: '/:id', templateUrl: 'views/contacts.info.html', controller: function($stateParams, ContactService) { ContactService.selectContact($stateParams.id); this.contact = ContactService.selectedContact; }, controllerAs: 'ContactInfo' }; $stateProvider .state(this.contacts) .state(this.contactsInfo); } } module.exports = Configs;
On définit notre modèle dans les fichiers contact.js
et contactService.js
:
function Contact() { return function(id, name, phone) { this.id = id; this.name = name; this.phone = phone; }; } module.exports = Contact;
function ContactService(Contact) { this.contacts = [ new Contact(1, 'Damien', '0102030405'), new Contact(2, 'Pierre', '0203040501'), new Contact(3, 'Hadrien', '0304050102'), new Contact(4, 'Adrien', '0405010203'), new Contact(5, 'Frank', '0501020304'), new Contact(6, 'Etienne', '0504030201') ]; this.selectedContact; } ContactService.prototype.all = function() { return this.contacts; }; ContactService.prototype.selectContact = function(contactId) { this.selectedContact = this.contacts.filter(function(contact) { return contact.id == contactId; })[0]; }; module.exports = ContactService;
Je me sers du service afin d'accéder à mes entités qui sont définies dans ma factory. Il contient également la logique métier liée à mon modèle (ici la sélection d'un contact par exemple).
Et finalement le contrôleur contactCtrl.js
:
function ContactCtrl(ContactService) { this.ContactService = ContactService; this.contacts = this.ContactService.all(); }; ContactCtrl.prototype.isSelectedContact = function(contactId) { return this.ContactService.selectedContact.id === contactId; }; ContactCtrl.prototype.selectContact = function(contactId) { this.ContactService.selectContact(contactId); }; module.exports = ContactCtrl;
On remarque la facilité de découpage de notre application, chaque composant (configuration, modèle ou contrôleur) peut être facilement réutilisé, le code de notre application est simplifié et facilement maintenable.
Automatiser la génération #
Une fois que l'application est en marche, il reste à automatiser la génération de notre fichier bundle.js
à chaque modification, pour cela plusieurs solutions sont disponibles.
Watchify #
Watchify permet de mettre à jour notre bundle Browserify à chaque modification d'un fichier source.
On l'installe comme tout bon packet npm
:
npm install -g watchify
Pour l'utiliser en tant que script npm
et l'utiliser facilement, on l'ajoute dans notre package.json
:
"scripts": { "watchify": "watchify app/app.js -o htdocs/dest/bundle.js" },
On le lance ensuite avec la commande :
npm run watchify
Chaque modification dans notre code va maintenant provoquer une nouvelle génération de notre bundle.js
.
Gulp #
Si vous utilisez Gulp, voici un exemple de tâche Browserfify à intégrer dans votre gulpfile.js
var gulp = require('gulp'); var browserify = require('gulp-browserify'); var rename = require('gulp-rename'); gulp.task('browserify', function() { gulp.src('app/app.js') .pipe(browserify({ insertGlobals: true })) .pipe(rename('bundle.js')) .pipe(gulp.dest('./htdocs/dest')) }); gulp.task('watch', function() { gulp.watch(['app/**/*.js'],[ 'browserify' ]); });
Vous êtes maitenant en mesure de structurer votre application AngularJS avec Browserify !
N'hésitez pas à faire vos retours.
Cet article vous a plu ? Sachez que nous recrutons !