Slide 1

Slide 1 text

@michellesanver SymfonyCon Madrid 2014 Life After Assetic State of the Art Symfony 2 Frontend Dev

Slide 2

Slide 2 text

@michellesanver

Slide 3

Slide 3 text

@michellesanver Intro A simple Symfony2 application

Slide 4

Slide 4 text

@michellesanver A simple Symfony2 Application JavaScript

Slide 5

Slide 5 text

@michellesanver A simple Symfony2 Application jQuery / Angular.js

Slide 6

Slide 6 text

@michellesanver A simple Symfony2 Application Custom Files

Slide 7

Slide 7 text

@michellesanver A simple Symfony2 Application SASS / LESS

Slide 8

Slide 8 text

@michellesanver A simple Symfony2 Application Minimise for performance

Slide 9

Slide 9 text

@michellesanver Audience Do you use assetic?

Slide 10

Slide 10 text

@michellesanver Audience Do you use grunt or gulp?

Slide 11

Slide 11 text

@michellesanver Audience Do you use bower?

Slide 12

Slide 12 text

@michellesanver Audience Manually!? (Or not at all)

Slide 13

Slide 13 text

@michellesanver

Slide 14

Slide 14 text

@michellesanver

Slide 15

Slide 15 text

@michellesanver Michelle Sanver

Slide 16

Slide 16 text

@michellesanver Michelle Sanver Body Text Co-President of PHPWomen

Slide 17

Slide 17 text

@michellesanver Michelle Sanver Accent(s)!?

Slide 18

Slide 18 text

@michellesanver Michelle Sanver

Slide 19

Slide 19 text

@michellesanver Table Of Contents • Assetic - Symfony2 front-end manager • Bower - Front-end package manager • Gulp - A modular task runner • Gulp + Bower in Symfony2 • Life After Assetic

Slide 20

Slide 20 text

@michellesanver Disclaimer There are several good solutions.

Slide 21

Slide 21 text

@michellesanver Assetic

Slide 22

Slide 22 text

@michellesanver Life *before* assetic

Slide 23

Slide 23 text

@michellesanver Life *before* assetic Minify manually

Slide 24

Slide 24 text

@michellesanver Life *before* assetic Compile SASS/LESS The “old” way

Slide 25

Slide 25 text

@michellesanver Life *before* assetic Or use third party tools, still not well integrated.

Slide 26

Slide 26 text

@michellesanver Assetic An awesome tool for asset management!

Slide 27

Slide 27 text

@michellesanver Assetic Minify and combine CSS and JS files

Slide 28

Slide 28 text

@michellesanver Assetic Your files can live anywhere!

Slide 29

Slide 29 text

@michellesanver Assetic Compilers LESS, SASS, CoffeeScript

Slide 30

Slide 30 text

@michellesanver Assetic Image Optimisation

Slide 31

Slide 31 text

@michellesanver Assetic Assets and filters

Slide 32

Slide 32 text

@michellesanver Assetic: Assets {% javascripts '@AcmeFooBundle/Resources/public/js/*' %}

Slide 33

Slide 33 text

@michellesanver Assetic: Assets {% stylesheets 'bundles/acme_foo/css/*' filter='cssrewrite' %} {% endstylesheets %}

Slide 34

Slide 34 text

@michellesanver Assetic: Filters {% stylesheets 'bundles/acme_foo/css/*' filter='cssrewrite' %} {% endstylesheets %}

Slide 35

Slide 35 text

@michellesanver Assetic: Compilers Define them in the config

Slide 36

Slide 36 text

@michellesanver Bower

Slide 37

Slide 37 text

@michellesanver Before Bower Downloading .zip files

Slide 38

Slide 38 text

@michellesanver Before Bower Dependencies: Trial and error

Slide 39

Slide 39 text

@michellesanver Bower Bower solved this!

Slide 40

Slide 40 text

@michellesanver Bower The Composer of JavaScript

Slide 41

Slide 41 text

@michellesanver Installing Bower npm init

Slide 42

Slide 42 text

@michellesanver Installing Bower npm install -g bower

Slide 43

Slide 43 text

@michellesanver Installing Bower: Locally npm install --save-dev bower

Slide 44

Slide 44 text

@michellesanver Installing Bower: Locally bower command available at ./ node_modules/.bin/bower

Slide 45

Slide 45 text

@michellesanver Installing Bower: Locally alias npm-exec='PATH=$(npm bin): $PATH'

Slide 46

Slide 46 text

@michellesanver Using Bower Every project is an installable library

Slide 47

Slide 47 text

