Développement front-end avancé

 

Vincent Garreau

 

Slides disponibles sur
slides.com/vincentgarreau

Workflows, outils et astuces pour un développement front-end avancé

H1 à H5 / P2015

vincentgarreau.com

Au programme

Vendredi 12/05 Workflow CSS + ES2015/17
Workflow JS + Modules et composants web
Vendredi 19/05 Frameworks JS + Introduction à Vue.js

6 heures avec vous !

Workflow CSS  + ES2015/17

Intervention 1/2 / Partie 1 - Vendredi 12/05

Fondamentaux CSS

Préprocesseurs CSS / Postprocesseurs CSS

Méthodologies CSS

Linters CSS

CSS : Trucs et astuces perso
 

Introduction à ES2015 jusqu'à ES2017

Workflow JS + Modules et composants web

Intervention 1/2 / Partie 2 - Vendredi 12/05

Package managers

Task runners / Introduction à Gulp

Introduction aux modules / composants

Systèmes de modules existants

Module bundlers / Introduction à Webpack

Linters JS

Frameworks JS + Introduction à Vue.js

 

Intervention 2/2 - Vendredi 19/05

Présentation des frameworks JS existants

Introduction à Vue.js

 

Live coding :
Création d'un portfolio avec Vue.js + Webpack

Workflow CSS  + ES2015/17

 

Intervention 1/2 / Partie 1 - Vendredi 12/05

Fondamentaux CSS

Quelques notions basiques à maîtriser et à avoir en tête

Il existe 3 moyens

pour appliquer du style CSS

sur une page HTML

  Internal style 😱

 

 

 

Inline style 😰

 

 

 

External style 👍🏻

<style>.element { width: 200px; }</style>  
<span style="width:200px"></span>
<link rel="stylesheet" href="style.css">

Les sélecteurs CSS ont un poids qui détermine un ordre de priorité

 

Terme en anglais : CSS specificity

Terme en français : Poids des sélecteurs

<span style="color: red"> // 1000

#element // 100

.element // 10

span // 1

#element > div > li:hover // 100 + 1 + 1 + 10

.element !important // S'applique en priorité
Style inline
(HTML)

IDs
Classes, attributs,
pseudo classes (:)
Elements,
pseudo elements
(::)
1000 100 10 1

En CSS, on évite de se répéter

DRY :

Don't Repeat Yourself

cela dit...

 

KISS :

Keep It Simple, Stupid

.button-push { padding: 10px; }
<button class="button-push">Push 1</button>
<button class="button-push">Push 2</button>

.classes = réutilisables 👍🏻

#ids = uniques

 

D'après les standards W3C

Le CSS doit être le plus

maintenable possible

💪

Préprocesseurs CSS

 

Un préprocesseur CSS contient une palette d'outils qui permet d'écrire un CSS plus maintenable

Plusieurs
préprocesseurs CSS
existent

 

Less

 

Sass

 
Stylus

Stylus

// CSS
.element {
  width: 200px;
  height: 80px;
  font-size: 1.2em;
}

// Stylus ({}, : et ; sont chacun optionnel)
.element
  width 200px
  height 80px
  font-size 1.2em

Léger et rapide à écrire

Stylus

// CSS
.element > li { padding:10px; }
.element > li:hover { padding:20px; }

// Stylus
.element
  > li
    padding 10px
    &:hover
      padding 20px

Principe d'indentation (évitez plus de 3 niveaux)

Variables

// Sans préprocesseur
.element
  width 20px
  height 20px
  margin-right 10px

// Avec préprocesseur
$element-size = 20px
.element
  width $element-size
  height $element-size
  margin-right $element-size / 2 // Opération

Mixins

// Création de la mixin
text-truncate(customWidth)
  overflow hidden
  text-overflow ellipsis
  white-space nowrap
  width customWidth
  max-width 100%

// Appel de la mixin
.element
  text-truncate(200px)

Permet de retourner et déclarer une série de propriétées

Fonctions

// Création de la fonction
add(a, b)
  a + b

// Appel de la fonction
.element
  width add(10px, 5px) // 15px

Fonctions utiles intégrées dans Stylus :

rgba, darken, lighten... 

Même principe qu'une mixin, mais retourne une valeur

Pourquoi les mixins et les fonctions ? 🤔

DRY : Don't Repeat Yourself

Les mixins et fonctions s'utilisent 

dans des cas spécifiques 

et / ou répétitifs 

D'autres fonctionnalités

sont disponibles selon les préprocesseurs...

Opérateurs

Conditions

Itérations

@extend

@block

....

Postprocesseurs CSS

 

Un postprocesseur CSS est un outil qui permet d'effectuer
des tâches spécifiques sur un fichier CSS

