Archives pour la catégorie JavaScript

Présentation de Grunt au LyonJS par @mklabs

Grunt est un nouvel outil d’automatisation de build basé sur node.js, principalement pour le développement front-end. J’ai eu l’occasion d’en voir la présentation lors d’un LyonJS et j’ai appris pas mal de choses donc peut-être que vous aussi :).

Automating Website Optimizations

Voici les slides de @mklabs (appuyer sur -> pour faire défiler):

http://mklabs.github.com/slides/automating-website-optimization/

Au programme:

  • Une petite compilation des meilleurs outils d’automatisation / build existants (Ant, Cake, Rake, …)
  • Optimisation de sites web (cache busting, images en CSS en base64, compilation conditionnelle, …)
  • Introduction à Grunt
  • Création de plug-ins pour Grunt pour personnalisation de l’automatisation ou pour faciliter la création de batchs

Utiliser XPath sur un navigateur Android 2.x

Voici un article qui ne va pas servir à grand monde mais je l’écris pendant que c’est encore chaud. Il existe plusieurs manières de traverser un DOM, que ce soit un DOM HTML ou un DOM XML (puisque bon, du HTML reste du XML).  Vous pouvez utiliser jQuery pour vous faciliter la tâche avec la méthode $.find(query) qui va vous permettre d’atteindre facilement un élément:

var $xml = $(xml); // ici xml = un objet Document
var subNode = $xml.find("SubNode")[0];

Facile :). Mais vous n’utilisez pas forcement jQuery, ou vous n’avez pas envie de l’intégrer à votre page pour X raisons. Dans ce cas-là, vous pouvez toujours utiliser l’API « à l’ancienne » qui est l’API XPath:

http://www.w3schools.com/xpath/

De la même manière, vous allez prendre un noeud XML, lui passer une query au format XPath et vous allez récupérer un noeud XML ou un ensemble de noeud. Comme d’habitude, c’est standard mais tout le monde ne l’a pas implémenté ou pas implémenté de la même manière  ou implémenté avec les pieds.

Si vous utilisez la Google Closure Library (comme moi), vous avez accès à une API qui va se charger de faire les abstractions nécessaires: goog.dom.xml:

http://closure-library.googlecode.com/svn/docs/closure_goog_dom_xml.js.html

Vous avez donc des méthodes comme « goog.dom.xml.selectSingleNode » qui font:

/**
 * Selects a single node using an Xpath expression and a root node
 * @param {Node} node The root node.
 * @param {string} path Xpath selector.
 * @return {Node} The selected node, or null if no matching node.
 */
goog.dom.xml.selectSingleNode = function(node, path) {
  if (typeof node.selectSingleNode != 'undefined') {
    var doc = goog.dom.getOwnerDocument(node);
    if (typeof doc.setProperty != 'undefined') {
      doc.setProperty('SelectionLanguage', 'XPath');
    }
    return node.selectSingleNode(path);
  } else if (document.implementation.hasFeature('XPath', '3.0')) {
    var doc = goog.dom.getOwnerDocument(node);
    var resolver = doc.createNSResolver(doc.documentElement);
    var result = doc.evaluate(path, node, resolver,
        XPathResult.FIRST_ORDERED_NODE_TYPE, null);
    return result.singleNodeValue;
  }
  return null;
};

Pour reprendre l’exemple de tout à l’heure, cela donne:

var subNode = goog.dom.xml.selectSingleNode(xml, "/SubNode");

Dans la méthode goog.dom.xml.selectSingleNode, le if est le comportement spécial IE et le else pour tous les autres navigateurs. Il y a quand même un test intéressant:

if (document.implementation.hasFeature('XPath', '3.0')

On demande au navigateur de confirmer qu’il gère bien XPath avant de faire toute manipulation.

Quand les navigateurs nous mentent

Tout cela fonctionne très bien, sur IE, de vieux FF, Chrome, Safari, etc. Puis j’ai essayé sur une tablette Android 2.2 (et 2 téléphones en 2.2) et là, rien ne se passe. Comme il n’y a pas de console sur le navigateur Android de base, j’ai débuggé à grands coups de alert(…) à toutes les lignes jusqu’à trouver celle qui bloquait:

var resolver = doc.createNSResolver(doc.documentElement);

Avec un try / catch autour, on m’informe que:

object <Document> has no method 'createNSResolver'

Si vous souhaitez en savoir plus sur ce createNSResolver, voici les specs:

https://developer.mozilla.org/en/Introduction_to_using_XPath_in_JavaScript

Après quelques recherche, j’apprend que malgré le fait que le navigateur renvoie bien « true » au test document.implementation.hasFeature(‘XPath’, ‘3.0’), celui-ci n’a aucune des méthodes nécessaires pour réaliser le parse XPath. Un joli mensonge qui fait perdre du temps.

Apparemment, cela semble corrigé par les implémentations > 2.2 de Android, à vérifier. Toujours est-il qu’il reste pas mal de matos en 2.2 et qu’il me faut une solution

Parsers XPath en JavaScript

Lors de mes recherches, je suis tombé sur ce billet:

https://github.com/levand/domina/issues/12

Exactement le même problème que moi et enfin une solution. J’essaie donc d’ajouter le fichier xpath.js dans mon projet (le nom est prometteur):

https://github.com/levand/domina/blob/1.0.0-beta1/public/xpath.js

Cela ne marche toujours pas. Le script étant uniquement disponible en version minifiée, difficile de déterminer s’il faut utiliser une autre méthode ou quoi.

Je tombe ensuite sur une autre implémentation, par « Llama Internet Laboratory »:

http://llamalab.com/js/xpath/

Le nom ne porte pas beaucoup d’espoir mais j’essaie quand même d’intégrer les 2 fichiers dans mon projet. Et magie, cela fonctionne directement. Ce script est plus malin et remplace directement les méthodes de Document, ce qui me permet de ne pas modifier l’implémentation de Google Closure.

Conclusion

Plusieurs conclusions:

  • L’implémentation de  « Llama Internet Laboratory » et la plus light et permet de ne pas modifier les appels XPath
  • Ne faîtes pas forcement confiance à ce que vous dit le navigateur, il est mieux de tester l’existence de propriétés que d’utiliser les méthodes d’interrogation.
  • Essayez de vous passer de XPath et de parcourir le DOM de manière plus « classique », avec goog.dom.query(…) par exemple

JavaScript – Gestion des Error / Exception de manière globale

En JavaScript, j’en apprend presque tous les jours, il faut dire que je pars de loin :). En ActionScript, il y a un mécanisme permettant de gérer les exceptions « runtime » de manière globale depuis Flash Player 10.1:

Global Error Handling in AIR 2.0 and Flash 10.1

Bien pratique pour éviter les mauvaises surprises, comme des accès à des objets null non vérifiés. Lorsqu’une exception se produit au sein de l’exécution de la VM Flash Player, votre programme devient instable. Il peut continuer à fonctionner, partiellement, ou pas du tout, c’est assez capricieux, il vaut mieux prévenir l’utilisateur qu’une erreur s’est produite.

Pour ce qui est de l’exécution du JavaScript, c’est à peu près pareil, il arrive que l’exécution se stoppe après une exception. En JavaScript, il est possible de gérer les erreurs de 2 manières:

  • avec un try / catch pour les erreurs pour les exceptions lancée à l’aide d’une instruction « throw »
  • un event handler nommé « onerror » sur window

Pour le premier, c’est assez classique en programmation, je vous passe les détails. En revanche, je ne connaissais pas le second.

Exemple d’utilisation de window.onerror

Un petit exemple:

window.onerror = function(errorMeaage, fileName, lineNumber){
    document.write('Error: ' + errorMeaage);
}

On récupère donc le message d’erreur (venant de l’exception), le nom du fichier JS qui a lancé cette erreur et le numéro de ligne.

Attention, selon les navigateurs et leurs versions, il se peut que vous ne récupériez pas toutes ces informations.

Utilisation de Error::stack

Au delà de cela, il existe aussi une autre technique, il existe aussi une manière d’obtenir la stack d’appel, c’est-à-dire l’enchaînement des fonctions qui a mené à cette erreur. C’est souvent l’information qui est la plus pertinente pour la résolution d’un bug. Cette propriété se nommé « stack » et est présente sur les objets de type error. Voici la documentation officielle:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack

Comme vous le voyez, vous pouvez lancer une erreur et récupérer la stack d’appel complète:

function trace() {
            try {
                throw new Error("myError");
            }
            catch(e) {
                alert(e.stack);
            }
        }

Comme vous pouvez le voir dans la table de compatibilité, cette fonction n’est pas disponible dans IE ni dans certains Safari. En plus de cela, les stacks d’erreurs peuvent être assez sombres.