@michellesanver Using Bower bower init

Slide 48

Slide 48 text

@michellesanver Using Bower bower.init main file

Slide 49

Slide 49 text

@michellesanver Using Bower bower.init what types of modules does this package expose?

Slide 50

Slide 50 text

@michellesanver Using Bower bower.init set currently installed components as dependencies?

Slide 51

Slide 51 text

@michellesanver Using Bower bower.init add commonly ignored files to ignore list?

Slide 52

Slide 52 text

@michellesanver Using Bower bower.init would you like to mark this package as private which prevents it from being accidentally published to the registry?

Slide 53

Slide 53 text

@michellesanver Using Bower bower.json

Slide 54

Slide 54 text

@michellesanver bower.json $ bower install --save jquery bootstrap

Slide 55

Slide 55 text

@michellesanver bower.json "dependencies": { "jquery": "~2.1.1", "bootstrap": "~3.1.1" }

Slide 56

Slide 56 text

@michellesanver bower.json bower install

Slide 57

Slide 57 text

@michellesanver bower.json { "directory": "public/bower_components" }

Slide 58

Slide 58 text

@michellesanver bower.json rm -Rf bower_components bower install

Slide 59

Slide 59 text

@michellesanver bower.json /bower_components//dist/ <files>

Slide 60

Slide 60 text

@michellesanver bower.json 
 
 


Slide 61

Slide 61 text

@michellesanver Updating Libraries bower update bootstrap

Slide 62

Slide 62 text

@michellesanver No more .zip files \o/

Slide 63

Slide 63 text

@michellesanver Gulp

Slide 64

Slide 64 text

@michellesanver Gulp Task Runner

Slide 65

Slide 65 text

@michellesanver Gulp Gulp vs. Grunt

Slide 66

Slide 66 text

@michellesanver Gulp vs .Grunt Grunt is config based

Slide 67

Slide 67 text

@michellesanver Gulp. vs Grunt Gulp is module based

Slide 68

Slide 68 text

@michellesanver Gulp: Out of the box Task, Watch, Src, Dest.

Slide 69

Slide 69 text

@michellesanver Gulp: Out of the box gulp.task()

Slide 70

Slide 70 text

@michellesanver Gulp: Out of the box gulp.watch()

Slide 71

Slide 71 text

@michellesanver Gulp: Out of the box gulp.src()

Slide 72

Slide 72 text

@michellesanver Gulp: Out of the box gulp.dest()

Slide 73

Slide 73 text

@michellesanver Default Task is automatic

Slide 74

Slide 74 text

@michellesanver Gulp pipe()

Slide 75

Slide 75 text

@michellesanver Virtual file system and streaming

Slide 76

Slide 76 text

@michellesanver Virtual file system and streaming vinylfs

Slide 77

Slide 77 text

@michellesanver Virtual file system and streaming Multi-pipe without temporary files!

Slide 78

Slide 78 text

@michellesanver Installation is just like bower Gulp

Slide 79

Slide 79 text

@michellesanver Gulp npm install -g gulp

Slide 80

Slide 80 text

@michellesanver An example workflow

Slide 81

Slide 81 text

@michellesanver An example workflow A simple PHP application with generated templates

Slide 82

Slide 82 text

@michellesanver An example workflow • Find all the files being used • Minify them • Concat them • Save them • Replace the references in our templates

Slide 83

Slide 83 text

@michellesanver Plugins gulp-uglifyjs gulp-minify-css gulp-usemin

Slide 84

Slide 84 text

@michellesanver Installing Plugins npm install --save-dev gulp-usemin gulp-uglify gulp-minify-css

Slide 85

Slide 85 text

@michellesanver An example workflow gulp.src()

Slide 86

Slide 86 text

@michellesanver An example workflow uglifyjs and minify-css with concat options

Slide 87

Slide 87 text

@michellesanver An example workflow gulp.dest()

Slide 88

Slide 88 text

@michellesanver An example workflow usemin (replace)

Slide 89

Slide 89 text

@michellesanver Add directives 
 
 


Slide 90

Slide 90 text

@michellesanver Add directives 
 …
 usemin (replace)

Slide 91

Slide 91 text

@michellesanver Add directives 
 
 


Slide 92

Slide 92 text

@michellesanver Pull in modules var gulp = require('gulp');
 var usemin = require('gulp-usemin');
 var uglify = require('gulp-uglify');
 var minifyCss = require('gulp-minify-css');

Slide 93

Slide 93 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 94

Slide 94 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 95

Slide 95 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 96

Slide 96 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 97

Slide 97 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 98

Slide 98 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 99

