Guide
du lecteur

Utiliser jQuery avec Node.js sous Windows

par
le à 10h43

Utiliser jQuery pour du développement côté serveur serait vraiment formidable ! C'est possible avec Node.js. Nous y sommes enfin, l'une des parties très intéressante qui peut justifier l'utilisation de Node.js à la place de vos développements PHP et Cie. C'est le moment de travailler de la même façon côté client et côté serveur sur vos processus de contrôle (vos Contrôleurs en MVC) et donc de développer vos sites avec un unique langage de programmation : JavaScript. Cependant, sous Windows, il y a une petite difficulté en plus liée aux modules développés en code natif que nous allons surmonter ! C'est parti pour manipuler le DOM côté Back-end !

À la découverte de Node.js sous Windows

À propos du module node-jquery

L'utilisation du module Node.js node-jquery permet de manipuler des objets jQuery dans du code JavaScript développé pour être interprété côté serveur par le moteur JavaScript V8 (l'interpréteur JavaScript socle de Node.js). node-jquery est lui-même le socle de base permettant cette utilisation de l'autre côté et comme son développeur le dit « n'est simplement que ça ».

Initialement développé par coolaj86 —le développeur qui a également développé le module node-walk utilisé dans mon précédent billet)— node-jquery va être dès à présent maintenu par la Team jQuery elle-même, ce qui assure un suivi et une utilisabilité solide de cette approche comme méthode de développement dans le futur.

Note : il est donc possible que dans un futur proche se soit un autre plugin que node-jquery qu'il faille installer pour utiliser jQuery côté serveur, car node-jquery n'est pas le seul module permettant d'utiliser jQuery côté serveur. Cependant, l'utilisation de jQuery en elle-même restera identique et équivalente à celle du côté client.

Ce que nous dit la documentation node-jquery...

Comme toujours, rendez-vous sur le registre des modules Node.js pour chercher node-jquery et ainsi atteindre la page de projet et de documentation.

On y apprend que :

  • pour installer le module jQuery : on utilise npm install jquery (et pas npm install jQuery) et
  • pour manipuler l'objet jQuery : on déclare var $ = require('jquery').create(); et manipule donc $.

Note : vous constaterez qu'il y a plusieurs projets de socle jQuery en place pour utiliser la librairie jQuery côté serveur si vous fouillez le registre NPM. Libre à-vous d'en choisir une autre. Il faut cependant prendre en compte le support du module dans le temps.

...mais ce qu'elle ne nous dit pas

