Slide 1

Slide 1 text

DEAL WITH LARAVEL ASSETS BY BOWER & GULP Jace Ju @ KKBOX

Slide 2

Slide 2 text

What problems in Laravel 4 assets?

Slide 3

Slide 3 text

No Built-in assets manager

Slide 4

Slide 4 text

No Dependency management

Slide 5

Slide 5 text

Twitter Bootstrap -> jQuery Backbone.js -> underscore.js

Slide 6

Slide 6 text

No Assets pre-compile & minify

Slide 7

Slide 7 text

No Changes watching & Live reload

Slide 8

Slide 8 text

No Packing & Revision

Slide 9

Slide 9 text

Where is better solution?

Slide 10

Slide 10 text

Bower + Gulp !!

Slide 11

Slide 11 text

Bower A package manager for the web http://bower.io/

Slide 12

Slide 12 text

Gulp The streaming build system http://gulpjs.com/

Slide 13

Slide 13 text

Quick Demo http://y2u.be/iTkM1LJcLsU

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

How to do this?

Slide 16

Slide 16 text

Install IO.JS (by Platform)

Slide 17

Slide 17 text

Install Bower & Gulp $ npm install -g bower gulp /usr/local/bin/gulp -> /usr/local/lib/node_modules/gulp/bin/gulp.js /usr/local/bin/bower -> /usr/local/lib/node_modules/bower/bin/bower ...

Slide 18

Slide 18 text

Create Laravel Project (4.2) $ laravel new project-name Crafting application... Application ready! Build something amazing.

Slide 19

Slide 19 text

Create custom assets

Slide 20

Slide 20 text

Create assets folders $ cd project-name $ mkdir -p assets/{scripts,styles,images,fonts} project-name ├── ... (laravel folders) └── assets ├── scripts ├── styles ├── images └── fonts

Slide 21

Slide 21 text

Create custom assets $ vi assets/styles/main.scss $ vi assets/scripts/index.js

Slide 22

Slide 22 text

Add bower support

Slide 23

Slide 23 text

Create bower.json $ bower init ? name: project-name ? version: 0.0.0 ? description: ? main file: ? what types of modules does this package expose?: ? keywords: ... ? Looks good?: Yes

Slide 24

Slide 24 text

bower.json $ cat bower.json { name: 'project-name', version: '0.0.0', authors: [ 'Author ' ], license: 'MIT', private: true, ignore: [ ... ] }

Slide 25

Slide 25 text

Create .bowerrc $ echo "/public/bower_components" >> .gitignore $ vi .bowerrc { "directory": "public/bower_components" }

Slide 26

Slide 26 text

Install package $ bower install --save bootstrap bower cached git://github.com/twbs/bootstrap.git#3.3.1 bower validate 3.3.1 against git://github.com/twbs/bootstrap.git#* bower cached git://github.com/jquery/jquery.git#2.1.3 ... bootstrap#3.3.1 bower_components/bootstrap └── jquery#2.1.3 jquery#2.1.3 bower_components/jquery

Slide 27

Slide 27 text

Inject assets

Slide 28

Slide 28 text

Create blade template $ mv app/views app/templates $ echo "/app/views" >> .gitignore $ vi app/templates/index.blade.php

Slide 29

Slide 29 text

Styles

Slide 30

Slide 30 text

Scripts

Slide 31

Slide 31 text

