Fork me on GitHub

Introduction

Après l'échec cuisant d'un second billet sur la Devoxx, il était peut être temps de se remettre en selle et de ne pas laisser mourir ce blog de sa belle mort. Non glandouillerie ! Tu ne m'auras pas sans lutter ! Cette fois, parlons un peu de Web, et plus exactement, de Javascript. Plus exactement encore, des extensions navigateurs et, spécifiquement (promis c'est fini), des extensions pour Firefox. Un des aspects à retenir de la Devoxx était la tendance de la communauté Java à s'ouvrir un peu à autre chose. Certains auraient tendance à dire qu'il était temps mais étant moi même un jeune membre de cette communauté, je ne saurais en parler. Du bout de ma lorgnette, le monde est peuplé de gentils geeks, volant de langages en langages aussi facilement que sur le dos d'une licorne (J’exagère à peine). Bref, plus de la moitié des conférences de la Devoxx, et même des conférences tout cours, si l'on regarde le nombre d'évènements Parisiens dédiés au développement, sont aujourd'hui tournés vers le Web, aux langages fonctionnels et au meilleur candidat pouvant relier les deux mondes : le Javascript. Alors vous allez me dire, ouiii, toussaaa, le Web existe depuis bien longtemps, le Javascript est un langage qui a toujours été mis à l'écart et que, finalement, les acteurs de la mode actuelle ne font que se réveiller d'un sommeil bien profond. And so what? Il y aura toujours des early adopters, il y aura toujours des disciplines populaires. A nous de faire le tri parmi tout ça et de surfer sur les bonnes vagues, au bon moment. Je suis sur que tout un tas de développeurs Erlang seraient ravis de voir émerger une période dédiée à leur langage préféré. Et étant moi même un fervent utilisateur de GNU/Linux, je ne cracherais pas sur une reconnaissance un peu plus sympa du grand publique. Et puis après tout, depuis quand faut-il attendre qu'untel ou unetelle nous dise quel est LE langage à la mode avant de s'y intéresser? L'informatique a la chance d'être un domaine en pleine expansion et il fournira probablement assez de nouveautés et d'innovations pour nous occuper jusqu'à la fin de nos jours. Je ne parle même pas de job... nous allons devenir indispensables les gars ! Toujours est-il que la conjonction des planètes iPhone, NoSQL, Multi-Core avec la géante gazeuse Web et ses satellites HTML 5 et REST fait que tout le monde parle de révolution et cherche un nouveau leader en (allons y gaiement) Javascript. Javascript côté client, Javascript côté serveur, pour les applications mobiles, pour faire des extensions, etc... J'arrête immédiatement les détracteurs, je ne suis pas un allumé du ciboulot, j'aime encore personnellement beaucoup Java. Et pour ceux qui douterais encore du sérieux du langage, regardez bien autour de vous. Je l'ai vu faire des choses vraiment formidables, ce qui ne présage que de bonnes choses pour l'avenir. Il a aussi l'avantage d'être un bon tremplin avant d'aller sur des langages full fonctionnels. Je vous invite également à venir voir de vous mêmes la population de formidables hackers lors de conférences. Un des acteurs majeur du Web depuis maintenant bien longtemps est Mozilla. Que l'on aime ou que l'on n'aime pas Firefox n'enlèvera jamais tout le travail que la fondation a fait pour nous. Chrome, de certains points de vues est peut être meilleur aujourd'hui mais à mon sens, c'est temporaire et il apporte d'abord une saine et bénéfique concurrence à l'égale de ce qui se fait depuis 20 ans dans le monde du logiciel libre. C'est grâce à Mozilla que Internet Explorer est sorti de sa torpeur, beaucoup d'innovations sont de leur fait, même si certaines manquent de communications et, plus important, leur philosophie de ce que doit être le Web est le bon chemin à suivre. Ils n'imposent rien à personnes, il veulent un Internet aux mains de leurs utilisateurs. Pourquoi je parle de Mozilla? Hm... au hasard parce que c'est un billet sur les Addons Firefox? Ok, bon, mais pourquoi tout le pavé qui parle du Web? Facile ! Parce qu'il n'y a pas trop longtemps, Mozilla a décidé de repartir complètement de zéro (deux fois même !) au sujet du développement d'extensions pour leur navigateur et ils ont choisis le dernier cri en matière de technologies.

Go !

