Un Brunch avec Symfony2 !
Sur un de mes projets client, l’une de mes premières tâches était la mise en place des différents outils pour le frontend, seul pré-requis technique donné par le client concernant cette tâche : ne pas utiliser Gulp.
J’ai donc mis en place Grunt, mais lors de nos essais de build automatisé sur une petite instance DigitalOcean, le processus node de Grunt n’arrêtait pas de se faire tuer.
Il ne nous a pas fallu longtemps pour nous rendre compte que le système se débarrassait de Grunt à cause de sa trop grande consommation mémoire (> 500 Mo), sans compter le temps d’exécution entre chaque compilation, environ 12 secondes.
Je suis donc passé à Brunch et je vais vous présenter son utilisation avec Symfony2.
Brunch
est un outil de build spécialisé dans les assets. Il permet ainsi :
- la compilation des différents types de fichier (Less, Stylus Scss, Coffee, TypeScript, Jade…) ;
- la concaténation des fichiers ;
- la minification et l’optimisation des fichiers en mode production ;
- la surveillance des fichiers (watcher) pendant le développement ;
- la vérification syntaxique ;
- etc.
Pour celles et ceux qui viennent de Grunt ou Gulp, la question est : Que vaut Brunch comparé à ces deux outils ?
Section intitulée comparaison-de-grunt-gulp-et-brunchComparaison de Grunt, Gulp et Brunch
Examinons les différents fichiers de configurations de ces trois outils pour une même application :
On constate que Brunch
a une configuration très simpliste, en effet, l’outil est orienté convention plutôt que configuration.
Grunt
et Gulp
proposent une syntaxe pour décrire un ensemble de tâches, ainsi que leur ordre d’exécution. La principale différence entre les deux outils est que Grunt
exécute les tâches l’une après l’autre tandis que Gulp
propose un fonctionnement en pipeline qui évite d’utiliser des fichiers temporaires et permet une exécution en parallèle. Gulp est donc meilleur que Grunt sur la rapidité d’exécution ainsi que sur la quantité de configuration.
Je me suis également arrêté sur la vitesse de compilation de ces trois outils pour une même application.
Ce test a été effectué avec les tâches suivantes : Sass + import de Foundation, Less + import de foundation, Stylus, Concat, Uglify, Babel, TypeScript, CoffeScript. J’ai pu rapidement faire le comparatif avec le generator-joli-symfony.
Section intitulée gruntGrunt
Section intitulée gulpGulp
Section intitulée brunchBrunch
Brunch est le plus rapide, et sa configuration est plus simple : c’est notre nouveau jouet préféré à JoliCode !
Section intitulée installationInstallation
L’installation se fait de façon très classique :
$ npm install -g brunch
Le fait de l’installer en global permet de bénéficier de la commande brunch dans tout notre système et ainsi pouvoir exécuter les deux commandes brunch build
et brunch watch
.
Brunch est écrit en CoffeeScript, il est donc possible de le configurer en CoffeeScript ou en JavaScript via les fichiers brunch-config.coffee
ou brunch-config.js
.
Nous allons partir sur une configuration minimale en JavaScript, brunch-config.js
.
Ce fichier est tout simplement un module javascript qui exporte une propriété config
à l’intérieur de laquelle on retrouve une propriété files
.
On peut alors configurer trois types d’assets : javascripts
, stylesheets
et templates
. La propriété joinTo
qui est obligatoire nous permet de définir le ou les fichiers générés à la fin de la compilation.
./brunch-config.js
'use strict';
exports.config = {
files: {
javascripts: {
joinTo: 'app.js'
},
stylesheets: {
joinTo: 'app.css'
},
templates: {
joinTo: 'template.js'
}
}
};
javascripts : concerne tous les fichiers qui seront compilés en javascript (CoffeeScript, TypeScript, Babel, …).
stylesheets : concerne tous les fichiers qui seront compilés en css (SASS, Less, Stylus, …).
templates : concerne tous les fichiers qui seront compilés en HTML (Jade, YAML, …).
Par exemple, si notre projet utilise du CoffeeScript ou du TypeScript, la configuration du fichier brunch-config sera identique.
Section intitulée structures-de-dossier-par-defaut-pour-brunchStructures de dossier par défaut pour Brunch
Par défaut, Brunch se base sur cette structure de dossier :
Structure de l’application
- app
- js
- application.js
- manager.js
- assets
- fonts
- open-sans.eot
- open-sans.svg
- open-sans.ttf
- open-sans.woff
- style
- _main.scss
- _header.scss
- style.scss
- public
app : contient tous les fichiers source, à l’exception des fichiers JS fournis par des tiers (bower_component) et non conçus pour être enrobés en modules. On peut donc avoir des fichiers scripts, feuilles de style, et fichiers templates. Les fichiers préfixés par un underscore seront compilés uniquement s’ils sont importés par d’autres fichiers. (exemple avec Sass : @import "main"
)
app/assets : copié-collé dans le dossier cible, tel quel. Parfait pour les fonts, images, etc.
public : est le dossier cible par défaut afin de retrouver tous les fichiers compilés. Si on prend notre fichier de configuration, on peut voir que nos différents fichiers après compilation arrivent bien dans le dossier public/app.js
, public/app.css
et public/template.js
.
Tous les fichiers installés avec Bower
seront inclus automatiquement avant les fichiers du dossier app
, fini la mise à jour manuelle de la liste des vendors !
Nous allons maintenant configurer Brunch pour l’adapter à la structure d’un projet Symfony2.
Section intitulée structures-pour-un-projet-symfony2Structures pour un projet Symfony2
Voici la structure des fichiers que je compte utiliser :
- app
- Resources
- assets
- fonts
- open-sans.eot
- open-sans.svg
- open-sans.ttf
- open-sans.woff
- js
- application.js
- manager.js
- scss
- _main.scss
- _header.scss
- style.scss
- src
- web
- bower_component
- foundation
Voici le fichier brunch-config.js
mis à jour pour l’adapter à Symfony2 :
'use strict';
exports.config = {
paths: {
'public': 'web',
'watched': ['app/Resources']
},
conventions: {
'assets': /^app\/Resources\/assets/
},
files: {
javascripts: {
joinTo: {
'js/app.js': /^app/,
'js/vendor.js': /^(?!app)/
}
},
stylesheets: {
joinTo: 'css/style.css'
}
}
};
Section intitulée personnalisation-de-brunchPersonnalisation de Brunch
Le dossier cible peut être modifié avec paths.public,
je lui indique donc que mes fichiers seront maintenant compilés dans le dossier web
. Par défaut, le dossier cible est public
.
paths.watched
: est simplement la liste des fichiers sources utilisés dans l’application. Par défaut ['app', 'test', 'vendor']
. Mon nouveau dossier surveillé app/Resources
.
conventions.assets
: Le dossier assets sera copié-collé (récursivement) dans le dossier cible sans aucun traitement. C’est l’équivalent de la tâche Copy
que nous croisons très souvent dans grunt ou gulp. Par défaut cela correspond au dossier app/assets
. Il attend une regex ou une fonction. J’ai opté pour la regex /^app\/Resources\/assets/
.
On peut aussi définir certains fichiers ou dossiers à ignorer avec conventions.ignored
.
J’ai modifié l’objet javascripts afin d’avoir après compilation deux fichiers javascript app.js
et vendor.js
.
Le fichier app.js
contiendra tous mes fichiers sources définis par cette regex /^app/
et le fichier vendor.js
contiendra tous les autres fichiers, en excluant le dossier app, définis par cette regex /^(?!app)/
comme les librairies installées avec bower.
javascripts: {
joinTo: {
'js/app.js': /^app/,
'js/vendor.js': /^(?!app)/
}
},
Vous pouvez consulter la configuration de référence ici . Nous allons maintenant mettre en pratique Brunch
en utilisant les fichiers suivants :
app/Resources/js/calculator.js
'use strict';
var Calculator = {
add: function add(a, b) {
return console.log(a + b);
},
substract: function substract(a, b) {
return console.log(a - b);
}
};
module.exports = Calculator;
Pour compliquer la tâche, on va utiliser du Scss plutôt que du CSS.
app/Resources/scss/style.scss
@import "colors";
@import "main";
_app/Resources/scss/main.scss
body {
backgound-color: $primary;
}
_app/Resources/scss/colors.scss
$primary: #ff0;
Pour poursuivre, nous avons besoin d’installer les modules suivants avec npm
: brunch
, javascript-brunch
, et sass-brunch
. Ces modules sont des plugins, mais contrairement à Grunt, nous n’avons pas besoin de les déclarer pour qu’ils soit utilisés.
$ npm install brunch javascript-brunch sass-brunch --save
$ brunch build ## Ça fonctionne ! :-)
Section intitulée les-commandes-de-brunchles commandes de Brunch
Avec Brunch, nous avons deux commandes utiles à disposition :
$ brunch build
En lui passant l’option -P, on active le mode production permettant ainsi d’optimiser, de minifier et de désactiver les fichiers source maps.
Version simplifiée : $ brunch b
.
$ brunch watch
Surveille les répertoires définis et relance une compilation à chaque changement. Lors de la modification d’un fichier, il re-compile uniquement ce qui est nécessaire (compilation incrémentale), cela lui permet d’être ultra-rapide.
Version simplifiée : $ brunch w
.
Section intitulée allez-plus-loin-avec-bowerAllez plus loin avec bower
Maintenant, je veux ajouter Foundation
dans mon projet avec bower. Si vous ne connaissez pas bower, je vous invite à lire cet article.
Pensez à créer le fichier bower.json
.
{
"name": "brunch-sf2",
"version": "0.1.0",
"authors": [
"Laurent Brunet "
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}
$ bower install --save foundation
Foundation est livré avec quelques dépendances :
- 'bower_components/foundation/',
- 'bower_components/fastclick/',
- 'bower_components/jquery/',
- 'bower_components/jquery.cookie/',
- 'bower_components/jquery-placeholder/',
- 'bower_components/modernizr/',
D’après ma configuration, tous les fichiers javascript seront compilés dans mon fichier vendor.js
, mais je veux juste utiliser les fichiers Sass de Foundation. Je vais donc spécifier à Brunch tous les fichiers ou dossiers que je veux ignorer avec conventions.ignored
. Ils ne seront pas pris en compte lors de la compilation.
./brunch-config.js
exports.config = {
conventions: {
ignored: [
'bower_components/foundation/',
'bower_components/fastclick/',
'bower_components/jquery/',
'bower_components/jquery.cookie/',
'bower_components/jquery-placeholder/',
'bower_components/modernizr/',
],
}
};
Il est possible d’avoir des erreurs lorsqu’on installe certains plugins avec bower. Lorsque je compile, brunch m’indique une erreur qui concerne modernizr.
error: [Error: Component JSON file "/Users/lbrunet/Documents/sandbox/Yo-test/bower_components/modernizr/.bower.json" must have `main` property. See https://github.com/paulmillr/read-components#README]
Section intitulée l-erreur-main-propertyL’erreur Main Property
L’explication est très simple, chaque composant géré avec bower
doit contenir une propriété main
dans son fichier bower.json
. Cela permet à Brunch de pouvoir définir automatiquement les composants afin de pouvoir les compiler, sinon l’analyse échouera. Aujourd’hui 50% des modules ne définissent pas cette propriété dans leur fichier bower.json
.
Par exemple, dans le bower.json
de Foundation, la propriété main
indique les trois fichiers suivants :
{
"name": "foundation",
"version": "5.5.2",
"main": [
"css/foundation.css",
"css/foundation.css.map",
"js/foundation.js"
],
"ignore": [],
}
Si on regarde le bower.json
de modernizr, il n’y a pas de propriété main
définie.
{
"name": "modernizr",
"homepage": "https://github.com/Modernizr/Modernizr",
"version": "2.8.3",
"_release": "2.8.3",
"_resolution": {
"type": "version",
"tag": "v2.8.3",
"commit": "d6bb30c0f12ebb3ddd01e90b0bf435e1c34e6f11"
},
"_source": "git://github.com/Modernizr/Modernizr.git",
"_target": ">= 2.7.2",
"_originalSource": "modernizr"
}
Nous allons y remédier en modifiant ainsi notre fichier bower.json
./bower.json
{
"name": "brunch-sf2",
"dependencies": {
"foundation": "~5.5.2"
},
"overrides": {
"modernizr": {
"main": [
"modernizr.js"
]
}
}
}
Le but est de spécifier le ou les fichiers javascripts ou stylesheets en utilisant overrides
qui prend en paramètre le nom du dossier modernizr
et lui affecter un main
avec l’emplacement des fichiers.
Section intitulée les-pluginsLes plugins
Pour qu’un plugin soit actif et utilisé, il suffit qu’il soit installé, donc qu’il figure au package.json
et ait été installé par npm
.
Ainsi un simple $ npm install --save imageoptmizer-brunch
suffit à optimiser les images lors d’un build production et un $ npm install --save eslint-brunch
suffit à ajouter le linter sur vos fichiers Javascripts.
Brunch va instancier automatiquement les plugins dans leurs configurations par défaut, plus besoin de les charger avec un require
ou loadNpmTasks
.
il est possible d’affiner le comportement d’un plugin via une configuration dédiée, à définir dans le fichier brunch-coffee.js
sous la clé plugins
. Consultez la documentation du plugin pour être certain de la configuration à utiliser.
./brunch-config.js
exports.config = {
plugins: {
cleancss: {
keepSpecialComments: 0,
removeEmpty: true
},
uglify: {
mangle: true,
compress: false
}
}
};
Section intitulée je-viens-a-peine-de-vous-rencontrer-mais-je-vous-aime-dejaJe viens à peine de vous rencontrer, mais je vous aime déjà !
Je peux vous affirmer dès à présent que tous mes projets Symfony2
seront brunchés ! C’est vraiment un gain de temps sur la compilation lorsque l’on développe mais aussi en simplicité à mettre en oeuvre.
D’ailleurs, vous pouvez vous aussi créer vos projet avec brunch, Gulp ou Grunt, les vendors de Symfony2 installés, Assetic supprimé et ce avec une seule commande :
$ yo joli-symfony
Retrouve le générateur-joli-Symfony à cette adresse : https://github.com/jolicode/generator-joli-symfony, nous venons de sortir la version 1.0 !
Enfin, n’hésitez pas à explorer l’utilisation de Brunch
avec d’autres technologies. Vous pouvez consulter par exemple notre démo d’une application React & Flux écrite en ES6.
Je vous laisse digérer tout ça et à la prochaine !
Section intitulée ressourcesRessources
Commentaires et discussions
Yo, crée tes projets Symfony2 sur mesure
Si vous suivez un peu l’actualité du blog, vous avez dû apercevoir mon précédent article sur automatiser le front-end dans un projet Symfony2. On y voit que la mise en place d’un workflow front-end moderne avec Symfony2 peut prendre du temps : mise en place des dépendances ou librairies…
Lire la suite de l’article Yo, crée tes projets Symfony2 sur mesure
Automatiser le front-end dans un projet Symfony2
Dans tout projet Web, nous sommes confrontés à des tâches répétitives : Télécharger les différentes librairies ; Compiler les assets (Sass, Less, Stylus, CoffeeScript, TypeScript, …) ; Optimiser les images ; Gérer la concaténation des fichiers javascript, puis la minification…
Lire la suite de l’article Automatiser le front-end dans un projet Symfony2
Nos articles sur le même sujet
Ces clients ont profité de notre expertise
LOOK Cycle bénéficie désormais d’une nouvelle plateforme eCommerce disponible sur 70 pays et 5 langues. La base technique modulaire de Sylius permet de répondre aux exigences de LOOK Cycle en terme de catalogue, produits, tunnel d’achat, commandes, expéditions, gestion des clients et des expéditions.
Pour La Plateforme du Bâtiment, le début d’année 2014 est le moment de mettre à jour le socle technique du site. JoliCode est donc intervenu aux côtés des équipes internes pour réaliser une migration de Symfony2 de la version 2.0 à la 2.3. Au programme : beaucoup de tests unitaires et fonctionnels, l’installation et l’utilisation de Composer, et une…
À l’occasion de la 12e édition du concours Europan Europe, JoliCode a conçu la plateforme technique du concours. Ce site permet la présentation des différents sites pour lesquels il y a un appel à projets, et encadre le processus de recueil des projets soumis par des milliers d’architectes candidats. L’application gère également toute la partie post-concours…