A Front End Developer’s Perspective on Twig

A Front End Developer’s Perspective on Twig

In web development, the process of transferring marked-up pages from front end to back end developers often poses certain difficulties.

Problems arise mostly when back end developers try to convert a markup into templates for their own needs.

Fortunately, today this kind of problem can be easily solved by means of MV* (MVC) Frameworks where the work with views is carried out only by front end developers.

But what shall we do when the project isn’t written in AngularJS or BackboneJS? For that, we came up with the solution to use Twig – a modern template engine for PHP programming (http://twig.sensiolabs.org). It is the most flexible, fast, and secure template engine for PHP.

One more issue I’d like to share, from my experience, lies in the way of testing the work result. Working with Twig, you have to launch a local server based on PHP by default. This might be very inconvenient for front end developers. Fortunately, there’s a solution for avoiding it. This can be accomplished with a combination of nodeJS (http://nodejs.org/) and task runner – gulpJS  (http://gulpjs.com).

Gulp and Yeoman Installations

In case you haven’t used nodeJS yet, you’ll have to install it on your computer. After the installation of nodeJS, you have to install gulp globally. This can be easily done – just write the following text in the command line:

$ npm install --global gulp

In addition, you’ll have to install Yeoman for further work (http://yeoman.io). It helps to make our webapp generation agile and high quality.

$ npm install -g yo

Project build up

The next step will be generating our project, where I suggest to use an open-source generator (https://github.com/yeoman/generator-gulp-webapp), that scaffolds out a front-end web app using http://gulpjs.com for the build process.

Install the generator:

$ npm install --global generator-gulp-webapp

And now run $ yo gulp-webapp to scaffold your webapp

Afterward, you have to deliver the application package https://www.npmjs.com/package/gulp-twig (https://www.npmjs.com/package/gulp-twig) based on twig.js. Twig.js is a pure JavaScript implementation of the Twig PHP templating language.

Twig Installation

This method demonstrates how to set upTwig as your HTML template engine:

1. Install

$ npm install gulp-twig --save

2. Create a views task

Add this task to your gulpfile.js, it will compile .twig files to .html files in .tmp:

var gulp = require('gulp');

gulp.task(‘twig’, function () {

‘use strict’;

var twig = require(‘gulp-twig’);

return gulp.src(‘./index.twig’)

.pipe(twig({

data: {

“title”: “Letzgro Web and Mobile Development”,

“hire_lezgro”: “hire Letzgro”,

“top_menu”:[

{“name”: “about”, “link”: “about”, “sub”: null},

{“name”: “services”, “link”: “services”, “sub”: null},

{“name”: “cloud”, “link”: “cloud”, “sub”: null},

{“name”: “mobile”, “link”: “mobile”,”sub”: null},

{“name”: “portfolios”, “link”: “portfolios”, “sub”: null},

{“name”: “blog”, “link”: “blog”,”sub”: null},

{“name”: “careers”, “link”: “careers”,”sub”: null}

]

}

}))

.pipe(gulp.dest(‘./’));

});

 

 

3. Add twig as a dependency of both html and connect

gulp.task('html', [‘twig’, 'styles'], function () {
...

gulp.task('connect', [‘twig’, 'styles', 'fonts'], function () {
...

4. Update other tasks

  • html

We want to parse the compiled HTML:

gulp.task('html', [twig, 'styles'], function () {
var assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

–  return gulp.src('app/*.html')
+  return gulp.src(['app/*.html', '.tmp/*.html'])
.pipe(assets)
.pipe($.if('*.js', $.uglify()))
.pipe($.if('*.css', $.csso()))
.pipe(assets.restore())
.pipe($.useref())
.pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true})))
.pipe(gulp.dest('dist'));
});

  • extras

We don’t want to copy over any .twig files in the build process:

gulp.task('extras', function () {
return gulp.src([
'app/*.*',
'!app/*.html',

+    '!app/*.twig
], {
dot: true
}).pipe(gulp.dest('dist'));
});

  • wiredep

Wiredep supports Twig:

gulp.task('wiredep', function () {
var wiredep = require('wiredep').stream;

gulp.src('app/styles/*.scss')
.pipe(wiredep({
ignorePath: /^(\.\.\/)+/
}))
.pipe(gulp.dest('app/styles'));

–  gulp.src('app/*.html')
+  gulp.src('app/layouts/*.twig')
.pipe(wiredep({
exclude: ['bootstrap-sass-official'],
ignorePath style="background-color: #FAFAFC;": /^(\.\.\/)*\.\./
}))
.pipe(gulp.dest('app/layouts'));
});

Assuming your wiredep comment blocks are in the layouts.

  • watch

Recompile Twig templates on each change and refresh the browser after an HTML file is compiled:

gulp.task('watch', ['connect'], function () {
var server = $.livereload();

// watch for changes
gulp.watch([
'app/*.html',

+    '.tmp/*.html',
'.tmp/styles/**/*.css',
'app/scripts/**/*.js',
'app/images/**/*'
]).on('change', function (file) {
server.changed(file.path);
});

+  gulp.watch('app/**/*.twig', ['views']);
gulp.watch('app/styles/**/*.scss', ['styles']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});

5. Rewrite index.html as layout.twig + index.twig. For example:

<div class=”col-md-9 white-shadow”>

<ul class=”col-md-7″>

{% for item in top_menu %}

<li> <a href=”{{ item.link }}”>{{item.name}}</a> </li>

{% endfor %}

</ul>

<div class=”col-md-5 right-box”>

<a href=”#” class=”button hire-lezgro”>

<span>{{ hire_lezgro }}</span>

</a>

</div>

</div>

There should be no problems at this stage and we would get a markup during compilation process that can be checked.

Data extraction from the json file

Frankly speaking, I didn’t want to keep all the data in gulpfile.js. So, I decided to transfer the whole script separately into a json file.

{

“title”: “Letzgro Web and Mobile Development”,

“hire_lezgro”: “hire Letzgro”,

“top_menu”:[

{“name”: “about”, “link”: “about”, “sub”: null},

{“name”: “services”, “link”: “services”, “sub”: null},

{“name”: “cloud”, “link”: “cloud”, “sub”: null},

{“name”: “mobile”, “link”: “mobile”,”sub”: null},

{“name”: “portfolios”, “link”: “portfolios”, “sub”: null},

{“name”: “blog”, “link”: “blog”,”sub”: null},

{“name”: “careers”, “link”: “careers”,”sub”: null}

]

}

To do this, I installed gulp-data (https://www.npmjs.com/package/gulp-data) and node.js path module (https://www.npmjs.com/package/path).

First, install gulp-data as a development dependency:

$ npm install --save gulp-data

and nodeJS path module

$ npm install --save path

Then, add it to your gulpfile.js:

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

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

var path = require('path');

Thus, I obtained a twig template and a separate json file with data. To maintain a good file structure, I give them the same names.

webapp
└── app
├── fixtures
│   └── index.json├── views
│   └── layout.twig└── index.twig 

I also changed the following lines in gulpfile.js:

gulp.task(‘twig’, function () {

return gulp.src(‘app/*.twig’)

.pipe(data(function(file) {

return require(‘./app/fixtures/’ + path.basename(file.path, ‘.twig’) + ‘.json’);

}))

.pipe(twig())

.pipe(gulp.dest(‘.tmp’));

});

Following these steps we gain a compiled markup.

<div class=”col-md-9 white-shadow”>

<ul class=”col-md-7″>

<li> <a href=”about”>about</a> </li>

<li> <a href=”services”>services</a> </li>

<li> <a href=”cloud”>cloud</a> </li>

<li> <a href=”mobile”>mobile</a> </li>

<li> <a href=”portfolios”>portfolios</a> </li>

<li> <a href=”blog”>blog</a> </li>

<li> <a href=”careers”>careers</a> </li>

</ul>

<div class=”col-md-5 right-box”>

<a href=”#” class=”button hire-lezgro”>

<span>hire Letzgro</span>

</a>

</div>

</div>

 

Go ahead and test it. It’s one of the easiest ways to work without PHP. In addition, we gain live reload during the work which is very convenient because there’s no need to reload the web page manually.

About the Author

grabovskyi-avatar-538424438-0Mykhailo Graboskyi

Senior Frontend Developer / Team Lead at Letzgro

Related Posts

1 COMMENTS

  1. Bruno Wego
    June 12, 2015 00:07

    Really nice tutorial. Congrats!

Leave a reply