Je ne parlerai pas de XUL et de XCOM, je n'y connais pas grand chose, mais nous allons plutôt voir comment développer une extension avec le nouveau SDK de Mozilla. Anciennement appelé Jetpack lors de sa phase prototype, son petit nom officiel est : Firefox Addons SDK. Beaucoup de développeurs ayant utilisés Jetpack depuis ses débuts sont d'ailleurs assez frustrés de la tournure des événements et de la perte de compatibilité du jour au lendemain. Toutefois, il est grand temps de soigner ses blessures et de s'y remettre, le SDK est désormais stabilisé et il est dors et déjà utilisable pour la beta de Firefox 4. La raison de cette "cassure" est bien mieux expliqué ici par le grand Aza Raskin mais globalement, il fallait remodeler un peu le cœur du projet pour pouvoir proposer un SDK amélioré par des outils Web de demain, indépendant d'une version de navigateur (l'intégralité du SDK et des dépendances sont inclues dans l'archive !), permettant un redémarrage à chaud et ouvert aux projets de Mozilla tels que Bespin ou Flightdeck et surtout Elecrolysis. Ce fameux SDK est composé de deux éléments : Un outils développé en python permettant de faciliter le boulot du développeur en proposant de la génération de documentation, un environnement de tests, la génération automatique de fichiers xpi et j'en passe. Puis, un large panel d'APIs Javascript permettant de s'interfacer avec le navigateur et pouvoir exécuter les actions courantes. Le plus sympa étant que ces APIs soient basées sur la spécification CommonJS, ce qui vous permet en fait de pouvoir inclure dans vos extensions toute librairie compatible avec cette spéc, node.js y compris ! Et mieux encore, une extension pour Firefox est un module CommonJS à part entière, donc pour peu que le développeur fasse attention, pour 0€ supplémentaire, on peux développer des APIs Javascript compatibles avec Firefox, Node.js et probablement un tas de futurs Framework. Pour l'installation c'est facile, il suffit de télécharger ça, de le décompresser où l'on veut et voilà. Par contre, pour commencer à coder comme des fous il faut d'abord lancer l'environnement du SDK avec une petite commande :
Sous Linux : source bin/activate Sous Windows : bin/activate.bat

Bon mais quand est-ce qu'on code?

D'accord, d'accord, il est temps de passer au choses sérieuses. Mais qu'est ce qu'on code? Et bien imaginons que l'on veuille écrire une extension Firefox pour Rss Todo List, une petite application bien pratique développée par Grégory Paul qui permet de créer des flux RSS pour y ajouter des adresses Internet dont on veut se souvenir. Le concept est assez simple, on choisi un nom et ça fait un flux que l'on a plus qu'à ajouter dans son agrégateur et que l'on peut réutiliser plus tard afin de s'envoyer à soit même, ou à d'autre, des liens intéressants. Très rapidement, vous allez faire la connaissance de la commande la plus utilisée du SDK : cfx, c'est le petit outils fourni par Mozilla pour vous faciliter la vie. Par exemple, pour démarrer un Addon Firefox de zéro, on commence par créer un répertoire au nom de l'extension désirée dans le répertoire <addon-sdk>/package/ et on exécute la commande suivante :
cfx init
En moins de deux, une arborescence complète est disponible et immédiatement utilisable. Pour l'instant sa seule utilité est d'afficher une icône Mozilla qui, si l'on clique dessus, redirige vers le site de Mozilla... mais bon...Hem. Une petite description s'impose ici. Cette arborescence, comme je le disais plus haut est l'arborescence de base d'un module CommonJS :
  • Un fichier package.json contient la description de notre module, les auteurs, la version, le nom, etc... ainsi que les dépendances CommonJS dont le module a besoin
  • README.md comme son nom l'indique va servir de lisez-moi et, comme toutes les documentations d'un addon Firefox, est structuré en Markdown qui ressemble fortement à un langage de wiki.
  • Le répertoire data va accueillir les fichiers internes à l'application (des icônes par exemple)
  • Dans le répertoire lib ira le code source
  • docs, la documentation globale. Également en Markdown, elle peut être divisée pour détailler chaque sous librairie
  • Et enfin, le répertoire tests contiendra le code source des tests unitaires
