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-autoloaderGandi Social Club
Composer
Exemple
#!/bin/sh
composer \
dump-autoload \
--classmap-authoritative \
--optimize-autoloader \
--apcu-autoloaderGandi Social Club
Composer
Exemple
#!/bin/sh
composer \
dump-autoload \
--classmap-authoritative \
--optimize-autoloader \
--apcu-autoloaderGandi Social Club
Composer
Exemple
#!/bin/sh
composer \
dump-autoload \
--classmap-authoritative \
--optimize-autoloader \
--apcu-autoloaderGandi Social Club
Composer
Exemple
#!/bin/sh
composer \
dump-autoload \
--classmap-authoritative \
--optimize-autoloader \
--apcu-autoloaderGandi Social Club
Composer
Exemple
#!/bin/sh
composer \
dump-autoload \
--classmap-authoritative \
--optimize-autoloader \
--apcu-autoloaderGandi 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
- 96