Gandi Social Club

Performance & bonne pratique

Gandi Social Club

Sommaire

  • DataTables
  • Bundle Free
  • PHP Lint & JavaScript Lint
  • JavaScript & CSS Pur
  • Code Splitting
  • Vegeta
  • BlackFire
  • Composer
  • NGINX
  • Symfony

Gandi Social Club

DataTables

Gandi Social Club

DataTables

Pourquoi ?

  • Gain de performance sur les recherches
  • Pas besoin de recharger la page
  • Meilleure UX

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Exemple 

import {DataTable} from "simple-datatables";

new DataTable(document.querySelector("#table"), {
    labels: {
        placeholder: "Rechercher par identifiant, nom, description, ...",
        perPage: "{select} éléments par page",
        noRows: "Aucun élement trouvé.",
        info: "{start} sur {end} éléments affichés pour {rows} trouvés"
    },
    layout: {
        top: "{search}",
        bottom: "{info}{pager}"
    },
    perPage: 25
});

Gandi Social Club

DataTables

Rendu

Gandi Social Club

Bundle Free

Gandi Social Club

Bundle Free

Pourquoi ?

  • Moins de bundle chargés par pages
  • Plus rapide au rendu HTML
  • Plus rapide à installer le projet

Gandi Social Club

Bundle Free

Exemple

{
    "require": {
        "php": "^7.2.5",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "antishov/doctrine-extensions-bundle": "^1.4",
        "doctrine/annotations": "^1.8",
        "sensio/framework-extra-bundle": "^5.1",
        "symfony/asset": "5.0.*",
        "symfony/console": "5.0.*",
        "symfony/dotenv": "5.0.*",
        "symfony/expression-language": "5.0.*",
        "symfony/flex": "^1.3.1",
        "symfony/form": "5.0.*",
        "symfony/framework-bundle": "5.0.*",
        "symfony/google-mailer": "5.0.*",
        "symfony/http-client": "5.0.*",
        "symfony/intl": "5.0.*",
        "symfony/mailer": "5.0.*",
        "symfony/mime": "5.0.*",
        "symfony/monolog-bundle": "^3.1",
        "symfony/notifier": "5.0.*",
        "symfony/orm-pack": "^1.0",
        "symfony/process": "5.0.*",
        "symfony/security-bundle": "5.0.*",
        "symfony/serializer-pack": "^1.0",
        "symfony/string": "5.0.*",
        "symfony/translation": "5.0.*",
        "symfony/twig-bundle": "5.0.*",
        "symfony/twig-pack": "^1.0",
        "symfony/validator": "5.0.*",
        "symfony/web-link": "5.0.*",
        "symfony/yaml": "5.0.*",
        "twig/extra-bundle": "^3.0",
        "twig/inky-extra": "^3.0"
    }
}

Gandi Social Club

PHP Lint & JS Lint

Gandi Social Club

PHP & JS Lint

Pourquoi ?

  • Meilleure qualité de code
  • Bonnes pratiques
  • Évite des erreurs
  • Un code de qualité est un code performant

Gandi Social Club

PHP & JS Lint

Exemple

Gandi Social Club

JS & CSS Pur

Gandi Social Club

JS & CSS Pur

Pourquoi ?

  • Moins de données à télécharger
  • Moins de librairie à télécharger
  • Moins de code à évaluer pour le navigateur
  • Materialize (seule dépendence)
  • Pas de jQuery !!!

Gandi Social Club

JS & CSS Pur

Exemple

function removeProjectTag(chip) {
  const {tagName} = chip.dataset;
  const foundTag = initialTags.find(tag => tag.name.split(" - ")[0] === tagName);

  if (foundTag) {
    fetch(`/admin/project/${projectId}/tags/${foundTag.id}`, {
      method: "DELETE",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      if (response.ok) {
        chip.removeEventListener("click", removeProjectTag);
        window.location.reload();
        return;
      }

      response.json().then(data => {
        data.errors.forEach(error => {
          window.M.toast({html: error, classes: "red"});
        });
      });
    });
  }
}

Gandi Social Club

JS & CSS Pur

Exemple

function removeProjectTag(chip) {
  const {tagName} = chip.dataset;
  const foundTag = initialTags.find(tag => tag.name.split(" - ")[0] === tagName);

  if (foundTag) {
    fetch(`/admin/project/${projectId}/tags/${foundTag.id}`, {
      method: "DELETE",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      if (response.ok) {
        chip.removeEventListener("click", removeProjectTag);
        window.location.reload();
        return;
      }

      response.json().then(data => {
        data.errors.forEach(error => {
          window.M.toast({html: error, classes: "red"});
        });
      });
    });
  }
}

Gandi Social Club

JS & CSS Pur

Exemple

function removeProjectTag(chip) {
  const {tagName} = chip.dataset;
  const foundTag = initialTags.find(tag => tag.name.split(" - ")[0] === tagName);

  if (foundTag) {
    fetch(`/admin/project/${projectId}/tags/${foundTag.id}`, {
      method: "DELETE",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      if (response.ok) {
        chip.removeEventListener("click", removeProjectTag);
        window.location.reload();
        return;
      }

      response.json().then(data => {
        data.errors.forEach(error => {
          window.M.toast({html: error, classes: "red"});
        });
      });
    });
  }
}

Gandi Social Club

JS & CSS Pur

Exemple