Malheureusement, que vous exécutiez votre fichier avec la ligne require('jquery').create() avant ou après installation du module node-jquery, si vous êtes sous Windows, vous aurez toujours la même erreur : « Cannot find module 'jquery' ». Nous allons arranger cela plus loin (bon, en fait la doc mentionnait le problème sous Windows, mais j'aimais bien mes titres !).

Sous Windows, jQuery ne marche pas (même après installation)
Sous Windows, jQuery ne marche pas (même après installation)

jQuery ne marche pas avec Node.js sous Windows

Et oui ! Nous avons mis le doigt sur un problème que rencontre tous les débutants Node.js qui commence à jouer avec les modules NPM sous Windows. Effectivement, dans mon deuxième billet, j'ai passé sous silence les pré-requis qui nous auraient éviter ce souci pour entrer dans le vif du sujet. Maintenant, il est l'heure d'installer un environnement de développement Node.js plus complet pour résoudre ce problème.

Si vous ne possédez pas sur votre machine Python, Microsoft Visual Studio et quelques autres dépendances, en tapant npm install jquery dans votre console vous allez obtenir une erreur :

Sans Python et Microsoft Visual Studio : jQuery ne marche pas
Sans Python et Microsoft Visual Studio : jQuery ne marche pas

En fouillant dans le répertoire node_modules le dossier jquery est pourtant bien là ! Alors pourquoi ça ne marche pas ! La réponse se trouve dans les logs des erreurs disponibles dans votre console ou, comme indiqué, dans le fichier npm.debug.log :

Error: Can't find Python executable "python", you can set the PYTHON env variable.

et

contextify@0.1.5 install: `node-gyp rebuild`
error `cmd "/c" "node-gyp rebuild"` failed with 1
error Failed at the contextify@0.1.5 install script.
error This is most likely a problem with the contextify package,
error not with npm itself.
error Tell the author that this fails on your system:
error node-gyp rebuild
error You can get their info via:
error npm owner ls contextify
error There is likely additional logging output above.

Résolevons ce problème !

Python et Microsoft Visual Studio comme pré-requis Node.js sous Windows

En réalité si jQuery ne fonctionne pas, c'est parce que l'un des modules Node.js dont il est dépendant n'est pas un module écrits en JavaScript mais un module écrits en code natif, le module contextify, qui requiert donc d'être compilé sur la machine où il est utilisé pour fonctionner.

C'est le module node-gyp qui s'occupe de compiler les modules Node.js développés en language natif (autre qu'en JavaScript) et pour faire son travail il a besoin des logiciels Windows Python ainsi que Microsoft Visual Studio (ou Microsoft Visual C++).

Nous ne le verrons pas dans ce billet, mais sachez qu'il est également possible de se procurer les sources compilés de contextify pour votre machine et ne pas avoir à installer Python et Microsoft Visual Studio. Cependant, puisque le cas de figure se représentera assez souvent (avec d'autres modules natifs), je vous conseille de le faire.

Installation de Python 2.7.x pour Windows

Pour commencer nous allons installer le logiciel Python sur votre machine Windows. Bien que celui-ci existe en version 3.x.x il faut installer une version 2.7.x pour que cela fonctionne.

A ce stade, en ré-essayant la commande npm install jquery l'erreur précédente est passée et la nouvelle erreur est :

MSBUILD : error MSB3428: Impossible de charger le composant Visual C++ "VCBuild.exe" (MSBUILD : error MSB3428: Could not load the Visual C++ component "VCBuild.exe").

Installation de Microsoft Visual C++ pour Node.js

Pour vous procurer le « VCBuild.exe » dont il est question : installez le logiciel Microsoft Visual Studio 2010 (ou 2012). Vous pouvez vous contenter uniquement de la branche C++ du logiciel (Microsoft Visual C++) et vous contenter même de sa version Express (gratuite et moins lourde).

  • Rendez-vous donc sur le site de Microsoft et téléchargez Microsoft Visual C++ 2010 Express par exemple.
  • Ouvrez l'installeur « vc_web.exe » et suivez les « Next ». Vous n'êtes pas obligé de sélectionner les produits optionnels. Cliquez enfin sur « Install » et les fichiers sont téléchargés pour installation et installés.

En ré-essayant de nouveau la commande npm install jquery vous obtenez à présent l'erreur :

error MSB8007: The Plateform for project 'contextify.vcxproj' is invalid.

Microsoft Windows SDK for Windows 7 and .NET Framework 4

Pour corriger l'erreur précédente :

En cas de problème :

En cas de problème avec Microsoft Windows SDK for Windows 7 and .NET Framework 4
En cas de problème avec Microsoft Windows SDK for Windows 7 and .NET Framework 4
  • Désinstallez les Microsoft Visual C++ 2010 Redistributable x86 et x64 déjà installées (Menu Windows puis Panneau de congiguration puis Désinstaller un programmes). Ré-essayez.
  • Vous pouvez en plus télécharger directement l'ISO du SDK (« GRMSDK_EN_DVD.iso » pour x86 et « GRMSDKX_EN_DVD.iso » pour x64), gravez ou dézippez l'ISO et exécutez « setup.exe ».

En ré-essayant de nouveau la commande npm install jquery vous obtenez à présent le message d'avertissement (en jaune) :

warning C4530: C++ exception handler used, but unwind semantics are not enabled.

Si c'est le cas c'est que tout s'est bien passé.

Visual C++ 2010 SP1 Redistributable Package

Pour (re)mettre les versions Microsoft Visual C++ 2010 Redistributable :

Microsoft Visual C++ 2010 Service Pack 1 Compiler Update for the Windows SDK 7.1

Pour vous assurer de posséder tout ce qu'il faut pour ne rencontrer aucun problème à l'avenir :

Développer côté serveur avec jQuery

Maintenant que les pré-requis sont en place vous ne devriez plus avoir de problème pour compiler les modules Node.js en langage natif. À présent :

  • si ce n'est pas déjà fait : installez le module jQuery (node-jquery) avec la commande npm install jquery depuis le répertoire de votre projet (pour moi C:\nodejs\website\),
  • et installez jsdom depuis le même répertoire avec la commande npm install jsdom.

En reprenant le fichier website.js de mon billet précédent ; voici comment inclure jsdom et jQuery :

var
/*== Charger les modules Node.js ==*/
	http = require("http"),
	express =  require("express"),
	httpServer = express(),
	
	jsdom = require("jsdom").jsdom, // Utilisation d'un créateur de DOM.
	jquery = require('jquery'), // Utilisation de jQuery côté serveur.
	
/* ... */

Créer le DOM côté serveur avec jsdom

Reprenons l'exemple de la page d'accueil du site qui se présentait ainsi dans mon mon billet précédent :

/* ... */

/* Accueil */
httpServer.get(appConfig.path, function (request, response) {
	var
		header = {
			"Content-Type": "text/html",
			"Charset": "utf-8"
		},
		template = '<!DOCTYPE html>' +
			'<html lang="fr">' +
				'<head>' +
					'<meta charset="utf-8" />' +
					'<title>Ma première page</title>' +
					'<base href="//' + appConfig.url + '" />' +
				'</head>' +
				'<body>' +
					"<p><a href='./connexion/' title='Page de connexion'>Page de connexion</a></p>"
				'</body>' +
			'</html>';

	response.writeHead(200, header);
	response.write(template);
	response.end();
});

/* ... */

Effectuons plusieurs changements pour nous amuser avec jQuery.

  • Tout d'abord, ligne 8, nous avions créé une variable template représentant le contenu de la page qui allait être fourni au client (le navigateur du visiteur réclamant la page).
  • Nous allons dans un premier temps transformer cette variable de type String en un véritable document DOM côté serveur avec jsdom,
  • et ensuite l'englober dans une window (fenêtre) émulée de 1024px par défaut.
  • Pour finir nous allons restituer ce DOM sous forme de string pour l'envoyer au client comme précédemment à la ligne 21.
/* ... */

/* Accueil */
httpServer.get(appConfig.path, function (request, response) {
	var
		header = {
			"Content-Type": "text/html",
			"Charset": "utf-8"
		},
		
		// L'ancienne variable "template" de type String est remplacée
		// par la variable "document" de type Object représentant le DOM de la page.
		document = jsdom("<!DOCTYPE html>" +
			"<html lang='fr'>" +
				"<head>" +
					"<meta charset='utf-8' />" +
					"<title>Ma première page</title>" +
					"<base href='//" + appConfig.url + "' />" +
				"</head>" +
				"<body>" +
					"<p><a href='./connexion/' title='Page de connexion'>Page de connexion</a></p>"
				"</body>" +
			"</html>"),
			
		// Un objet "window" est créé. 
		// C'est l'émulation d'une fenêtre côté serveur qui a pour taille 1024px de large.		
		window = document.createWindow();

		// console.log(typeof document); // renvoi "object".
		// console.log(window.innerWidth); // renvoi "1024"
		
	response.writeHead(200, header);
	
	// On change la variable template par le rendu sous forme de string document (ou window.document).
	response.write(window.document.innerHTML);
	response.end();
});

/* ... */

Manipuler le DOM côté serveur avec jQuery

Nous allons dans un exemple tout simple ajouter une balise h1 à notre DOM après la création de celui-ci avec jQuery. Nous allons même effectuer un test pour démontrer comment le DOM peut être variable en fonction de conditions précises.

/* ... */

/* Accueil */
httpServer.get(appConfig.path, function (request, response) {
	var
		header = {
			"Content-Type": "text/html",
			"Charset": "utf-8"
		},

		document = jsdom("<!DOCTYPE html>" +
			"<html lang='fr'>" +
				"<head>" +
					"<meta charset='utf-8' />" +
					"<title>Ma première page</title>" +
					"<base href='//" + appConfig.url + "' />" +
				"</head>" +
				"<body>" +
					"<p><a href='./connexion/' title='Page de connexion'>Page de connexion</a></p>"
				"</body>" +
			"</html>"),	
		window = document.createWindow(),
		
		// Permettre à jQuery de manipuler le DOM...
		jQuery = jquery.create(window), // ...et au développeur de le manipuler via jQuery("selecteur")...
		$ = jQuery, // ...ou via $("selecteur").
		
	// On crée un nœud "h1" contenant le texte "Ceci est le titre d'origine !".
	h1Title = $("<h1>").text("Ceci est le titre d'origine !");
	// On l'ajoute au DOM serveur.
	$("body").prepend(h1Title);
	
	// Si la condition est réalisée...
	if (1 == 1) { // ...ce qui est le cas ; renvoi "true"...
		h1Title = $("h1").text("Ceci est le titre changé !"); // ... alors on cible le nœud h1 et on modifie le texte avec "Ceci est le titre changé !".
	}
		
	response.writeHead(200, header);
	response.write(window.document.innerHTML);
	response.end();
});

/* ... */
Résultat de notre page d'accueil côté client
Résultat de notre page d'accueil côté client

Exemple de rendu conditionnel après un POST avec jQuery

Tournons nous à présent vers la seconde page de mon fichier website.js précédent : la page de connexion. Ajoutons lui quelques styles et prévoyons son rendu en cas d'erreur de connexion ou de réussite de l'utilisateur.

/* ... */

/* Connexion */
function connectionRender(request, response) {
 	var
		header = {
			"Content-Type": "text/html",
			"Charset": "utf-8"
		},
		// LE CONTENU COMPLET DE "document" SE TROUVE PLUS BAS.
		document = jsdom("<!DOCTYPE html ><html>..."),
		window = document.createWindow(),
		jQuery = jquery.create(window),
		$ = jQuery;
		
		// Par défaut, on retire l'affichage après connexion puisqu'on vient d'arriver.
		// On modifiera cette partie de code plus loin.
		$("#logged").remove();

	response.writeHead(200, header);
	response.write(window.document.innerHTML);
	response.end();	
}
httpServer.get(appConfig.path + "connexion", function (request, response) {
    connectionRender(request, response);
}).post(appConfig.path + "connexion", function (request, response) {
    connectionRender(request, response);
});

/* ... */

Contenu complet de document = jsdom("<!DOCTYPE html><html>...") :

<!DOCTYPE html> 
	<html> 
		<head> 
			<meta charset="utf-8" /> 
			<title>Page de connexion</title> 
			"<base href=//"  appConfig.url  " />" 

			
			<style text="text/css"> 
				.error { 
					display: none;
				} 
				.error.show {
					display: block;
				}
				.error span { 
					display: none;
					color: #ff0000;
				} 
				.error span.show {
					display: block;
				}
			</style> 

		</head> 
		<body> 
			<form id="login" action="./connexion/" method="POST"> 
				<div class="field-login-email"> 
					<label for="login-email" placeholser="Email">Email : </label>
					
					<input id="login-email" type="text" name="login[email]" /> 

					
					
					<div class="error"> 
						<span class="empty">Le champ email est vide.</span> 
						<span class="invalide">Le champ email est invalide.</span> 
					</div> 

				</div> 

				<div class="field-login-password"> 
					<label for="login-password" placeholser="Mot de passe">Mot de passe : </label>
					
					<input id="login-password" type="password" name="login[password]" /> 

					
					
					<div class="error"> 
						<span class="empty">Le champ mot de passe est vide.</span> 
						<span class="invalide">Le couple Email/Mot de passe est incorrecte !</span> 
					</div> 

				</div> 

				<label><input type="submit" value="Ok" /></label> 
			</form> 

			
			<div id="logged">Vous êtes passé !</div> 
		</body> 
	</html>

Ce qui donne comme rendu :

Résultat de notre page identique, car ajout masqué en CSS ou retiré côté serveur
Résultat de notre page identique, car ajout masqué en CSS ou retiré côté serveur

Gérer les erreurs

Quand la page de connexion est demandée suite au clique sur le bouton « Ok » c'est une requête POST qui est envoyée et le résultat est traité par le code ligne 27 de notre exemple JavaScript plus haut. À cette ligne, la fonction connectionRender est appelée tout comme en GET à la différence prêt que des variables POST existent dans le cas de figure POST (ce qui n'est pas le cas en GET).