Exemple d'outil : PostCSS

 

PostCSS est un outil JavaScript qui permet d'effectuer des transformations d'un fichier CSS grâce à des plugins

 

Plugins PostCSS populaires :

autoprefixer : préfixe les propriétés

cssnext : permet d'écrire dès aujourd'hui du CSS4

Méthodologies CSS

 

Ensemble de conseils et de lignes de conduite

pour un CSS organisé et maintenable 

Catégorisation / Structure 

Convention de nommage

Catégorisation / Structure

 

Avantage d'un préprocesseur CSS :

 

Pouvoir générer un fichier CSS

à partir de plusieurs fichiers

 

Remarque

Sans préprocesseur, il est possible d'importer plusieurs fichiers CSS avec la méthode @import, mais cela est lourd car sans préprocesseur aucun fichier n'est généré.
Sans préprocesseur, 1 import = 1 requête HTTP en plus.

Exemple d'architecture CSS

7-1 Pattern
7 dossiers, 1 fichier

📁 base

📁 components

📁 layout

📁 pages

📁 themes

📁 abstracts

📁 vendors

main.scss

Convention de nommage

des classes

 

Permet d'éviter des cas problématiques comme écraser du style précédemment appliqué / mélanger des styles

 

Si plusieurs développeurs travaillent sur un même projet, appliquer une règle de  nommage commune est plus facile à comprendre / lire et à maintenir

Plusieurs conventions de nommage CSS existent

 

OOCSS 

Object-Oriented CSS


SMACSS 

Scalable and Modular Approach for CSS


BEM

Block Element Modifier

Convention de nommage

avec la méthodologie BEM

// block-name__element-name--modifier-name

<header class="app-header">
  <nav class="app-header-nav">
    <ul>
      <li class="app-header-nav__item"></li>
      <li class="app-header-nav__item app-header-nav__item--on"></li>
    </ul>
  </nav>
</header>

Block__Element--Modifier

Linters CSS

 

Outil pour garder un code CSS lisible, cohérent et harmonieux

2 manières

d'utiliser un linter

Vérification dans l'éditeur de texte / IDE :

Intégré via un plugin SlublimeText par exemple

 

et / ou

 

Vérification via une commande :

Intégré dans un script (tâche Grunt, Gulp, Webpack...)

Exemple / Plugin SublimeText : Stylint

CSS
Trucs et astuces perso

Propriétés CSS3
qui me sont souvent utiles...

flex 😍

// CSS2
.nav
  .nav-item
    display inline-block
    vertical-align middle


// CSS3
.nav
  display flex
  align-items center

calc 😎

// Largeur responsive à gauche, fixe à droite

.wrapper
  display flex
  width 100%

  .left // Largeur variable
    width calc(100% - 300px)

  .right // Largeur toujours égale à 300px
    width 300px

box-sizing 😘

// Largeur de 100px, padding inclus
.myElement
  width 100px
  padding 20px
  box-sizing border-box

// border-box = padding inclus
// content-box (par défaut) = padding exclus

Bootstrap ?

Oui, mais avec modération 🍻

Classes vraiment utiles :

 

dropdown

modal

tooltip

Un fichier à part pour

réappliquer les classes Bootstrap 

// custom-bootstrap.styl (chargé après BS.)

.modal-header
  border-radius .25rem .25rem 0 0
  background $white-alabaster
  text-align center
  border-bottom 0

.form-control
  border 1px solid $grey-alto

Méthode pour nommer les

variables de couleurs

// var-colors.styl
$blue-picton = #36AAEA

// button.styl
.custom-button
  background-color $blue-picton

Gestion des icônes

 

Icon Fonts vs SVG

css-tricks.com/icon-fonts-vs-svg

 

Méthode SVG Inline

Insertion du code de l'icône SVG directement dans le HTML

 

Méthode SVG Symbols

Insertion de l'icône SVG dans le HTML en utilisant les symboles

// On sélectione l'icône en ciblant l'id du symbole dans la balise "use"
<div class="svg-wrap">
  <svg>
    <use xlink:href="#icon-cross"></use>
  </svg>