function removeProjectTag(chip) {
  const {tagName} = chip.dataset;
  const foundTag = initialTags.find(tag => tag.name.split(" - ")[0] === tagName);

  if (foundTag) {
    fetch(`/admin/project/${projectId}/tags/${foundTag.id}`, {
      method: "DELETE",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      if (response.ok) {
        chip.removeEventListener("click", removeProjectTag);
        window.location.reload();
        return;
      }

      response.json().then(data => {
        data.errors.forEach(error => {
          window.M.toast({html: error, classes: "red"});
        });
      });
    });
  }
}

Gandi Social Club

JS & CSS Pur

Exemple

function removeProjectTag(chip) {
  const {tagName} = chip.dataset;
  const foundTag = initialTags.find(tag => tag.name.split(" - ")[0] === tagName);

  if (foundTag) {
    fetch(`/admin/project/${projectId}/tags/${foundTag.id}`, {
      method: "DELETE",
      credentials: "include",
      headers: {
        "Content-Type": "application/json"
      }
    }).then(response => {
      if (response.ok) {
        chip.removeEventListener("click", removeProjectTag);
        window.location.reload();
        return;
      }

      response.json().then(data => {
        data.errors.forEach(error => {
          window.M.toast({html: error, classes: "red"});
        });
      });
    });
  }
}

Gandi Social Club

Code Splitting

Gandi Social Club

Code Splitting

Pourquoi ?

  • Moins de code à télécharger
  • Moins de code à parser
  • Moins de code à évaluer
  • Meilleure modularité du code

Gandi Social Club

Code Splitting

Exemple

const Encore = require("@symfony/webpack-encore");


Encore.setOutputPath("public/build/")
    .setPublicPath("/build")
    .addEntry("app", "./assets/js/app.js")
    .addEntry("messages", "./assets/js/messages.js")
    .addEntry("frenchTranslations", "./assets/js/translations/fr.js")
    .addEntry("datatable", "./assets/js/datatable/index.js")
    .addEntry("front/profil", "./assets/front/profil/index.js")
    .addEntry("front/project", "./assets/front/project/index.js")
    .addEntry("admin/project", "./assets/admin/project/index.js");

module.exports = Encore.getWebpackConfig();

Gandi Social Club

Vegeta

Gandi Social Club

Vegeta

Pourquoi ?

  • Tester les limites de notre serveur
  • Monitorer les baisses de performances
  • Surveiller les pages à risque

Gandi Social Club

Vegeta

Exemple

Gandi Social Club

BlackFire

Gandi Social Club

BlackFire

Pourquoi ?

  • Améliorer les performances
  • Corriger les erreurs de pédantique
  • Surveiller en continue les performances
  • Assurer une qualité constante

Gandi Social Club

BlackFire

Exemple

blackfire:
    image: blackfire/blackfire
    depends_on:
        - php
    ports:
        - 0.0.0.0:8707:8707
    environment:
        # Exposes BLACKFIRE_* environment variables from the host
        BLACKFIRE_SERVER_ID: ...
        BLACKFIRE_SERVER_TOKEN: ...
        BLACKFIRE_CLIENT_ID: ...
        BLACKFIRE_CLIENT_TOKEN: ...

Gandi Social Club

BlackFire

Exemple

Gandi Social Club

BlackFire

Exemple

Gandi Social Club

BlackFire

Exemple

Gandi Social Club

BlackFire

Exemple

Gandi Social Club

Composer

Gandi Social Club

Composer

Pourquoi ?

  • Mapper des classes
  • Gagner du temps sur l'autoloader
  • Supprimer les classes innexistantes

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

Composer

Exemple

#!/bin/sh

composer \
    dump-autoload \
    --classmap-authoritative \
    --optimize-autoloader \
    --apcu-autoloader

Gandi Social Club

NGINX

Gandi Social Club

NGINX

Pourquoi ?

  • Meilleur temps de réponse
  • Moins de données à télécharger
  • Plus de connexions simultannées

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

NGINX

Exemple

user                    gandi gandi;
worker_processes        16;
error_log               logs/gandi-social.club.log;
pid                     logs/gandi-social.club.pid;

events {
    worker_connections  4096;
}

http {
    include             conf/mime.types;
    include             /etc/nginx/proxy.conf;
    include             /etc/nginx/fastcgi.conf;
    index               index.html index.php;
    default_type        application/octet-stream;
    access_log          logs/gandi-social.club.access.log;

    server {
        listen          80 default_server;
        server_name     gandi-social.club;
        return          301 https://gandi-social.club$request_uri;
    }
    server {
        listen          443 ssl http2;
        server_name     gandi-social.club;
        gzip            on;
        gzip_comp_level 9;
        gzip_min_length 1;
        gzip_types      ...

        location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
            expires     365d;
        }
    }
}

Gandi Social Club

Symfony

Gandi Social Club

Symfony

Pourquoi ?

  • Bonnes pratiques
  • Aider le framework
  • Accélerer le chargement des pages (cache)

Gandi Social Club

Symfony

Exemple

Gandi Social Club

Symfony

Exemple

Gandi Social Club

Symfony

Exemple

Gandi Social Club

Symfony

Exemple

<?php

$response = $this->render('blog/index.html.twig', []);
$response->setMaxAge(3600);

return $response;

Gandi Social Club

Merci de nous avoir écouté !

Gandi

By Amin Nairi

Gandi

Slide de présentation des optimisations de performances ajouté sur le projet Gandi Social Club

  • 95