Nous allons donc tester l'existence et le contenu des variables POST du formulaire pour décider de la réponse adaptée à notre visiteur.

Tout d'abord, permettons à Express de récupérer les valeurs des champs de formulaire via l'attribut name. Pour cela il faut lui « demander » d'utiliser l'intergiciel bodyParser.

/* ... */

httpServer
/* == Définir un environnement d'exécution : SET NODE_ENV=dev ==*/
	.configure(function () {
		/* Commun à tous les environnements */
		
		// Ajout du middleware "bodyParser" pour parser les attributs name
		// et les récupérer via request.body.
		httpServer.use(express.bodyParser());
	})
/* ... */

Ensuite mettons en place le mécanisme de réception uniquement en POST.

/* ... */

/* Connexion */
function connectionRender(request, response) {
 	var
		header = {
			"Content-Type": "text/html",
			"Charset": "utf-8"
		},
		document = jsdom("<!DOCTYPE html ><html>..."),
		window = document.createWindow(),
		jQuery = jquery.create(window),
		$ = jQuery;

		// Si on passe par ici après une réclamation en POST, on entre.
		if (request.method == 'POST') {
			var
				// Par défaut, on estime que la validation du formulaire est bonne.
				isValid = true,
				// Normalement, cet info se récupère dans une base de donnée. C'est un des utilisateurs valide.
				passEmail = "tout@est.ok",
				// Et ça c'est le mot de passe associé à l'utilisateur.
				passPassword = "azerty",
				// Une regex pour vérifier la validité des emails.
				checkEmail = /^[-._a-z0-9]+@[-._a-z0-9]+\.[.a-z]{2,4}$/i;

			// Quoi qu'il arrive on réinjecte la valeur email (mais pas mot de passe).
			$("#login-email").val(request.body.login.email.trim());
	
			// Le champ email est-il remplit ?
			if (request.body.login.email.trim() == "") {
				// S'il est vide, on le signale.
				$(".field-login-email .error").addClass("show");
				$(".field-login-email .error .empty").addClass("show");
				// Et on ne valide pas le formulaire.
				isValid = false;

			// Le champ email est-il valide ?
			} else if (!checkEmail.test(request.body.login.email.trim())) {
				// S'il est anormal, on le signale.
				$(".field-login-email .error").addClass("show");
				$(".field-login-email .error .invalide").addClass("show");

				// Et on ne valide pas le formulaire.
				isValid = false;
			}

			// Le champ mot de passe est-il remplit ?
			if (request.body.login.password.trim() == "") {
				// S'il est vide, on le signale.
				$(".field-login-password .error").addClass("show");
				$(".field-login-password .error .empty").addClass("show");
				// Et on ne valide pas le formulaire.
				isValid = false;
			}

			if (isValid) {
				// Y a-t-il une concordance email / mot de passe.
				if (
					request.body.login.email.trim() == passEmail &&
					request.body.login.password.trim() == passPassword
				) {

					/////////////////
					// C'est ici qu'on va mettre en place un mécanisme de remplissage de session.
					/////////////////

				} else {
					// S'il y a une erreur, on le signale.
					$(".field-login-password .error").addClass("show");
					$(".field-login-password .error .invalide").addClass("show");
				}
			}
		}

		// Nous modifierons cette partie dans la partie suivante.
		$("#logged").remove();		

	response.writeHead(200, header);
	response.write(window.document.innerHTML);
	response.end();	
}
httpServer.get(appConfig.path + "connexion", function (request, response) {
    connectionRender(request, response);
}).post(appConfig.path + "connexion", function (request, response) {
    connectionRender(request, response);
});