</div>
// On insère le fichier définition SVG dans le HTML (en haut, juste après l'ouverture du body)

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>

  <symbol id="icon-cross" viewBox="0 0 32 32">
    <title>cross</title>
    <path fill="#222" class="path1" d="M15.392 13.984l12.32-12.32c0.384-0.384 0.384-0.992 0-1.376s-0.992-0.384-1.376 0l-12.32 12.32-12.352-12.32c-0.384-0.384-0.992-0.384-1.376 0s-0.384 0.992 0 1.376l12.32 12.32-12.32 12.352c-0.384 0.384-0.384 0.992 0 1.376s0.992 0.384 1.376 0l12.352-12.32 12.32 12.32c0.384 0.384 0.992 0.384 1.376 0s0.384-0.992 0-1.376l-12.32-12.352z"></path>
  </symbol>

  <symbol id="icon-arrow" viewBox="0 0 32 32">
    <title>arrow</title>
    <path fill="#666" class="path1" d="M0.29 8.875l0.18 0.21 13.6 15.65c0.46 0.53 1.15 0.86 1.92 0.86s1.46-0.34 1.92-0.86l13.82-15.88c0.17-0.25 0.27-0.55 0.27-0.87 0-0.87-0.74-1.58-1.66-1.58v0h-28.68c-0.92 0-1.66 0.71-1.66 1.58 0 0.33 0.11 0.64 0.29 0.89z"></path>
  </symbol>

</defs>
</svg>

ES 2015 / ES 2017

 

Le standard JavaScript

ECMAScript 2015  = 6e édition / ES6)

ECMAScript 2016  = 7e édition / ES7)

ECMAScript 2017  = 8e édition / ES8)

Règles de portées

var = portées des fonctions

let = portées de blocs (if, for...)

let is the new var

var / let

// Anciennement var (ES5)
for (var i = 0; i <= 10; i++) {
  console.log(i)
}
console.log(i) // 11


// Avec let (ES6)
for (let i = 0; i <= 10; i++) {
  console.log(i)
}
console.log(i) // undefined 

var / let

var school = 'HETIC'

// Anciennement var (ES5)
if (school === 'HETIC') {
  var director = 'M. Beaux'
}
console.log(director) // M. Beaux

// Avec let (ES6)
if (school === 'HETIC') {
  let director = 'M. Beaux'
}
console.log(director) // undefined

const

let age = 21
const firstname = 'Marie'
const identity = {}


age = 22 // let donc OK

firstname = 'Elodie' // const donc FAIL

identity = { firstname: 'Marie' }  // FAIL

identity.firstname = 'Marie' // OK

const / let

Règle d'utilisation

const = variable non modifiable*

let = variable modifiable

non modifiable* = non redéclarable

Fonctions fléchées

// ES5
function Example() {

  var self = this // On "copie" this dans self

  this.callbackClick = function() {
    console.log('clicked')
  }

  $('button').on('click', function() { // Non fléchée
    self.callbackClick() // this réfère à button
  })

}
var example = new Example()

Fonctions fléchées

// ES6
function Example() {
  
  // Syntaxe concise (si 1 seule instruction)
  this.callbackClick = () => console.log('clicked')

  $('button').on('click', () => { // Fléchée
    this.callbackClick() // this réfère à Example
  })

}

var example = new Example()

Méthode "raccourcie"

// ES5
var methods = {
  login: function () {
    console.log('login...')
  }
}

// ES6
const methods = {
  login() { // Notation raccourcie
    console.log('login...')
  }
}

Propriété "raccourcie"

name = 'HETIC'
level = 'Bac +5'

// ES5
var school = {
  name: name,
  level: level
}

// ES6
const school = {
  name,
  level
}

Opérateur de décomposition

// On insère "..." devant l'objet itérable

const displayNames = (...people) => {
  console.log(people) // ['Jean', 'Louis', 'Charles']
}

displayNames('Jean', 'Louis', 'Charles')


// Insertion dans un tableau (alternatif à "push")

const missingNb = [2, 3]
const nb = [1, ...missingNb, 4] // [1, 2, 3, 4]

Littéraux de gabarits

year = '2020'

// ES5
var str = 'La P' + year + ' est au top'

// ES6 : Entre backticks (différents des quotes)
const str = `La P${year} est au top`


// La P2020 est au top

Argument "par défaut"

const setColor(value = '#FF0000') = () {
  console.log(`Couleur : ${value}`)
}

setColor("#000000") // Couleur : #000000

setColor() // Couleur : #FF0000

Includes

str = 'Les cours de marketing en H2 sont intenses'
youtubers = ['DirtyBiology', 'E-Penser']

// ES5
str.indexOf('marketing') !== -1 // true
youtubers['E-Penser'] !== undefined // true

// ES6
str.includes('marketing') // true 
youtubers.includes('E-Penser') // true

Promise

const getAvatar = (email) => {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: `https://www.gravatar.com/${email}.json`,
      dataType: 'jsonp',
      success(data) { resolve(data) },
      error(data) { reject(data) }
    })
  })
}

getAvatar('08e83ed895943c88b5d11db6665ee8b4')
  .then((response) => {
    console.log('resolve data', response)
  })
  .catch((response) => {
    console.log('reject data', response)
  })