Utilisation de librairies externes: Tracekit et StackTrace

Pour faire ce travail de compatibilité entre les browser qui gèrent certaines propriétés et d’autres qui n’envoient qu’une partie des informations, il vaut mieux faire confiance à une petite librairie qui va faire le boulot à votre place. Il serait dommage d’avoir des exceptions dans le code qui gère les exceptions, non ? :).

Lire la suite

JavaScript – Améliorer la qualité de son code (Linter, IDE, compilateur, tests et build)

Un des comportements les plus ennuyeux de JavaScript est sa gestion des erreurs. A cause de certaines librairies « wrapper » ou même de la nature dynamique du langage, il peut se produire des erreurs dîtes « silencieuses ». Ces dernières ne vont pas produire une exception mais vont simplement stopper l’exécution de la page. Et cela, le plus souvent à cause d’une faute de frappe, d’une ‘,’ qui traîne à la fin d’un bloc JSON ou d’un « ; » oublié. Rageant.

Heureusement, vous avez plusieurs solutions pour vous en sortir.

JSLint & JSHint

JSLint est un outil permettant de vérifier la qualité de votre code (avec un site encore plus moche que celui de Tomcat, belle performance). Comme ils le disent sur la homepage: « JSLint will hurt your feelings. » car les règles de bases sont assez strictes et il est peu probable que n’importe lequel de vos scripts ne passe le test en en sortant vainqueur.

http://www.jslint.com/

Un peu comme pour PMD (Java) ou FlexPMD, vous pouvez altérer les règles de base et enlever celles qui vous paraissent stupides ou trop restrictives pour ne garder que celles qui vous importent. Les outils comme JSLint pourront trouver des « , » qui traînent en fin de bloc par exemple et vous prévenir.

JSHint est un « fork » (dérivé) de JSLint qui lui va vérifier les erreurs potentielles de votre code, comme par exemple une variable déclarée au sein d’un if/else ou des boucles qui ne devraient pas être. Celui-ci a des règles plus « utiles » que JSLint.

http://www.jshint.com/

La correction d’erreurs trouvées par un Linter ou un Hinter est déjà un premier pas pour vous éviter que ces erreurs n’apparaissent. Il existent d’autres Linter que JSLint au passage.

Un bon IDE

Il est toujours mieux de voir les erreurs au moment où on les tape qu’au moment où elles se produisent. Ce n’est pas le cas pour tout le monde mais j’ai du mal à me passer d’un bon IDE pour travailler. Pour l’instant, je suis très content d’IntelliJ IDEA (ou WebStorm), qui fait du bon boulot avec le JavaScript. J’ai essayé rapidement Aptana (basé sur Eclipse) mais il m’a paru plus lent et moins fonctionnel qu’IntelliJ.

Voici quelques exemples d’aide qu’offre IntelliJ.

Auto-complétion sur tous les fichiers du projet

Voilà un truc que je n’ai pas trouvé dans Aptana (en tout cas, ça ne fonctionnait pas directement). Comme JavaScript n’a rien dans le langage pour gérer les dépendances entre les objets JavaScript, il n’est pas possible pour l’IDE de savoir exactement dans quels fichiers aller chercher les éléments nécessaires à l’auto-complétion. IntelliJ va donc scanner tous les fichiers ouverts de votre projet pour vous faire des propositions, pas seulement ce qu’il y a dans le fichier courant:

Comme vous le voyez, ce fichier ne contient aucun code mais IntelliJ va quand même me proposer des constructeurs qui se trouvent dans d’autres fichiers. Il propose en plus ce qui est dans le bon namespace en priorité, pratique.

Détection des méthodes non déclarées

Vous allez donc pouvoir éviter quelques fautes de frappe, par exemple, j’ai oublié un « i » dans cette méthode:

Vous pouvez modifier le niveau d’erreur si vous voulez que cela vous saute plus aux yeux.

Pseudo-typage des variables avec JSDoc

Découvert presque par hasard en annotant mon JavaScript pour le Google Closure Compiler, IntelliJ se sert aussi de la JSDoc pour vous proposer de meilleurs suggestions, ce qui réduit encore la possibilité d’erreur à la frappe:

Ce n’est pas « typé » au sens strict du terme mais cela donne une indication à l’IDE et à un compilateur éventuel. A noter que cela fonctionne sur les propriétés de manières transitive (les propriétés des propriétés des propriétés, …)

Lire la suite