/* ... */

Tout manquement au formulaire sera à présent signalé.

En cas d'erreur du formulaire on affiche les messages cachés
En cas d'erreur du formulaire on affiche les messages cachés

Gérer la réussite

Permettons également de conserver dans une variable de session des informations qui suivront l'utilisateur de page en page (un équivalent de $_SESSION en PHP par exemple) avec les intergiciels cookieParser et session de Express. Pour cela il va falloir allouer de la mémoire au cookie pour l'entregistrement avec express.session.MemoryStore.

On récupère l'objet MemoryStore

/* ... */

	http = require("http"),
	express =  require("express"),
	httpServer = express(),

	// Ajout de l'objet MemoryStore pour donner du volume au cookie de session.
	MemoryStore = express.session.MemoryStore,

	jsdom = require("jsdom").jsdom, 
	jquery = require('jquery'),
	
/* ... */

On permet les sessions avec cookieParser et session

/* ... */

httpServer
/* == Définir un environnement d'exécution : SET NODE_ENV=dev ==*/
	.configure(function () {
		/* Commun à tous les environnements */
		httpServer.use(express.bodyParser());
		
		/* Permettre de manipuler les sessions */
	    httpServer.use(express.cookieParser());
		/* Paramétrage des sessions */
	    httpServer.use(express.session({
        	store: new MemoryStore(), // Allocation de place.
        	secret: 'secret', // Secret connu du serveur rendant le cookie illisible pour le client.
        	key: 'website.sid' // Nom du cookie.
	    }));
	})