Rewrite route $ vi app/routes.php Route::get('/', function() { // render app/views/index.blade.php return View::make('index'); });

Slide 32

Slide 32 text

Node modules for tasks

Slide 33

Slide 33 text

Create package.json $ vi package.json { "name": "project-name", "private": true, "devDependencies": { }, "engines": { "node": ">=0.10.0" } }

Slide 34

Slide 34 text

Install node modules $ echo "/node_modules" >> .gitignore $ npm install --save-dev

Slide 35

Slide 35 text

Task tools gulp (3.8.10) The streaming build system gulp-load-plugins (0.8.0) Automatically load any gulp plugins in your package.json run-sequence (1.0.2) Run a series of dependent gulp tasks in order gulp-if (1.2.5) Conditionally run a task merge-stream (0.1.6) Create a stream that emits events from multiple other streams

Slide 36

Slide 36 text

File tools gulp-flatten (0.0.4) remove or replace relative path for files gulp-replace (0.5.0) A string replace plugin for gulp del (1.1.1) Delete files/folders using globs

Slide 37

Slide 37 text

Style tools gulp-ruby-sass (0.7.1) Compile Sass to CSS with Ruby Sass gulp-autoprefixer (1.0.1) Prefix CSS gulp-csso (0.2.9) Minify CSS with CSSO.

Slide 38

Slide 38 text

Script tools gulp-jshint (1.9.0) JSHint plugin for gulp jshint-stylish (1.0.0) Stylish reporter for JSHint gulp-uglify (1.0.2) Minify files with UglifyJS. uglify-save-license (0.4.1) License detector for UglifyJS

Slide 39

Slide 39 text

Image tools gulp-cache (0.1.11) A cache proxy task for Gulp gulp-imagemin (2.0.0) Minify PNG, JPEG, GIF and SVG images

Slide 40

Slide 40 text

Server tools gulp-livereload (3.0.2) Gulp plugin for livereload.

Slide 41

Slide 41 text

Assets tools gulp-useref (1.0.2) Parse build blocks in HTML files to replace references to non-optimized scripts or stylesheets. gulp-rev (2.0.1) Static asset revisioning by appending content hash to filenames gulp-rev-replace (0.3.1) Rewrite occurences of filenames which have been renamed by gulp-rev wiredep (2.2.2) Wire Bower dependencies to your source code.

Slide 42

Slide 42 text

Add gulp support

Slide 43

Slide 43 text

Create gulpfile.js $ vi gulpfile.js 'use strict'; // Load gulp and plug-ins var gulp = require('gulp'); var del = require('del'); var path = require('path'); var runSequence = require('run-sequence'); var $ = require('gulp-load-plugins')();

Slide 44

Slide 44 text

Common tasks for assets

Slide 45

Slide 45 text

Inject bower components gulp.task('wiredep', function() { var wiredep = require('wiredep').stream; return gulp.src('app/templates/**/*.blade.php') .pipe(wiredep({ ignorePath: '../../public/' })) .pipe(gulp.dest('app/views')); });

Slide 46

Slide 46 text

Before After

Slide 47

Slide 47 text

Pre-compile Sass files assets/styles/*.scss ! public/styles/*.css $ echo "/.sass-cache" >> .gitignore gulp.task('styles', function() { return gulp.src('assets/styles/*.scss') .pipe($.rubySass({ ... })) .pipe($.autoprefixer({ ... })) .pipe(gulp.dest('public/styles')); });

Slide 48

Slide 48 text

Check syntax and copy files assets/scripts/*.js ! public/scripts/*.js gulp.task('scripts', function() { return gulp.src('./assets/scripts/*.js') .pipe($.jshint('.jshintrc')) .pipe($.jshint.reporter('jshint-stylish')) .pipe(gulp.dest('public/scripts')); });

Slide 49

Slide 49 text

.jshintrc $ vi .jshintrc { "node": true, "esnext": true, "bitwise": true, ... "trailing": true, "smarttabs": true, "white": true } http://jshint.com/docs/

Slide 50

Slide 50 text

Optimize images assets/images/**/* ! public/images/ gulp.task('images', function() { return gulp.src('assets/images/**/*') .pipe($.cache($.imagemin({ ... }))) .pipe(gulp.dest('public/images')); });

Slide 51

Slide 51 text

Copy fonts assets/fonts/**/*.* ! public/fonts/ // Fonts gulp.task('fonts', function () { return gulp.src([ 'assets/fonts/*.{otf,eot,svg,ttf,woff}', 'public/bower_components/**/fonts/**/*.{otf,eot,svg,ttf,woff}' ]) .pipe($.flatten()) .pipe(gulp.dest('public/fonts')); });

Slide 52

Slide 52 text

Tasks for development

Slide 53

Slide 53 text

Clean temporary files // Clean gulp.task('clean:develop', function(cb) { del([ 'app/views', 'public/styles', 'public/scripts', '.sass-cache'], cb); });

Slide 54

Slide 54 text

Prepare for development gulp.task('prepare', function (cb) { runSequence( 'clean:develop', ['wiredep', 'styles', 'scripts', 'images', 'fonts'], cb); });

Slide 55

Slide 55 text

Start php built-in web server gulp.task('serve', function () { var spawn = require('child_process').spawn, child = spawn('php', [ 'artisan', 'serve' ], { cwd: process.cwd() }), log = function (data) { console.log(data.toString()) }, kill = function () { child.kill(); } child.stdout.on('data', log); child.stderr.on('data', log); process.on('exit', kill); process.on('uncaughtException', kill); });

Slide 56

Slide 56 text

Livereload when destination be changed gulp.task('livereload', function () { var server = $.livereload; server.listen(); gulp.watch([ 'app/views/**/*', 'public/**/*', '!public/bower_components/**/*', ]).on('change', server.changed); });

Slide 57

Slide 57 text

Watching changes of source gulp.task('watch', ['prepare'], function() { gulp.start('serve'); gulp.start('livereload'); gulp.watch('app/templates/**/*.php', ['wiredep']); gulp.watch('assets/styles/**/*.scss', ['styles']); gulp.watch('assets/scripts/**/*.js', ['scripts']); gulp.watch('assets/images/**/*', ['images']); });

Slide 58

Slide 58 text

Build tasks

Slide 59

Slide 59 text

Minify & Packing & Revision gulp.task('build', ['wiredep', 'styles', 'scripts', 'images', 'fonts'], function() { var assets = $.useref.assets({ searchPath: 'public' }); return gulp.src('app/views/**/*.blade.php') .pipe(assets) .pipe($.if('*.js', $.uglify())) .pipe($.if('*.css', $.csso())) .pipe($.rev()) .pipe(gulp.dest('public')) .pipe(assets.restore()) .pipe($.useref()) .pipe($.revReplace({ replaceInExtensions: ['.php'] })) .pipe(gulp.dest('app/views')); });

Slide 60

Slide 60 text

Packing Before After

Slide 61

Slide 61 text

Revision Before After

Slide 62

Slide 62 text

Default build gulp.task('clean', ['clean:develop', 'clean:cache'], function(cb) { del(['public/css', 'public/js', 'public/fonts', 'public/images'], cb); }); gulp.task('clean:temporary', function (cb) { del([ 'app/views/js', 'app/views/css', 'public/scripts', 'public/styles', '.sass-cache' ], cb); }); gulp.task('default', function(cb) { runSequence('clean', 'build', 'clean:temporary', cb); });

Slide 63

Slide 63 text

Ignore packages folder and compiled files $ vi .gitignore ... /app/views /public/bower_components /node_modules /public/styles /public/scripts /public/css /public/js /public/fonts /public/images /.sass-cache /.bundle Gemfile.lock

Slide 64

Slide 64 text

Laravel 4 Skeleton with Gulp # Save your time composer create-project jaceju/laragulp project-name -s dev

Slide 65

Slide 65 text

Laravel Elixir Beautiful Gulp tasks for your Laravel applications. https://github.com/laravel/elixir

Slide 66

Slide 66 text

Laracast http://goo.gl/gdNrcc

Slide 67

Slide 67 text

gulpfile.js elixir(function(mix) { mix.less('*.less') .stylesIn("public/css") .version('css/all.css'); });

Slide 68

Slide 68 text

In blade template from public/build/rev-manifest.json { "css/all.css": "css/all-602a38ff.css" }

Slide 69

Slide 69 text

Summary

Slide 70

Slide 70 text

• Automate all what machine can handle. • Separate develop flow and deploy flow. • DDIY, use third-party tools wisely and well. • This should be first step of your workflow.

Slide 71

Slide 71 text

No best practice, only better solution.

Slide 72

Slide 72 text

Q & A