Développement Web

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Contexte historique

Internet (~1980) et le Web (~1990)
  • Repose sur Internet, TCP/IP, modèle OSI

  • Un des services de l’Internet (port 80)

  • 3 piliers : HTML, URI, HTTP

mosaic browser

Les 3 piliers du Web

HTTP
GET /idl/slides/webdev.html#/3 HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: naomod.univ-nantes.io
Accept-Language: fr-fr
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
HTML
<!DOCTYPE html>
<html>
    <meta charset="utf-8">
    <head>
        <title>Développement Web</title>
    </head>
    <body>
        <h1>Les 3 piliers du Web</h1>
        <h2>HTML</h2>
    </body>
</html>

Plusieurs évolutions

  • Séparation mise en forme (CSS)

  • Des pages statiques vers interactions dynamiques

  • Cloud computing, Web sémantique, Web embarqué, systèmes pervasifs, etc.

  • HTML5 (Conteneur d’applications complexes)

Évolutions du Web

Évolutions du Web => Web 2.0
  • Utilisateur proactif (Wikipedia, blogs, etc.)

  • Interfaces riches, intégration d’applications

Moyens techniques
  • Langage de scripts:

    • côté serveur (PHP, ASP, C#…)

    • côté client (Javascript, Adobe Flash…)

Architecture d’une application Web

Architecture

Échange de données entre applications et services

JSON
{
 "query": {
  "count": 10,
  "created": "2011-06-21T08:10:46Z",
  "lang": "en-US"
  }
}
XML
<query>
  <count>10</count>
  <created>2011-06-21T08:10:46Z</created>
  <lang>en-US</lang>
</query>

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Cadres d’applications

Application Frameworks
  • Applications "semi-complètes"

  • Architecture pré-établie

  • Conçus pour simplifier le développement

framework
Figure 1. Framework

Types d’Architectures de Frameworks

  • MVC Modèle-Vue-Contrôleur

    • Modèles Push ou Pull

  • Organisation 3-tiers

MVC Modèle-Vue-Contrôleur

mvc
Modèles Push / Pull
  • La plupart des cadres MVC utilisent le modèle push: Django, Ruby on Rails, Symfony

  • Certains utilisent le modèle pull: Vue, Angular2, React

Organisation 3-tiers

  1. Client (Browser avec HTML/Javascipt/CSS)

  2. Application (composants métier)

  3. Base de données (stockage)

Applications web multi-page

  • Côté Serveur: Django, Symfony, Ruby on Rails

  • Côté Client: Angular, React, Vue

Architecture
vuejs logo
react logo
angular logo

Applications web page unique (SPA)

  • Exemples: Gmail, Google Maps, Facebook, Twitter, Instagram, etc.

  • Cadres côté serveur: Spring Boot, Express, API Platform

  • Cadres côté client: Angular, React, Vue

Web Deployment

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Langages côté client

html css js
  • Le trio Javascript/HTML/CSS est la seule option option crédible comme langage native: c’est la norme effective.

  • Mais beaucoup de variantes de Javascript sont utilisées.

Solutions émergentes

  • WebAssembly (ou wasm) est un nouveau format portable, efficace et adapté à la compilation sur le Web.

  • WebAssembly est actuellement conçu comme un standard ouvert par un groupe communautaire de la W3C comprenant des représentants de tous les principaux navigateurs.

Plateformes d’exécution (Navigateurs)

dom
DOM (Document Object Model)
  • Document Object Model fait de chaque élément identifiable d’une application Web un objet pouvant être manipulé pour la couleur, la transparence, la position, le son et le comportement.

  • Chaque balise HTML est un objet/enregistrement DOM.

DOM (Document Object Model)

funnel
dom

Applications Web

webapplications

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Développement côté serveur avec Node.js

nodejs logo

Présentation Node.js

  • Node.js est une plateforme pour développer des applications en JavaScript «côté serveur»

  • Moteur léger et peu gourmand en ressources (CPU, Mémoire)

  • Noyau en JavaScript et C++ par-dessus le moteur JavaScript V8 de Google Chrome (régulièrement mis à jour dans Node.js)

  • Logiciel libre.

Présentation Node.js (Cont.)

  • Manipule nativement le format JSON

  • Sait gérer nativement toutes les requêtes HTTP

  • Développement aisé d’applications (grande agilité)

  • Les applications réalisées sont extrêmement rapides

Utilisations de Node.js

Node.js est excellent pour :
  • Créer des services et des sites Web

    • Très nombreuses connexions et montée en charge (gère des milliers de connexions simultanées à faible charge sur un seul processus)

  • Communications temps réel

Limitations

Applications ayant besoin de:
  • usage intensif de CPU : 3D, transcodage vidéo, etc.

  • mise en mémoire de grande quantité de données

Philosophie de Node.js

modules nodejs
  1. Un coeur léger offrant une API simple

  2. Des modules complémentaires développés par la communauté

Objectifs

  • Programmabilité et composabilité maximale

  • Réutilisabilité radicale

  • Agilité maximale

  • Innovation rapide car décentralisée

Recherche de modules

Modules utiles

Express

Serveur web minimaliste

EJS(Embedded JavaScript)

Langage simple de templates

body-parser

Traitement de requêtes HTTP

request

Client HTTP simplifié

Modules serveur utiles

Tracer

Serveur de logs

Commander

Gestion de la ligne de commande

Node-convict

lecture / enregistrement de configuration

Koa

Cadre web/REST (web framework) utilisant les promesses et les générateurs

Modules serveur utiles (Cont.)

Bookshelf.js

ORM fonctionnant avec PostgreSQL, MySQL, SQLite3, Oracle

Ldapjs*

Client et serveur LDAP

Nodemailer

Envoi de courriels

Archiver

Génération d’archives ZIP, TAR en streaming Fast-csv:: : Création et lecture de CSV

Modules client et serveur utiles

Create-error

Création de nouveaux types d’erreur

Bluebird*

Module pour promesses, ultra-rapide, avec plein d’utilitaires

Moment

Affichage, manipulations dates et durées

Validator.js

Validation et nettoyage de chaînes de caractères

Nunjucks

Template engine proposant layouts et streaming (développé par Mozilla)

Base64url

Encode, decode, escape, unescape

Modules client utiles

Loglevel

logs en console débraillables à l’exécution et compatible avec tout navigateur web (idéal pour assurer du débogage et du support)

Dexie

API IndexedDB avec des promesses, permettant notamment la recherche plein texte

Installation de modules avec NPM

  • Avec NPM on peut utiliser (installer) un module présent dans le registre NPM mais pas seulement.

  • Avec NPM on peut aussi utiliser (installer) un module présent sur un dépôt Git public, comme GitHub, ou privé

modules npm

Factoriser le code avec modules NPM (Cont.)

Forme des URL de module sur dépôt Git
git://github.com/user/project.git#commit-ish
git+ssh://user@hostname:project.git#commit-ish
git+ssh://user@hostname/project.git#commit-ish
git+http://user@hostname/project/blah.git#commit-ish
git+https://user@hostname/project/blah.git#commit-ish
Exemple pour utiliser (installer) un module privé :
npm install git+ssh://git@git.entreprise.fr:module1.git --save-dev –save-exact

Modules CommonJS

  • NPM et Node.js utilisent le standard CommonJS pour gérer les modules. La spec modules ES6 en est inspirée.

  • Exemple de module fourni (repository.js) et de module importé (behavior.js) :

// repository.js
exports.getDocsCount = getDocsCount;
function getDocsCount() {
    return db.documents.count();
}
// behavior.js
var repository = require('./repository');
repository.getDocsCount();

Modules CommonJS pour code client (navigateur)

  • Grâce à Browserify on peut utiliser les modules CommonJS avec tous les avantages que cela représente au niveau du code JavaScript déployé sur le client (navigateur)

  • On peut ainsi disposer d’environ 80% des 120.000 modules NPM disponibles à ce jour côté client.

  • Les développeurs peuvent utiliser les mêmes modules qu’ils connaissent côté client que côté serveur (et inversement :-) )

  • Pour mettre en pratique lire absolument : https://github.com/substack/browserify-handbook

