Optimising Your Front End Workflow With Symfony, Twig, Bower and Gulp
-
Upload
matthew-davis -
Category
Technology
-
view
9.430 -
download
1
description
Transcript of Optimising Your Front End Workflow With Symfony, Twig, Bower and Gulp
OPTIMISING YOURFRONT END
WORKFLOW
MATTHEW DAVIS
@mdavis1982
phpspec/nyan-formatters
PhpSpec
phpspec/nyan-formatters
PhpSpec
RAWWWR!
Terrible at jokes
Terrible at jokes
Sorry!
Advances in back end code
Advances in back end code
DDD
SOLIDPSR
CALISTHENICS
INTERFACESTDD
COMPOSITION
DRY
COMPOSER
When we look at front end code…
Cool tools for front end code
Cool tools for front end codeTWIG
GRUNT
GULPREQUIRE JS
BOWER ANGULAR
SASS
YEOMAN
LESS
COFFEE SCRIPT
And a GAZILLION* more
And a GAZILLION* more
*approximately
Lack of practical examples
😢
Let’s change that!
😄
Example Project
https://github.com/mdavis1982/workflow
Simple Article ManagementExample Project
https://github.com/mdavis1982/workflow
Simple Article ManagementExample Project
Administration Area
https://github.com/mdavis1982/workflow
Twig
Insanely powerful
Compiled and cachedInsanely powerful
Compiled and cachedInsanely powerful
Often overlooked
Translate all the things
Translations are notoriously messy
But it’s easy to keep them organised
framework: translator: { fallback: "%locale%" }
config.yml
/** * The title of the Article * * @var string * * @ORM\Column(type="string", length=255) * * @Assert\NotBlank(message="article.title.not_blank") * @Assert\Length( * max=255, * maxMessage="article.title.length.max" * ) */ protected $title;
Article.php
article: title: not_blank: You must enter a title length: max: The title cannot be longer than {{ limit }} characters content: not_blank: You must enter some content
validators.en.yml
$builder ->add( 'title', 'text', [ 'label' => 'article.label.title' ] )
ArticleType.php
$builder ->add( 'title', 'text', [ 'label' => 'article.label.title' ] )
ArticleType.php
For all properties in the form
article: label: title: Title content: Content submit: Save
forms.en.yml
forms.en.yml?!
/** * {@inheritdoc} */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults([ 'data_class' => 'MD\Entity\Article', 'translation_domain' => 'forms' ]); }
ArticleType.php
When your translations don’t work…
CLEAR THE CACHE!
CLEAR THE CACHE!
Even in the dev environment
Translate everything
Translate everythingAll titles, actions, single words
Translate everythingAll titles, actions, single words
Translations per ‘section’
article: title: list: All Articles create: Add a New Article action: create: Add New cancel: Cancel
admin.en.yml
{% block body %} <h1>{{ 'article.title.list'|trans({}, 'admin') }}</h1> {% if articles %} <ul class="articles"> {% for article in articles %} <li>{{ article.title }}</li> {% endfor %} </ul> {% endif %} <a href="{{ path('admin.article.create') }}”> {{ 'article.action.create'|trans({}, 'admin') }} </a> {% endblock body %}
list.html.twig
Messy
Template Inheritance
Default base template
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>{% block title %}Welcome!{% endblock %}</title> {% block stylesheets %}{% endblock %} <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" /> </head> <body> {% block body %}{% endblock %} {% block javascripts %}{% endblock %} </body> </html>
base.html.twig
Doesn’t promote great code
<!doctype html> <!--[if lt IE 7 ]> <html lang="en" class="no-js ie6 lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if IE 7 ]> <html lang="en" class="no-js ie7 lt-ie9 lt-ie8"> <![endif]--> <!--[if IE 8 ]> <html lang="en" class="no-js ie8 lt-ie9"> <![endif]--> <!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]--> <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"><!--<![endif]--> <head> <meta charset="utf-8" /> <title>{% block title %}{% endblock title %}</title> <!-- Set up mobile viewport for responsive design --> <meta name="viewport" content="width=device-width" /> {% block stylesheets %}{% endblock stylesheets %} </head> <body> {% block content %}{% endblock content %} {% block javascripts %}{% endblock javascripts %} </body> </html>
base.html.twig
Gives us a better foundation
The same HTML structure and assets per ‘section’?
New ‘Layouts’ Directory
Directory Structure
{% extends "::base.html.twig" %} {% block title %} {{ 'defaults.title'|trans({}, 'admin') }}{% endblock title %} {% block content %} {% block body %}{% endblock body %} {% endblock content %}
admin.html.twig
{% extends "::base.html.twig" %} {% block title %}{{ 'defaults.title'|trans }}{% endblock title %} {% block content %} {% block header %}{% endblock header %} {% block body %}{% endblock body %} {% block footer %}{% endblock footer %} {% endblock content %}
frontend.html.twig
What?!
Change the extends
{% extends "MDMainBundle:Layouts:admin.html.twig" %} {% block body %} <h1>{{ 'article.title.list'|trans({}, 'admin') }}</h1> {% if articles %} <ul class="articles"> {% for article in articles %} <li>{{ article.title }}</li> {% endfor %} </ul> {% endif %} <a href="{{ path('admin.article.create') }}”> {{ 'article.action.create'|trans({}, 'admin') }} </a> {% endblock body %}
list.html.twig
Given ourselves flexible base
All boilerplate code is DRYGiven ourselves flexible base
All boilerplate code is DRYGiven ourselves flexible base
Defaults per ‘section’
trans_default_domain
{% extends "MDMainBundle:Layouts:admin.html.twig" %} {% trans_default_domain "admin" %} {% block body %} <h1>{{ 'article.title.list'|trans }}</h1> {% if articles %} <ul class="articles"> {% for article in articles %} <li>{{ article.title }}</li> {% endfor %} </ul> {% endif %} <a href="{{ path('admin.article.create') }}”> {{ 'article.action.create'|trans }} </a> {% endblock body %}
list.html.twig
But wait!
{% trans_default_domain "admin" %}
admin.html.twig
NOPE
And it won’t be fixed
Node.js
http://nodejs.org
Server-side JavaScriptNode.js
http://nodejs.org
Server-side JavaScriptNode.js
Adds extra functionality
http://nodejs.org
npm
Composer for nodenpm
Composer for nodenpm
Install globally or into project
OMG!!1!
Bower
http://bower.io
Demo: Installing Bower With No Sudo - Eek!
👎
Demo: Installing Bower Successfully - Yay!
👍
Getting stuff into your project
Find dependencies
Demo: Using Bower To Search For Packages - Modernizr
Install dependencies
Demo: Using Bower To Install Packages - Modernizr
We can do better
.bowerrc
Demo: Using .bowerrc To Customise Installation Directory
Better
BetterSave dependencies
bower.json
Demo: Using Bower To Save Dependencies To bower.json
Don’t forget .gitignore
Easy to reference assets
{% block javascripts %}<script src="{{ asset('/vendor/modernizr/modernizr.js') }}"></script>
{% endblock javascripts %}
Easy to reference assets
{% block javascripts %}<script src="{{ asset('/vendor/modernizr/modernizr.js') }}"></script>
{% endblock javascripts %}
Easy to reference assets
Globally or per ‘section’
Different locations?
Non-standard install
Make it clearNon-standard install
Make it clearNon-standard install
Potentially more flexibility
Gulp
http://gulpjs.com
Build tool
“Every week someone who doesn’t understand Make writes a new build
system in JavaScript. #gruntjs #gearjs #gulpjs #broccolijs.
Laugh or cry? ”https://twitter.com/aslak_hellesoy/status/435506106496851968
Streaming
Plugin architecture
Demo: Installing Gulp Globally With npm
One extra step
Demo: Installing Gulp and Gulp-Util Into A Project With npm
Don’t forget .gitignore
Minify JavaScript
Demo: Using Gulp To Minify JavaScript
Use it in our project
{% block javascripts %} <script src="{{ asset('/web/js/vendor/modernizr.js') }}"></script> {% endblock javascripts %}
frontend.html.twig
ITCHY NOSE!!!
We have 2 copies in web/
We have 2 copies in web/Bower install to /assets/vendor
We have 2 copies in web/Bower install to /assets/vendor
Prevents source being public
(S)CSS
Normal SCSS workflow
@import "assets/vendor/normalize-scss/normalize"; $body-width: 60% !default; body { width: $body-width; margin: 0 auto; }
frontend.scss
var scss = require('gulp-sass');!!gulp.task('scss', function() { return gulp.src('assets/scss/*.scss') .pipe(scss()) .pipe(gulp.dest('web/css')); });
gulpfile.js
{% block stylesheets %} <link rel="stylesheet" href="{{ asset('/css/frontend.css') }}" /> {% endblock stylesheets %}
frontend.html.twig
matt at Chloe in ~/Sites/workflow.dev on dev *🍔 $ gulp scss[gulp] Using file /Users/matt/Sites/workflow.dev/gulpfile.js[gulp] Working directory changed to /Users/matt/Sites/workflow.dev[gulp] Running 'scss'...[gulp] Finished 'scss' in 11 ms
Running commands manually gets old real fast
Watching!
gulp.task('watch', function() { gulp.watch('assets/scss/**/*.scss', ['scss']); });
gulpfile.js
Demo: Gulp Watch In Action
Awesomesauce!
Only scratching the surface!
Gulp plugins
Gulp pluginsTWIG
COPY
GITBROWSERIFY
TESTS RENAME
CONCAT
OPTIMISE
LINT
NOTIFICATIONS
Custom actions are easy
Setting up a project can be tedious
Can be taken much further!
GAZILLIONS of tools available
GAZILLIONS of tools availableDon’t use all of them!
Plan it!
Plan it!
**groan**
Questions?
@mdavis1982Thanks!