/* ... */

Ensuite terminons de mettre en place le mécanisme de réception.

/* ... */

			if (isValid) {
				if (
					request.body.login.email.trim() == passEmail &&
					request.body.login.password.trim() == passPassword
				) {
				
					// En passant ici on initialise l'état d'utilisateur identifié.
					request.session.user = request.session.user || {}; // Création ou conservation de l'objet arbitrairement nommé "user" s'il n'existe pas.
					
					// Passage à true de la propriété arbitrairement nommé "isLogged".
					request.session.user.isLogged = true;

				} else {
					$(".field-login-password .error").addClass("show");
					$(".field-login-password .error .invalide").addClass("show");
				}
			}
		}

		// Changement de la partie du rendu affiché en fonction d'un état connecté ou non connecté.
		// S'il y a un objet user avec la propriété isLogged à true.
		if (request.session.user && request.session.user.isLogged) {
			// On retire la partie hors-connexion.
			$("#login").remove();
		} else {
			// On retire la partie connexion.
			$("#logged").remove();
		}	

	response.writeHead(200, header);
	response.write(window.document.innerHTML);
	response.end();
	
/* ... */

À présent en tapant respectivement dans les champs « Email » et « Mot de passe » : "tout@est.ok" et "azerty" la page s'affichera en "mode connecté", même après rechargement de la page. Seul la fermeture du navigateur détruira le lien entre le client et la session car le cookie est par défaut paramétré pour expirer à la fin de la sesion. On affichera donc alors la partie "non connecté".

