L'art d'aspirer votre code

Créé par Baptiste Donaux

Baptiste Donaux

Gulp, qu'est-ce que c'est ?

  • Un Task Manager
  • Basé sur Node.js
  • … écrit en JavaScript

La concurrence dans tout ça ?

Et aussi…

Arborescence

app
|_Resources
  |_lib <-- vos dépendances sont installées ici
  |_public
    |_images <-- Pourquoi ne pas mettre vos images directement dans web/images ?
    |_fonts <-- Pourquoi ne pas mettre vos fonts directement dans web/fonts ?
    |_stylesheet *.{less,sass,scss}
    |_js *.{js,ts,cs}
docker <3
src <-- on abandonne les ressources dans les bundles
vendor
web
|_images
|_fonts
|_css <-- les fichiers compilés dans app/Resources/public/stylesheet/
|_js <-- les fichiers compilés dans app/Resources/public/js/

Arborescence

Pour les ressources CSS/JS, on gère un fichier principal (main/global) dans lequel on vient mettre les instructions communes à toutes les pages.
Ce fichier est toujours chargé !

Quand un bout de code est manquant, on crée un fichier supplémentaire dans l'arborescence correspondante, qu'on vient ajouter dans le template Twig.

app
|_Resources
  |_lib <-- vos dépendances sont installées ici
  |_public
    |_js
      |_main.js
      |_admin
        |_list.js

Arborescence

// app/Resources/views/base.html.twig

{% block stylesheets %}

{% endblock %}
// app/Resources/views/admin/list.html.twig

{% block stylesheets %}
{{ parent() }}

{% endblock %}

Gulp/Bower <3

Gulp/Bower <3

Gestionnaire de dépendances (assets).
Avantages:

  • Pas de dépendances à versionner
  • Mise à jour rapide/efficace et en continue des bibliothèques

Gulp/Bower <3

// package.json
{
    "devDependencies": {
        "bower": "1.5.*"
    }
}
// bower.json
{
    "dependencies": {
        "autocomplete.js": "2.0.*"
    }
}

}
// .bowerrc
{
    "directory": "app/Resources/lib/"
}                        

Comment installer gulp.js ?

C'est la base…

(par François)
// package.json
{
    "devDependencies": {
        "gulp": "3.9.*"
    }
}
$ npm install
// gulpfile.js
var gulp = require('gulp');

// et c'est tout
$ gulp

Introduction et convention

// package.json
{
    "gulp":            "3.9.*",
    "gulp-imports":    "0.0.*",
    "gulp-less":       "3.0.*",
    "gulp-livereload": "3.8.*",
    "gulp-minify-css": "1.2.*",
    "gulp-uglify":     "1.4.*",
    "gulp-watch":      "4.3.*"
}

Introduction et convention (less)

// gulpfile.js

var gulp       = require('gulp'),
    less       = require('gulp-less'),
    minifyCSS  = require('gulp-minify-css'),
    path       = require('path');

gulp.task('css', function () {
    return gulp.src("./app/Resources/public/stylesheet/**/*.less")
        .pipe(less({
            paths: [ path.join(__dirname, 'less', 'includes') ]
        }))
        .pipe(minifyCSS())
        .pipe(gulp.dest("./web/css"));
});

gulp.task('default', ["css"]);

Introduction et convention (less)

// app/Resources/public/stylesheet/main.less

@import (inline) "../../lib/bootstrap/dist/css/bootstrap.css";

@swag: red;

body {
    background-color: @swag;
}

Introduction et convention (js)

// gulpfile.js

var gulp       = require('gulp'),
    imports    = require('gulp-imports'),
    uglify     = require('gulp-uglify');

gulp.task('js', function () {
    return gulp.src("./app/Resources/public/js/**/*.js")
        .pipe(imports())
        .pipe(uglify())
        .pipe(gulp.dest("./web/js"));
});

gulp.task('default', ["js"]);

Introduction et convention (js)

// app/Resources/public/js/main.js

//import("../../lib/jquery/dist/jquery.js");
//import("../../lib/bootstrap/dist/js/bootstrap.js");

$(document).ready(function() {
    console.log("Juste du swag… Just !");
});

Introduction et convention (gestion des environnements)

Pour gérer son environnement de dev différemment de celui de prod, vous pouvez créer des tasks différentes.

  • css-dev
  • css-prod
  • js-dev
  • js-prod
// gulpfile.js
gulp.task('dev', ['css-dev', 'js-dev']);
gulp.task('prod', ['css-prod', 'js-prod']);
gulp.task('default', ['dev']);

Introduction et convention (gérer le reload des fichiers - watch)

// package.json
{
    "gulp-livereload": "3.8.*",
    "gulp-watch": "4.3.*"
}
// gulpfile.js
                                
var gulp       = require('gulp'),
    livereload = require('gulp-livereload'),
    watch      = require('gulp-watch');

gulp.task('watch', function () {
    var onChange = function (event) {
        console.log('File ' + event.path + ' has been ' + event.type);

        livereload.changed(event.path);
    };

    livereload.listen();

    gulp.watch("./app/Resources/public/stylesheet/**/*.less", ['css-dev']).on('change', onChange);
    gulp.watch("./app/Resources/public/js/**/*.js", ['js-dev']).on('change', onChange);
});

Allez plus loin

JSX ?

// package.json
{
    "gulp-jsx": "2.0.*"
}
// gulpfile.js

var jsx = require('gulp-jsx');

gulp.task('js', function () {
    return gulp.src('./app/Resources/public/js/**/*.js')
        .pipe(jsx({
            factory: "createElement"
        }))
        .pipe(gulp.dest('./web/js'));
});

JSX - Factory

// app/Resources/public/js/main.js
                        
function createElement(element, attributes, subelements)
{
    var element = document.createElement(element);

    for (var attribute in attributes) {
        element.setAttribute(attribute, attributes[attribute]);
    }

    if (subelements !== undefined) {
        for (var i = 0; i < subelements.length; i++) {
            if (typeof subelements[i] == "string") {
                element.appendChild(
                    document.createTextNode(subelements[i])
                    );
            } else {
                element.appendChild(subelements[i]);
            }
        };
    }

    return element;
}

JSX - Syntaxe

var myElement = ;

JSX - Une fois compilé

var myElement = createElement('div', {class: "modal fade", tabindex: "-1", role: "dialog"}, [
  createElement('div', {class: "modal-dialog"}, [
    createElement('div', {class: "modal-content"}, [
      createElement('div', {class: "modal-header"}, [
        createElement('button', {type: "button", class: "close", 'data-dismiss': "modal", 'aria-label': "Close"}, [createElement('span', {'aria-hidden': "true"}, ["×"])]),
        createElement('h4', {class: "modal-title"}, ["Modal title"])
      ]),
      createElement('div', {class: "modal-body"}, [
        createElement('p', null, ["One fine body…"])
      ]),
      createElement('div', {class: "modal-footer"}, [
        createElement('button', {type: "button", class: "btn btn-default", 'data-dismiss': "modal"}, ["Close"]),
        createElement('button', {type: "button", class: "btn btn-primary"}, ["Save changes"])
      ])
    ])
  ])
]);

Problème

  • Gestion des erreurs de compilation dans le watch mal géré.
  • L'import de fichier JS avec gulp-imports pas tip-top

Maintenant, vous n'avez plus d'excuse !