Slide 99 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 100

Slide 100 text

@michellesanver Define our default task gulp.task('default', function() {
 gulp.src('src/templates/layout.src.tpl')
 .pipe(usemin({
 assetsDir: 'public',
 css: [minifyCss(), 'concat'],
 js: [uglify(), 'concat']
 }))
 .pipe(gulp.dest('public'));
 });

Slide 101

Slide 101 text

@michellesanver Running gulp $ gulp [09:11:05] Using gulpfile /path/to/gulpfile.js [09:11:05] Starting 'default'... [09:11:07] Finished 'default' after 2.01 s

Slide 102

Slide 102 text

@michellesanver Let’s dig deeper!

Slide 103

Slide 103 text

@michellesanver Cleaning up our template fix-template task

Slide 104

Slide 104 text

@michellesanver Cleaning up our template var rename = require('gulp-rename');
 var rimraf = require('del');
 
 gulp.task('fix-template', ['minify'], function() { return gulp.src('public/layout.src.tpl')
 pipe(del())
 pipe(rename("layout.tpl"))
 pipe(gulp.dest('src/templates'));
 });

Slide 105

Slide 105 text

@michellesanver Task Dependency Rename default to minify

Slide 106

Slide 106 text

@michellesanver Task Dependency gulp.task('fix-template', ['minify'], function() {

Slide 107

Slide 107 text

@michellesanver Task Dependency $ gulp fix-template [16:48:29] Using gulp file /path/to/gulpfile.js [16:48:29] Starting 'minify'... [16:48:29] Finished 'minify' after 44 ms [16:48:29] Starting 'fix-template'... [16:48:29] Finished 'fix-template' after 6.14 ms

Slide 108

Slide 108 text

@michellesanver Task Dependency Still doesn’t work

Slide 109

Slide 109 text

@michellesanver Task Dependency gulp.task('minify', function() {
 return gulp.src('src/templates/layout.src.tpl')

Slide 110

Slide 110 text

@michellesanver Task Dependency gulp.task('default', ['fix-template']);

Slide 111

Slide 111 text

@michellesanver Task Dependency gulp.task('default', ['minify', 'fix- template']);

Slide 112

Slide 112 text

@michellesanver Moving Stuff Bootstrap Fonts

Slide 113

Slide 113 text

@michellesanver Moving Stuff ../fonts.

Slide 114

Slide 114 text

@michellesanver Moving Stuff gulp-replace

Slide 115

Slide 115 text

@michellesanver Moving Stuff var replace = require('gulp-replace');
 
 gulp.task('fix-paths', ['minify'], function() {
 gulp.src('public/css/site.css')
 .pipe(replace('../', '../bower_components/ bootstrap/dist/'))
 .pipe(gulp.dest('public/css'));
 });

Slide 116

Slide 116 text

@michellesanver Moving Stuff Add the task to default

Slide 117

Slide 117 text

@michellesanver Moving Stuff gulp.task('default', ['minify', 'fix- template', 'fix-paths']);

Slide 118

Slide 118 text

@michellesanver Automatisation: Watch gulp.watch

Slide 119

Slide 119 text

@michellesanver Automatisation: Watch gulp.task('watch', ['default'], function() {
 var watchFiles = [
 'src/templates/layout.src.tpl',
 'public/bower_components/*/dist/js/*.js',
 '!public/bower_components/*/dist/js/*.min.js',
 'public/bower_components/*/dist/*.js',
 'public/bower_components/*/dist/css/*.css',
 '!public/bower_components/*/dist/css/*.min.css',
 'public/bower_components/*/dist/font/*'
 ];
 
 gulp.watch(watchFiles, ['default']);
 });

Slide 120

Slide 120 text

@michellesanver Automatisation: Watch $ gulp watch [23:05:01] Using gulpfile /path/to/gulpfile.js [23:05:01] Starting 'watch'... [23:05:01] Finished 'watch' after 30 ms

Slide 121

Slide 121 text

@michellesanver Automatisation: Watch Run on startup

Slide 122

Slide 122 text

@michellesanver Automatisation: Watch gulp.task('watch', ['default'], function() {

Slide 123

Slide 123 text

@michellesanver Automating the Automation Too much requires!

Slide 124

Slide 124 text

@michellesanver Automating the Automation gulp-load-plugins

Slide 125

Slide 125 text

@michellesanver Automating the Automation $ = require('gulp-load-plugins')();

Slide 126

Slide 126 text

@michellesanver Automating the Automation $.

Slide 127

Slide 127 text

@michellesanver Automating the Automation gulp-usemin -> $.usemin

Slide 128

Slide 128 text

@michellesanver Gulp + Bower in Symfony

Slide 129

Slide 129 text

@michellesanver OmNomHub: A real example

Slide 130

Slide 130 text

@michellesanver Bower.json in OmNomHub { "name": "OmNomHub", "dependencies": { "bootstrap-sass": "~3.0.2" }

Slide 131

Slide 131 text

@michellesanver Let’s look at our gulp file! Requiring modules

Slide 132

Slide 132 text

@michellesanver Let’s look at our gulp file! var gulp = require('gulp'); var sass = require('gulp-sass'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var cssmin = require('gulp-cssmin');

Slide 133

Slide 133 text

@michellesanver Let’s look at our gulp file! SASS Task

Slide 134

Slide 134 text

@michellesanver Let’s look at our gulp file! gulp.task('sass', function() { gulp.src('src/Omnomhub/Bundle/ MainBundle/Resources/sass/*.scss') .pipe(sass()) .pipe(cssmin()) .pipe(gulp.dest('web/css/')); });

Slide 135

Slide 135 text

@michellesanver Let’s look at our gulp file! Move compiled .CSS files

Slide 136

Slide 136 text

@michellesanver Let’s look at our gulp file! .pipe(gulp.dest('web/css/'));

Slide 137

Slide 137 text

@michellesanver Let’s look at our gulp file! JavaScript

Slide 138

Slide 138 text

@michellesanver Gulp: JavaScript gulp.task('bootstrapjs', function() { gulp.src([ 'bower_components/bootstrap-sass/js/transition.js', … 'bootstrap-sass/js/affix.js' ]) .pipe(concat('bootstrap.js')) .pipe(uglify()) .pipe(gulp.dest('web/js/')); });

Slide 139

Slide 139 text

@michellesanver Let’s look at our gulp file! List all the files

Slide 140

Slide 140 text

@michellesanver Let’s look at our gulp file! gulp.src([ ‘bower_components/bootstrap-sass/js/transition.js', 'bower_components/bootstrap-sass/js/alert.js', 'bower_components/bootstrap-sass/js/button.js', 'bower_components/bootstrap-sass/js/carousel.js', … 'bootstrap-sass/js/affix.js' ])

Slide 141

Slide 141 text

@michellesanver Let’s look at our gulp file! Concatenate them

Slide 142

Slide 142 text

@michellesanver Let’s look at our gulp file! .pipe(concat('bootstrap.js'))

Slide 143

Slide 143 text

@michellesanver Let’s look at our gulp file! Uglify them

Slide 144

Slide 144 text

@michellesanver Let’s look at our gulp file! .pipe(uglify())

Slide 145

Slide 145 text

@michellesanver Let’s look at our gulp file! Put the result in web/js

Slide 146

Slide 146 text

@michellesanver Let’s look at our gulp file! .pipe(gulp.dest('web/js/'));

Slide 147

Slide 147 text

@michellesanver Let’s look at our gulp file! When you run “gulp” gulp.task('default', ['sass', 'bootstrapjs']);

Slide 148

Slide 148 text

Life After Assetic @michellesanver

Slide 149

Slide 149 text

@michellesanver Cleaner Twig No more tasks in the twig files

Slide 150

Slide 150 text

@michellesanver Faster workflow Node.js tools == asynchronous

Slide 151

Slide 151 text

@michellesanver More features Gulp and Node.JS have a lot of possibilities and modules.

Slide 152

Slide 152 text

@michellesanver No more manual .ZIP downloads Can’t believe it took this long.

Slide 153

Slide 153 text

@michellesanver Life After Assetic Third party assetic bundles?

Slide 154

Slide 154 text

@michellesanver Life After Assetic Will they use bower?

Slide 155

Slide 155 text

@michellesanver Life After Assetic Other bundles are popping up!

Slide 156

Slide 156 text

@michellesanver Life After Assetic Gassetic

Slide 157

Slide 157 text

Limitations and Wrapup @michellesanver

Slide 158

Slide 158 text

Assetic is dead @michellesanver Or at least is should be…

Slide 159

Slide 159 text

@michellesanver Thank you for listening! https://joind.in/12950

Slide 160

Slide 160 text

@michellesanver @frankdejonge is still not famous.

Slide 161

Slide 161 text

@michellesanver Bonus

Slide 162

Slide 162 text

@michellesanver BowerPHP

Slide 163

Slide 163 text

@michellesanver BowerPHP Alpha!

Slide 164

Slide 164 text

@michellesanver BowerPHP http://bowerphp.org