Les autres commandes les plus utilisées seront :
cfx docs
Un mini serveur est lancé qui permet d'avoir accès à la documentation du SDK en local. Mais ce n'est pas tout, cette documentation va automatiquement ingérer les modules sur lesquels vous êtes en train de travailler. Vous pouvez donc voir directement de quoi votre documentation à l'air et si vous développer vous même des APIs (ou même si vous intégrez des librairies CommonJS externes), leur documentation y apparaitra aussi.
cfx test
Lance la série de tests unitaires.
cfx run
Plus util, démarre une instance de Firefox avec votre extension chargée à l'intérieur. Cette instance utilise un profil sandboxé pour ne pas surcharger vos essais. Et enfin, the last but not the least :
cfx xpi
Génère automatique un binaire livrable que l'on peux utiliser tel quel dans son navigateur préféré ! Je ne rentre pas dans les détails mais toutes ces commandes sont livrées avec des tas d'options. Comme la possibilité d'utiliser un profil personnalisé dans Firefox, charger des valeurs par défauts dans ses librairies, d'autres addons, etc...

Et ensuite ?

Tout d'abord, à quoi va ressembler notre application finale, de quoi va-t-on avoir besoin? Depuis la mort de Jetpack, les développeurs de Mozilla ont déportés toutes les icônes des extensions de la barre de status vers une barre de widget. Donc finalement, on aimerait bien pouvoir avoir sa petite icône la dedans. Si l'on clique dessus, on accède à un menu ou une page dans laquelle on a des champs de formulaire remplis par défaut, que l'on peut renseigner. Des boutons d'actions seraient bien, par exemple cliquer sur ajout enverrait une requête au serveur et ajouterait l'URL de la page que nous sommes en train de visiter, au flux. Mieux, comme l'on risque d'utiliser toujours un flux préféré (avec son nom pourquoi pas), cette valeur pourrait être sauvegardée dans le navigateur afin de la retrouver même après un redémarrage. Pour faire ça il va nous falloir, côté UI :
  • Un objet Widget. Autrement dit, le droit d'apparaitre dans la barre qui va bien.
  • Un Panel va nous offrir la possibilité d'afficher un menu et d'interagir avec lui grâce à du Html et du Javascript.