Async / Await

const ajax = (email) => {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: `https://www.gravatar.com/${email}.json`,
      dataType: 'jsonp',
      success(data) { resolve(data) },
      error(data) { reject(data) }
    })
  })
}

const getAvatar = async function(email) {
  const res = await ajax(email)
  return res
}

getAvatar('08e83ed895943c88b5d11db6665ee8b4')
  .then((response) => { console.log('resolve data', response) })
  .catch((response) => { console.log('reject data', response) })

Utiliser les prochains

standards JS dès aujourd'hui 

Worflow JS + Modules et composants web

 

Intervention 1/2 / Partie 2 - Vendredi 12/05

Package managers

Gestion des librairies / plugins via un

gestionnaire de paquets 

Package managers populaires

 

npm


Bower

// package.json
{
  "name": "my-portfolio-package",
  "version": "1.0.0",
  "dependencies": {
    "jquery": "^2.2.3"
  }
}

npm

// Commande pour installer le package jquery par exemple :
npm install jquery --save

Installer Node.js (npm inclus) : nodejs.org

Rechercher un package npm : npmjs.com

Task runners

Un outil pour automatiser certaines tâches :

compilation d'assets, etc.

Task runners populaires

 

Grunt


Gulp

// gulpfile.js

// Import du module gulp et gulp-stylus
var gulp = require('gulp')
var stylus = require('gulp-stylus')

// Création d'une tâche, nommée "stylus"
gulp.task('stylus', function() {
  return gulp.src('./assets/css/main.styl')
    .pipe(stylus())
    .pipe(gulp.dest('./build/css'))
})

Gulp

// 1. Aller à l'emplacement du projet dans le terminal
// 2. Lancer la tâche "stylus" en tapant la commande :
gulp stylus

Modules et composants

C'est quoi ? Pourquoi ?

Un site / application web

doit être le plus

maintenable possible

💪

Programmation modulaire

 Consiste à utiliser une

approche modulaire de l'architecture d'un projet informatique

Module Javascript

Concept appliqué au

Javascript

Composant web

Plus large qu'un module :

Template HTML + Javascript + Style CSS

Systèmes de modules

Différents systèmes pour créer des modules Javascript

Plusieurs systèmes pour créer des modules Javascript

 

AMD


CommonJS 


ES2015 Modules

Démos disponibles sur

 

github.com/VincentGarreau/WSF

// operators.js

define([], function () {
  return {
    sum: function (a, b) {
      return a + b
    },
    divide: function (a, b) {
      return a / b
    }
  }
})
// app.js

define(["./operators.js"], function (operators) {
  var test = operators.sum(10, 5) // 15
})

AMD

Asynchronous Module Definition

// operators.js

exports.sum = function (a, b) {
  return a + b
}

exports.divide = function (a, b) {
  return a / b
}
// app.js

var operators = require('./operators.js')

var test = operators.sum(10, 5) // 15

CommonJS

// operators.js

const myObject = {}

myObject.sum = (a, b) => {
  return a + b
}

myObject.divide = (a, b) => {
  return a / b
}

export default myObject
// app.js

import operators from './operators.js'

const test = operators.sum(10, 5) // 15

ES2015 Modules

Module bundlers

Un outil qui analyse les modules pour générer des assets

Module bundlers populaires

 

Browserify


Webpack

Webpack

module.exports = {

  // Points d'entrée
  entry: './assets/js/main.js',

  // Configuration de l'export
  output: {
    path: './build/js',
    filename: "main.js"
  },
  
  // Configuration des loaders
  module: {
    rules: [
      { test: /\.css$/, loader: "style-loader!css-loader" },
    ]
  },
  
  // Configuration des plugins
  plugins: []
	
}

Webpack

Grafikart - Lien du tutoriel

Linters JS

 

Outil pour garder un code JS lisible, cohérent et harmonieux

ESLint

Frameworks JS + Introduction à Vue.js

 

Intervention 2/2 - Vendredi 19/05

Frameworks JS

Un outil tout en un pour créer une application maintenable

Frameworks JS populaires

2010

2011

2011

2013

 

2009

2013

2014

Jeremy Ashkenas

Yehuda Katz

Meteor

Google

 

Google

Facebook

Evan You

Facile à prendre en main

Développement rapide

Un écosystème flexible grâce aux différents plugins Vue

Mises à jour régulières

Communauté active

Démos Vue.js

github.com/VincentGarreau/H2P2020

Développement front-end avancé - HETIC H2 P2020

By Vincent Garreau

Développement front-end avancé - HETIC H2 P2020

Workflows, outils et astuces pour un développement front-end avancé

  • 1,064