MBDS 2018-2019: Server Side JavaScript, Frameworks JS front-end

De $1

Version de 16:29, 19 Avr 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Introduction

Dans ce cours nous allons voir plusieurs aspects du développement Web Moderne :

  • Frameworks front end VueJS, React, Angular
  • Server Side JavaScript : NodeJS et principaux packages
  • Utilisation de la BD NoSQL MongoDB
  • Utilisation de base de données dans le cloud adaptées aux applis mobiles (syncrhonisées) comme FireBase
  • Hébergement dans le cloud, authentification via des services en ligne comme Oauth2
  • Développement en mode PAAS (Platform As A Service)

A faire : si vous êtes sous windows, installer un bon terminal en ligne de commande comme  http://cmder.net/ ou autre (github bash, etc.) si je vous vois avec une fenêtre DOS basique vous allez m'entendre !

Séance 1 : état des lieux du développement Web, intro à VueJS

DOM or not to DOM ?

Ecriture en live coding d'un gestionnaire de todos :

Nous allons comparer plusieurs versions:

  1. Pur JavaScript + DOM API : http://jsbin.com/gaqugic/edit
     
  2. Avec des librairies comme jQuery et Lodash : http://jsbin.com/posowem/edit?html,js
  3. Avec un framework comme vueJS, ici dans un exemple simple : http://jsbin.com/pigolozuva/1/edit?h...console,output 
  4. Idem mais avec des données distantes obtenues par fetch à partir d'une API REST : http://jsbin.com/dizigehata/1/edit?h...console,output

A propos de REST:

Remarque : on peu faire des requêtes REST avec XhR2fetch API(pour les curieux : quelques mots sur GraphQLet Appolo

On peut aujourd'hui gérer la progression des uploads et downloads avec fetch et l'API des streams (voir https://streams.spec.whatwg.org/demos/)

Suite de l'étude de VueJS

Créer des composants avec VueJS

Reprenez un des derniers exemples faits avec VueJS, ma gestion d'une todo list: http://jsbin.com/pigolozuva/1/edit?h...console,output 

Dans cet exemple, on ne peut pas instancier plusieurs "Vues". Mais on peut associer la VueJS à un "faux" élement custom HTML, comme ici: http://jsbin.com/penadanife/edit?htm...console,output

Exercice à faire: inspirez-vous de cet exemple pour gérer une liste de hobbies, mais avec les contraintes indiquées dans les commentaires HTML de ce squelette d'application: http://jsbin.com/guwetoy/edit?html,js,output

Correction (ne regarder qu'après avoir vraiment essayé, ou vu la correction en live conding) : http://jsbin.com/guwetoy/1/edit

Développer en mode "CLI" avec un environnement de build/testy

Cette fois-ci, pour terminer l'introduction à VueJS, le plus élégant/simple des trois gros frameworks "industriels" modernes (React, VueJS, Angular), nous allons regarder comment on peut développer avec "un environnement de développement", qu'on appelle "CLI" pour "Command Line Environment". 

Les trois frameworks cités, mais aussi Polymer dont on vient de parler, proposent un environnement "CLI".

Travail à faire :

  1. Installer Vue-cli: exécuter "npm install -g vue-cli", si vous êtes sous Linux ou Mac OS, il se peut que vous deviez faire "sudo npm install -g vue-cli" (essayez d'abord sans le sudo).

    Idem, sous windows il se peut que vous deviez avoir ouvert le terminal DOS en mode "administrateur".
     
  2. Créez un répertoire pour le TP
     
  3. Allez dans ce répertoire en mode ligne de commande, depuis votre terminal
     
  4. On va maintenant créer une application VueJS avec le mode "webpack-simple" (cf la page de doc: https://github.com/vuejs/vue-cli), on peut en effet créer plusieurs types de projets avec vue-cli.

    La commande à exécuter est "vue init webpack-simple nom_de_votre_app", je suggère quelques chose comme nom qui ressemble à "my-app-vue-cli1" par exemple. Vous exécuterez donc la commande : "vue init webpack-simple my-app-vue-cli1"

    Vous devrez alors répondre à un petit questionnaire, en général vous faites "enter", répondez "non" si on vous demande d'utiliser "SAAS" (un pré-processeur CSS comme LESS).

    Cela va créer un sous-répertoire my-app-vue-cli qui contiendra tout ce qu'il faut pour démarrer :
    • Une application exemple,
    • un environnement de développement,
    • Des fichiers de configuration pour webpack etc.
       
  5. Allez dans le répertoire de l'application et faites "npm install" pour installer les dépendances (de l'environnement de développement, et du framework)

     
  6. Exécutez l'application de test avec "npm run dev". Si jamais vous avez une page qui affiche "ERR EMPTY RESPONSE", il se peut que vous deviez changer le port du serveur de dev. Allez dans le fichier webpack.config.js et ajoutez une ligne "port:3000" par exemple, dans la config du devserver. 

    Voici ce que j'ai dans ma config:

    devServer: {
        historyApiFallback: true,
        noInfo: true,
        overlay: true,
        port:3000
    },
     
  7. Etudier le code du fichier main.js, index.html et App.vue

  8. Créer un composant User.vue qui affiche le nom d'un utilisateur
    Ici un exemple de code: User.vue

  9. Créer un composant Info.vue qui affiche juste des infos supplémentaires sous forme de <p>, et qui soit LOCAL à User.vue (voir Live Coding)

  10. Ajouter dans App.vue un <p>Ceci est un test<p>. Que fait le CSS de User.vue ? Supprimer l'attribut "scoped" de la balise <style> de User.vue, que se passe-t-il ?
     
  11. En étant sûr d'être dans le répertoire du projet faites "npm install -save vue-router" pour installer le module de routage de vueJS.

  12. Dans main.js ajoutez les lignes relatives au routeur (import, Vue.use, définition des routes, etc.) pour que le fichier ressemble à ceci :
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    import App from './App.vue';
    import User from './components/User.vue';
    import Blog from './components/Blog.vue';
    import Compte from './components/Compte.vue';

    // Définition des routes
    Vue.use(VueRouter);

    const routes = [
        {path:'/blog', component: Blog},
        {path:'/compte', component: Compte},
        {path:'/', component: User},
    ]

    const router = new VueRouter({
        routes: routes,
        mode:'history'
    })
    // La ligne ci-dessous rend le composant User utilisable
    // partout, dans tous les fichiers .vue
    // C'est un GLOBAL COMPONENT
    Vue.component("app-user", User);

    new Vue({
    el: '#app',
    router:router,
    render: h => h(App)
    })
  13. Remplacez le template de App.vue par le code suivant et testez:
<template>
  <div id="app">
    Hello {{msg}}

    <div>
      <router-link to="/">Home</router-link>
      <router-link to="/blog">Blog</router-link>
      <router-link to="/compte">compte</router-link>
    </div>

    <router-view></router-view>

    <app-user></app-user>
      <p>Ceci est un test</p>
  </div>
</template>

Correction de l'exercice: VueJSExoCli.zip, faire "npm install" et "npm run dev" une fois dezippé.

Séance XXX à venir - présentation de NodeJS et premiers exercices simples

Ressource : des MOOCS!

Outils à installer

  • Un bon éditeur de code prêt pour le dev front-end: sublime text 3, visual studio code, atom, etc. Pensez à installer les packages emmet, babel, etc.
  • Si vous êtes sous windows, un bon terminal, acceptant le copier/coller, la colorisation, le multi-onglet ou multi-fenêtre, par exemple http://cmder.net/, powershell (de microsoft, déjà installé sous win10), hyperterminal (payant), console2, powercmd, colorconsole, mobaextrem, terminal wings, conemu, 

TP - routage avec le module ExpressJS, Web Services RESTFUL

Supports de cours: transparents de présentation de Express 

  • TP:
    1.  Récupérez cette archive, dezippez là quelque part, avec la ligne de commande, faites cd dans le répertoire TP_ROUTAGE_EXPRESS_CRUD_AJAX créé, et exécutez la commande "npm install".

      Ceci devrait créer un sous directory node_modules contenant les modules nécessaires (dans notre cas: express et multer).
       
    2. Suivez les consignes du prof et les explications au tableau.
    3. Les bonnes pratiques pour créer une API RESThttps://blog.octo.com/designer-une-api-rest/

    4. FACULTATIF: Avec Multer on peut aussi uploader des fichiers Testez cet exemple qui fait de l'upload de fichiers. Pensez à installer les modules express et multer dans le répertoire avant d'exécuter.

TP - MongoDB

  • Vous allez, dans cette séance apprendre les bases de l'utilisation de MongoDB depuis une application écrite en JavaScript et exécutée avec NodeJS. Dans un second temps, vous ré-utiliserez le code qui fait le CRUD sur une base d'exemples de MongoDB, en le déplaçant dans des méthodes app.get, app.post etc du TP de la séance 3, pour faire une application utilisable depuis des URLs.

1 - Installer MongoDB sur votre machine

Suivez les installations propres à votre système d'exploitation situées sur cette page du site officiel. Ne choisissez pas l'installation manuelle.

Une fois installé lancez la commande "mongod" en ligne de commande. Si le daemon mongoDB ne se lance pas, regardez les erreurs.

Sur mon Mac j'ai fait:

  • brew update
  • brew install mongodb
  • mkdir -p /data/db
  • chmod 777 /data/db (pour autoriser un user lambda à écrire dedans)
  • mongod (pour exécuter MongoDB)

2 - Créer et peupler une collection par défaut (avec un dataset issu du tutorial MongoDB officiel)

  • Récupérez cette base de données de restaurants : le fichier primer-dataset.json (click droit/sauver) et exécuter la commande suivante, qui va créer une bd "test" et ajouter dedans la collection "restaurants" :
    • mongoimport --db test --collection restaurants --drop --file primer-dataset.json
  • Une fois l'importation faite, garder l'onglet ouvert sur cette page, car on va continuer le tutorial à l'étape 5.

3 - Installer un outil d'administration sympa

Je vous recommande fortement MongoChef, un produit commercial mais gratuit pour utilisation non commerciale. Le télécharger sur: https://studio3t.com/

4 - Ouvrir 3T STudio et voir la collection que l'on vient d'importer

  • S'assurer que MongoDB tourne (mongod doit être lancé, ou bien vous devez avoir installé MongoDB en service)
  • Lancer l'application 3T Studio, connectez-vous sur MongoDB. Les valeurs par défaut doivent être Ok, normalement.
  • Ouvrir la collection "restaurants" dans la base "test"

Quelques screenshots:

MongoChef1.jpg

MongoChefRequestBuilder.jpg 

5 - Installer le driver MongoDB pour NodeJS

  • Allez dans le répertoire du TP précédent (routage avec express etc)
     
  • Exécutez npm install -save mongodb
    • Cette dernière commande ne fait qu'installer le driver mongodb pour nodeJS dans le répertoire node_modules.

6 - Tester des requêtes CRUD avec NodeJS et express   

FAIT EN LIVE CODING: inserer + supprimer des lignes d'une table HTML depuis JavaScript: http://jsbin.com/hinilet/edit?console,output

  1. Récupérez cette archive qui est une version modifiée de l'exercice précédent: TPRoutageExpressWithMongo3.zip 
     
  2.  Dezipper, allez dans le répertoire créé (TPRoutageExpressWithMongo3) et faites "npm install"
     
  3. Exécutez node serverCrudWithMongo (ou nodemon)
     
  4. Ouvrez localhost:8080

  5. Etudiez le code, regardez en particulier comment, quand on clique sur le premier bouton GET AJAX un tableau est construit dynamiquement. 
     
  6. Etudiez ce que le prof a fait en live coding: la suppression et la modification d'une donnée.

A FAIRE : essayer d'ajouter un findByName et un count à l'application précédente.

Corrections pour le count et pour le findByName:

Voir la doc de MongoDB pour les requêtes comprenant des expressions régulières: https://docs.mongodb.com/manual/refe...r/query/regex/

Dans serverCrudWithMongo.js:

// ICI c'est autorisé par la norme REST car
// "count" est un mot réservé, on ne risque pas de
// le prendre pour une TABLE ou une collection
// cf la partie "reserved words" de
// https://blog.octo.com/designer-une-api-rest/
app.get('/api/restaurants/count', function(req, res) { 
	// on renvoie le nombre de restaurants
 	mongoDBModule.countRestaurants(function(data) {
 		var objdData = {
 			msg:"Count effectué avec succès",
 			data: data
 		}
 		res.send(JSON.stringify(objdData)); 
 	});     	
});

// On va récupérer des restaurants par un GET (standard REST) 
// cette fonction d'API peut accepter des paramètres
// pagesize = nombre de restaurants par page
// page = no de la page
// Oui, on va faire de la pagination, pour afficher
// par exemple les restaurants 10 par 10
app.get('/api/restaurants', function(req, res) { 
	// Si présent on prend la valeur du param, sinon 1
    let page = parseInt(req.query.page || 0);
    // idem si present on prend la valeur, sinon 10
    let pagesize = parseInt(req.query.pagesize || 10);
    let nom = req.query.nom;

	if(nom) {
    	// find by name
	 	mongoDBModule.findRestaurantsByName(nom, page, pagesize, function(data) {
	 		var objdData = {
	 			msg:"restaurant recherchés par nom avec succès",
	 			data: data
	 		}
	 		res.send(JSON.stringify(objdData)); 
	 	}); 
    } else {
    	// find normal
	 	mongoDBModule.findRestaurants(page, pagesize, function(data) {
	 		var objdData = {
	 			msg:"restaurant recherchés avec succès",
	 			data: data
	 		}
	 		res.send(JSON.stringify(objdData)); 
	 	}); 

    }
});

Dans app_modules/crud-mongo.js:

exports.countRestaurants = function(callback) {
	console.log("DANS COUNT")
	MongoClient.connect(url, function(err, client) {
                var db = client.db(dbName);
		db.collection('restaurants')
		.count(function(err, res) {
			console.log("COUNT = " + res)
			callback(res);
		});
	});
};

exports.findRestaurantsByName = function(nom,page, pagesize, callback) {
    MongoClient.connect(url, function(err, client) {
            var db = client.db(dbName);
    	    console.log("pagesize = " + pagesize);
    	    console.log("page = " + page);
    console.log("FIND BY NAME nom=" + nom);

    	// syntaxe recommandée
    	// Cf doc mongodb: https://docs.mongodb.com/manual/reference/operator/query/regex/
    	// The $regex value needs to be either the string 
    	// pattern to match or a regular expression object. 
    	// When passing a string pattern, you don't include 
    	// the / delimitters
    	// VERSION avec $regexp et $options
    	let myquery = {
    		"name": {
    			$regex: ".*" + nom + ".*", 
    			$options:"i"
    		}
    	}

    	// VERSION avec objet RegExp
    	//let myquery =  {'name' : new RegExp('^.*'+nom+'.*$',"i")};
    	// ou, si on veut être "case sensitive"  
    	//let myquery =  {'name' : new RegExp('^.*'+nom+'.*$')};
        if(!err){
            db.collection('restaurants')
            .find(myquery)
            .skip(page*pagesize)
            .limit(pagesize)
            .toArray()
            .then(arr => callback(arr));
        }
        else{
            callback(-1);
        }
    });
};