Derrière la scène :
  • tabs afin d'accéder aux informations de l'onglet en cours de visualisation (et aussi d'en ouvrir de nouveaux)
  • request, un bon point d'accès vers l'extérieur, en asynchrone (ou pas)
  • self pour accéder aux fichiers locaux (limité au scope de l'extension)
  • Et simplestorage pour sauvegarder des valeurs dans le profil utilisateur
  • Pour finir, les amateurs de Firebug reconnaîtrons l'objet console, sans qui nous ne pourrions pas loguer
Je vous laisse aller découvrir les autres APIs disponibles, le choix est assez complet, et le travail de Mozilla n'est pas encore terminé ! Pour utiliser un de ces objet, une de ces API, rien de plus simple. CommonJS stipule que l'on peut "appeler" une fonction d'une autre librairie en utilisant require.
var widgets = require("widget");
Hop ! On a accès à toutes les propriétés, méthodes, etc... de l'objet widget tel que décris dans la documentation. Et si vous souhaitez faire la même chose avec votre code, créer une librairie, séparer vos différents composants, c'est facile avec exports ! Par exemple, un fichier lib/mon-api.js qui contiendrait une fonction whatIsYourVersion() :
exports.whatIsYourVersion = whatIsYourVersion; ou juste exports.whatIsYourVersion = function() {return "1.0";};
Par défaut, Firefox charge le fichier lib/main.js de l'application. Enfin plus exactement, il fait un appel implicite à la méthode main de votre module. Vous pouvez d'ailleurs passer de cette manière des options de chargement :
exports.main = function(options) {/*foobar*/};
Pour la suite, le code source de l'application étant libre, je vous invite à jeter un œil : http://code.google.com/p/rsstodolist/source/browse/trunk/firefox-sdk-addon/rsstodolist/lib/main.js

Workers roxx !

Une des parties les plus intéressantes dans les choix technologiques de Mozilla est l'usage intensif du mécanisme de Web Workers. Pour plusieurs APIs, dont Panel (je vais citer également page-mod qui permet de modifier la page en cours et page-worker qui autorise du traitement sur une page en tâche de fond) la communication entre une page (qui se retrouve, pour le coup, dans un thread séparé) et l'Addon se fait par workers et donc, par un système de messages (à l'image des Actors de Scala). Pour afficher le menu de mon application tel qu'on le voit sur le screenshot, je donne à mon objet Panel une simple page HTML à manger et une liste de scripts Javascript à charger avec. Pour ceux qui sont allés voir le liens vers le code source, on peux voir que je charge carrément jQuery ! Personnellement ça me suffit pour être comblé. Je peux donc développer une extension comme n'importe quelle application Web avec la puissance d'APIs plus proches du système. Je vais parler sans savoir mais je crois que Chrome a fait un pas supplémentaire en avant et l'addon est littéralement la page Web. En comparaison, j'aime beaucoup l'approche de Mozilla qui semble un peu plus hybride entre un client léger et un client lourd. Je pense qu'à terme cela permettra une plus grande liberté, même si pour des applications simples il faut faire preuve d'un peu de talent en jonglerie. Je résume un peu, le contenu de mon menu est une page html et je peux coder avec jQuery dedans... super ! Mais comment je lui envoi des informations venant de mon addon et surtout, comment mon addon récupère les informations saisies dans le formulaire ? Avec de simples events. Comme je peux avoir des onClick, onMouseOver, etc... On va avoir un onMessage (d'un côté comme de l'autre) que l'on pourra appeler par la fonction postMessage (d'un côté comme de l'autre). Le tout de manière asynchrone. Exemple :
Point de vu de l'Addon : this.panel.postMessage({description: title, feed: feed}); Point de vu de la page : onMessage = function onMessage(infos) { if(infos && infos.description) $("#description").val(infos.description); if(infos && infos.feed) $("#feed").val(infos.feed); };
Et la communication inverse :
Point de vu de la page : postMessage("ready"); Point de vu de l'Addon : onMessage: function(message) { if(message == 'ready') { transmitInfos(); } else { doAction(message); } }
On peux presque dire que l'on a fini là ! Un dernier mot peut être sur les autres APIs utilisées dans ce code :
  • Request, utilise normalement l'objet XHR standard de Javascript et permet donc de faire des appels comme de l'Ajax. Parfait pour des APIs REST. Bonne nouvelle en plus, la limite de cross domain que l'on retrouve dans une application web ne s'applique pas ici. Inutile de passer par du JSonP.
  • Simplestorage permet de stocker n'importe quelle valeur, même du JSon un peu complexe. Et ça s'utilise assez facilement, comme n'importe quelle variable en fait : simpleStorage.storage.feed = "Aurélien". C'est sandboxé à votre application. Petite subtilité, ce sera à vous de gérer le cas du mode "Navigation privée"
  • Les tests. On en parle pas assez. Un objet test permet d'effectuer des assertions de base comme on en trouve un peu partout.

Y'a pas de Mozilla Store?

Pour acheter des t-shirts surement. Mais pour déposer des applications il s'agirait plutôt d'une plateforme commune aux développeurs. Une fois votre binaire généré (cfx xpi !), et votre compte Mozilla crée, il faut suivre un petit questionnaire sur le site, uploader le tout et voilà. Les questions sont utilitaires, de quoi décrire son extension, déclarer les développeurs, les auteurs, la version, etc... Petit point sur lequel je n'ai pas trop d'infos par contre : Il faut faire valider son application par la fondation Mozilla. Sont-ce des robots ou des gens? Il semblerait qu'un délais de 10 jours soit nécessaire pour valider un addon destiné à être "stable" (puis 5 jours pour les versions supérieures) ou 5 jours pour un addon expérimental. Il semble ne s'agir que de validation de sécurité car il est possible de créer des Addons bas niveaux, qui peuvent toucher profondément au chrome du navigateur. En tout cas, une fois le questionnaire remplis, Mozilla affiche une jolie page en votre honneur : https://addons.mozilla.org/fr/firefox/addon/rss-todolist-addon/

Conclusion

Et bien, et bien. Cet article est un peu long et j'aurais probablement pu détailler bien plus encore ! Mais j'espère au moins vous avoir redonné envie de tester feu Jetpack. Regarder les sources d'Rss Todolist ou d'autres exemples qui fourmilles sur Internet ou demandez moi en commentaire ! Cet SDK est réellement un outil puissant et les technologies utilisées sont de premier choix, probablement ce que l'on aura partout demain dans nos développements. Seul petit bémol : débuguer  est un véritable cauchemar... Je n'ai pour l'instant (mais je suis preneur) par trouvé de Firebug like permettant de tracer son code en mode test/run et c'est plutôt dommage...