Autres gestionnaires de modules (bower, yeoman)

  • Il y a actuellement plusieurs gestionnaires de modules JavaScript :

    • NPM, Bower, Yarn

  • Bower et Yarn sont moins puissants que NPM et sont généralement utilisés par les développeurs connaissant peu (la puissance de) NPM et Browserify

  • NPM a vocation à devenir l’unique gestionnaire de modules JavaScript. Mais Yarn reste très populaire

Construction d’applications avec NPM

  • NPM seul peut aussi servir à construire des applications

  • NPM lit le fichier package.json pour télécharger des modules (dépendances) et exécuter des scripts:

Construction d’applications avec NPM (Cont.)

{
  "name": "simple-server",
  "version": "1.0.0",
  "description": "A simples web server",
  "main": "build/simple-server.js",
  "dependencies": {
    "@types/express": "^4.17.2",
    "@types/node": "^13.7.0",
    "express": "^4.17.1",
    "ts-node": "^8.6.2"
  },
  "devDependencies": {
    "tslint": "^6.0.0",
    "typescript": "^3.7.5"
  },
  "scripts": {
    "prebuild": "tslint -c tslint.json -p tsconfig.json --fix",
    "build": "tsc",
    "prestart": "npm run build",
    "start": "node .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Autres outils de construction d’applications

  • Grunt : Outil très célèbre, basé sur la configuration, pour construire des applications web.

    • Facile à comprendre et à utiliser.

    • Désavantage : ne tire pas partie du streaming, fichiers lus et modifiés sur disque à chaque tâche.

  • Gulp : Outil de construction basé sur le code, plutôt que la configuration, et utilisant le streaming

Veille sécurité et correctifs

NSP

npm install --prefix ~/ -g nsp
nsp audit-package
   Name     Installed  Patched  Vulnerable Dependency
   connect    2.7.5    >=2.8.1  nodesecurity-jobs > kue > express
nsp audit-shrinkwrap
  Name     Installed  Patched  Vulnerable Dependency
  connect    2.7.5    >=2.8.1  nodesecurity-jobs > kue > express

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Création d’un site web météo

Avec Node.js, Express et OpenWeather

Aperçu de la solution

Partie I: Préparation

Vérification du service Open Weather Map

Vérification du service Open Weather Map (Cont.)

{
	"coord": {
		"lon": -1.55,
		"lat": 47.22
	},
	"weather": [{
		"id": 800,
		"main": "Clear",
		"description": "clear sky",
		"icon": "01n"
	}],
	"base": "stations",
	"main": {
		"temp": 6.68,
		"pressure": 1019,
		"humidity": 75,
		"temp_min": 6,
		"temp_max": 8
	},
	"visibility": 10000,
	"wind": {
		"speed": 4.6,
		"deg": 280
	},
	"clouds": {
		"all": 0
	},
	"dt": 1549836000,
	"sys": {
		"type": 1,
		"id": 6574,
		"message": 0.0031,
		"country": "FR",
		"sunrise": 1549783093,
		"sunset": 1549819397
	},
	"id": 2990969,
	"name": "Nantes",
	"cod": 200
}

Préparation du projet

  1. Créer un répertoire appelé weather-app

  2. Rentrer dans ce répertoire et initialiser npm.

mkdir weather-app
cd weather-app
npm init

Contenu initial

Fichier package.json:
{
  "name": "weather-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Installation de TypeScript

npm install --save-dev typescript
package.json
"devDependencies": {
  "typescript": "^3.7.5"
}

Configuration de TypeScript

tsc --init
tsconfig.json
{
    "compilerOptions": {
        "noImplicitAny": true,
        "target": "es5",
        "module": "commonjs",
        "outDir": "./build"
    },
    "exclude" : [
        "./build",
        "./node_modules"
    ],
    "include" : [
    "./src/ts"
  ]
}

Installation de Node.js

npm install --save node
npm install --save-dev @types/node
  • Afin que TypeScript puisse correctement exploiter l’API de NodeJS écrite en JavaScript, il est nécessaire de lui fournir un fichier de définitions de types au format .d.ts.

  • Heureusement, pour la plupart des bibliothèques et frameworks un minimum diffusés, il existe de tels fichiers de définition prêts à l’emploi.

Installation de Node.js (Cont.)

Fichier package.json
  "devDependencies": {
    "@types/node": "^13.7.0",
    "typescript": "^3.7.5"
  },
  "dependencies": {
    "node": "^13.8.0"
  }

Installation de Express, EJS, Body Parser et Request

npm install --save express ejs body-parser request

npm install --save-dev @types/body-parser @types/ejs @types/express @types/request ts-node nodemon

Installation de Express, EJS, Body Parser et Request (Cont.)

Fichier package.json
  "devDependencies": {
    "@types/body-parser": "^1.17.1",
    "@types/ejs": "^3.0.0",
    "@types/express": "^4.17.2",
    "@types/node": "^13.7.0",
    "@types/request": "^2.48.4",
    "nodemon": "^2.0.2",
    "ts-node": "^8.6.2",
    "typescript": "^3.7.5"
  },
  "dependencies": {
    "body-parser": "^1.19.0",
    "ejs": "^3.0.1",
    "express": "^4.17.1",
    "node": "^13.8.0",
    "request": "^2.88.0"
  }

Création des dossiers et fichiers source

mkdir -p src/ts
mkdir -p src/views
mkdir -p public/css

touch src/ts/weather-server.ts
touch src/views/index.ejs
touch public/css/style.css

Structure du projet

|-- weather-app
  |-- node_modules
    |-- express
    |-- ejs
    |-- (...)
  |-- public
    |-- css
      |-- style.css
  |-- src
    |-- ts
      |-- weather-server.ts
    |-- views
      |-- index.ejs
  |-- package.json
  |-- tsconfig.json

Partie II: Création et configuration du serveur web

Création d’un serveur minimaliste

Fichier weather-server.ts
import { Request, Response, Application } from 'express';
import express = require('express');

const app: Application = express();
const PORT = 3000; // default port to listen
const APIKEY = 'bfc78f0a877f409def99464b559c5d91';

// define a route handler for the default home page
app.get( "/", ( req: Request, res: Response ) => {
    res.send( "Hello world!" );
} );

// start the Express server
app.listen( PORT, () => {
    console.log( `server started at http://localhost:${ PORT }` );
} );

Compilation et exécution du serveur

  • Nouvelle configuration de NPM .Fichier package.json:

  "scripts": {
    "build": "tsc",
    "start": "node .",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
Exécution:
npm run build
npm run start

Partie III: Création et configuration du contenu

Création d’un fichier EJS

Fichier index.ejs
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Test</title>
    <link rel="stylesheet" type="text/css" href="/css/style.css">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>
  </head>
  <body>
    <div class="container">
      <fieldset>
        <form action="/" method="post">
          <input name="city" type="text" class="ghost-input" placeholder="Enter a City" required>
          <input type="submit" class="ghost-button" value="Get Weather">
        </form>
      </fieldset>
    </div>
  </body>
</html>

Configuration de EJS

import ejs = require('ejs');
app.set('views', 'src/views');
app.set('view engine', 'ejs')
app.get('/', ( req: Request, res: Response ) => {
  // res.send('Hello World!') // OLD CODE
  res.render('index'); // NEW CODE
})

Compilation et exécution du serveur

Compilation et exécution:
npm run build
npm run start

Partie IV: Ajout d’une feuille de style

Ajout d’un fichier CSS

mkdir -p public/css
touch public/css/style.css
    |-- weather-app
        (...)
       |-- public
          |-- css
             |-- style.css
       |-- package.json
       |-- server.js

Configuration de Express

Nouvelle ligne:
app.use(express.static('public'));

Le fichier CSS

Fichier style.css
/*
  Styles from this codepen:
  https://codepen.io/official_naveen/pen/rgknI
*/

body {
  width: 800px;
  margin: 0 auto;
  font-family: 'Open Sans', sans-serif;
}
.container {
  width: 600px;
  margin: 0 auto;
}
fieldset {
  display: block;
  -webkit-margin-start: 0px;
  -webkit-margin-end: 0px;
  -webkit-padding-before: 0em;
  -webkit-padding-start: 0em;
  -webkit-padding-end: 0em;
  -webkit-padding-after: 0em;
  border: 0px;
  border-image-source: initial;
  border-image-slice: initial;
  border-image-width: initial;
  border-image-outset: initial;
  border-image-repeat: initial;
  min-width: -webkit-min-content;
  padding: 30px;
}
.ghost-input, p {
  display: block;
  font-weight:300;
  width: 100%;
  font-size: 25px;
  border:0px;
  outline: none;
  width: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  color: #4b545f;
  background: #fff;
  font-family: Open Sans,Verdana;
  padding: 10px 15px;
  margin: 30px 0px;
  -webkit-transition: all 0.1s ease-in-out;
  -moz-transition: all 0.1s ease-in-out;
  -ms-transition: all 0.1s ease-in-out;
  -o-transition: all 0.1s ease-in-out;
  transition: all 0.1s ease-in-out;
}
.ghost-input:focus {
  border-bottom:1px solid #ddd;
}
.ghost-button {
  background-color: transparent;
  border:2px solid #ddd;
  padding:10px 30px;
  width: 100%;
  min-width: 350px;
  -webkit-transition: all 0.1s ease-in-out;
  -moz-transition: all 0.1s ease-in-out;
  -ms-transition: all 0.1s ease-in-out;
  -o-transition: all 0.1s ease-in-out;
  transition: all 0.1s ease-in-out;
}
.ghost-button:hover {
  border:2px solid #515151;
}
p {
  color: #E64A19;
}

Compilation et exécution du serveur

Compilation et exécution:
npm run build
npm run start

Partie V: Traitement de la requête

Configuration de Body Parser

Fichier weather-app.ts
import bodyParser = require('body-parser');
// ...
// ...
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', ( req: Request, res: Response ) => {
  res.render('index');
  console.log(req.body.city);
})

Compilation et exécution du serveur

Compilation et exécution:
npm run build
npm run start

Configuration de request

Fichier weather-app.ts
import request = require('request');

Traitement de la requête

Traitement du POST en 4 parties
  1. Construction de l’URL

  2. Appel de l’API

  3. Affichage de la météo

  4. Modification de la vue

1. Construction de l’URL

  • Tout d’abord, il faut récupérer le nom de la ville à partir de req.body

  • Ensuite, créer une URL pour accéder à l’API OpenWeatherMap

app.post('/', ( req: Request, res: Response ) => {
  let city = req.body.city;
  let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${APIKEY}`;

2. Appel de l’API

request(url, ( req: Request, res: Response ) => {
    if(err){
      res.render('index', {weather: null, error: 'Error, please try again'});
    } else {
      // Display weather
    }

3. Affichage de la météo

 else {
  let weather = JSON.parse(body)
  if(weather.main == undefined){
    res.render('index', {weather: null, error: 'Error, please try again'});
  } else {
    let weatherText = `It's ${weather.main.temp} degrees in ${weather.name}!`;
    res.render('index', {weather: weatherText, error: null});
  }
}

La totalité de la fonction

app.post('/', ( req: Request, res: Response ) => {
  let city = req.body.city;
  let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${APIKEY}`
request(url, function (err, response, body) {
    if(err){
      res.render('index', {weather: null, error: 'Error, please try again'});
    } else {
      let weather = JSON.parse(body)
      if(weather.main == undefined){
        res.render('index', {weather: null, error: 'Error, please try again'});
      } else {
        let weatherText = `It's ${weather.main.temp} degrees in ${weather.name}!`;
        res.render('index', {weather: weatherText, error: null});
      }
    }
  });
})

4. Modification de la vue

Mise à jour de la fonction get()
app.get('/', ( req: Request, res: Response ) => {
  res.render('index', {weather: null, error: null}); // NEW CODE
})
Changement du fichier index.ejs
<% if(weather !== null){ %>
  <p><%= weather %></p>
<% } %>
<% if(error !== null){ %>
  <p><%= error %></p>
<% } %>

Compilation et exécution du serveur

Compilation et exécution:
npm run build
npm run start

Plan

  • Un peu d’histoire

  • Cadres d’applications

  • Développement client

  • Développement serveur

  • Exemples

  • Conclusion

Conclusion

  • Node.js est une excellente plate-forme de développement d’applications, en particulier les applications qui utilisent les E/S de façon intensive.

  • Travailler avec Node.js implique de nombreux outils pour gérer les paquets, débogguer et empaqueter des projets pour le déploiement

Conclusion (Cont.)

  • Le gestionnaire de paquets de Node.js (NPM) est utilisé pour installer des paquets, et diviser les applications en plus petits artéfacts réutilisables.

  • Node.js peut être utilisé pour créer des outils de développement, des applications Web, ou des applications génériques.