Si tout est okay, on est loggué.
Si tout est okay, on est loggué.

Réflexion sur l'utilisation de jQuery côté serveur

Séparation de la vue et du contrôleur

C'est probablement le plus gros avantage d'utiliser jQuery côté serveur. Il permet ainsi d'avoir un template à plat dont on n'a pas à se soucier et un intégrateur ne connaissant rien en programmation (ça existe ?) pourrait créer des designs sans problèmes.

Ne pas faire du Responsive Web Design côté serveur

Même si l'on simule une fenêtre côté serveur, il ne sert à rien de gérer de la responsivité en essayant d'obtenir la taille de la fenêtre puisque celle qui nous intéresse est celle du client et non celle du serveur émulée. D'ailleurs les fonctions se rapportant à l'affichage ne fonctionnent pas toutes, car côté serveur, le navigateur n'est pas là pour vous répondre (ainsi show() et hide() ne marcheront pas par exemple).

Performance ?

La question. Il est sûr que passer par jQuery est plus lent à l'exécution que de simplement scinder le template en dix parties et de le remplir de conditions. Cependant, à la maintenance c'est un gain de temps complètement multiplié ! Entre payer des ressources qui développeront, débogueront et maintiendront en plus de temps et payer un serveur plus puissant : voyez où sont vos économies ! De plus, nous verrons plus loin que nous pourrons limiter jQuery à des cas précis et se servir d'un moteur de template (ce qui séparera « presque » la vue du contrôleur mais qui sera bien plus lisible que la méthode « v'l'a que je te fou tout au même endroit »).

Je n'ai pas assez de retour d'expérience sur la rapidité en production avec énormément d'utilisateur simultané. Si vous en avez, n'hésitez pas à la partager.

Source

Notre fichier commence à être bien remplis. Dans un prochain billet Node.js nous allons voir comment scinder notre code qui commence à être bien long dans plusieurs fichiers.

En attendant, vous pouvez télécharger le fichier résultat de cet article ici.

3 Commentaires

Choisir un Avatar depuis une url

Adresse : (64px x 64px)
L'url de votre image est incorrecte !

ou Changer la couleur de fond

Nouvelle couleur !

et Choisir un Avatar dans la liste

ChangerFermer
Je crois que vous avez oublié votre commentaire !
Votre email est bizarre !
L'url de votre site doit ressembler à ça : http(s)://(www.)votresite.ici !
Vous ne pouvez pas laisser d'email en restant Anonyme !
Vous ne pouvez pas laisser de site web sans votre email !

Votre commentaire a été ajouter ci-dessous ! Si vous désirez le supprimer ultérieurement, servez vous du code suivant :

Les commentaires sont actuellement affiché du plus rescent au plus ancien. Vous pouvez inverser l'ordre en cliquant ci-dessous :

  • Du plus rescent au plus ancien
  • Du plus ancien au plus rescent
114
Supprimer
Votre commentaire a été supprimé.
le à 13h50

C’était facile pour moi d’assimiler ce tutoriel car j’ai déjà bénéficié des tutoriels en vidéo pour savoir comment utiliser JQuery sur http://www.alphorm.com/tutoriel/formation-en-ligne-jquery. Merci pour ce partage.

Je trouve ce commentaire pertinent ?

Mauvais code de suppression
113
Supprimer
Votre commentaire a été supprimé.
le à 13h50

C’était facile pour moi d’assimiler ce tutoriel car j’ai déjà bénéficié des tutoriels en vidéo pour savoir comment utiliser JQuery sur http://www.alphorm.com/tutoriel/formation-en-ligne-jquery. Merci pour ce partage.

Je trouve ce commentaire pertinent ?

Mauvais code de suppression
112
Supprimer
Votre commentaire a été supprimé.
le à 12h44

Merci pour cet article

Je trouve ce commentaire pertinent ?

Mauvais code de suppression
Supprimer
Votre commentaire a été supprimé.
A l'instant

Je trouve ce commentaire pertinent ?

Vous avez aimé cette article ? Commentez le ou .

A propos de l'auteur

Bonjour, je suis Bruno Lesieur, architecte web basé sur Annecy. Intégrateur HTML5, CSS3 et JavaScript ou encore développeur Front-End ; appelez moi comme vous le voulez mais sachez que je suis très friand de performance web, de Responsive Web Design, d'accessibilité web, de bonnes pratiques, de techniques et d'outils de gestion web, de factorisation et d'automatisation, de partage et casse-tête en tout genre ainsi que de boissons gazeuses.
Article Commentaires Avis 3
utiliser-jquery-avec-nodejs-sous-windows

Quelques #IDet beaucoup de .CLASS

Année
Mois
https://blog.haeresis.fr default fr FR Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre