Front End Development with Gulp, Twig, and SCSS
Gulp can help boost your front-end project productivity. It includes running, compiling, and automating tasks that usually take repetitive work.
Gulp, Twig, and SCSS are the highlights of this story. I'm writing the story down for projects that use these tools. This is part of my HTML and SCSS development series.
Building on top of NodeJS and NPM ecosystem, Gulp gaining popularity among front-end developers. Gulp is a streaming task runner that involved automating and optimizing your project. When your projects get very big and difficult to maintain, Gulp eases you with helpful and handy tasks built-in. For example, splitting your project file into smaller chunks and modular will save time on your production.
Twig is a modern templating engine for PHP language, but it also could be used outside of PHP language itself and basic HTML tag-based.
SASS is completely compatible with all versions of CSS. SCSS files are a part of SASS syntax that is compiled to generate the CSS and which they have their slogan “CSS with superpowers”.
Getting Started
I assume you are already familiar with NodeJS and the first thing we are going to install is the node modules package that is necessary for this project. List all the packages and install them manually for the Gulp environment below:
$ npm install browser-sync gulp gulp-autoprefixer gulp-concat gulp-data gulp-plumber gulp-sass gulp-sourcemaps gulp-twig gulp-watch
Highlights
gulp-autoprefixer
: gulp cross-browser tool for autoprefixer css property.gulp-concat
: for concatenate files by directory.gulp-data
: for attaching data to the file object for other plugins to consume, in this case, our HTML from the Twig templating system.gulp-plumber
: for restarting the gulp stream if an error occurs.gulp-sass
: for our CSS preprocessor written in SASS lang.gulp-sourcemaps
: for source mapping of our source codes in the dev tool.gulp-twig
: for our HTML templating system from sensiolabs.org.gulp-watch
: for watching file changes and emit events if occur.
This command will set up our Gulp projects all with the dependencies, or you can add the project dependencies in the package.json file at the document root.
{
"name": "gulp-twig-scss",
"version": "1.0.0",
"description": "Frontend development using Gulp, Twig and SCSS",
"main": "gulpfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/dyarfi/gulp-twig-scss"
},
"keywords": [
"twig",
"gulp",
"HTML",
"frontend",
"SCSS"
],
"author": "Dykraf",
"license": "ISC",
"homepage": "https://dykraf.com",
"dependencies": {
"browser-sync": "^2.26.3",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^6.0.0",
"gulp-concat": "^2.6.1",
"gulp-data": "^1.3.1",
"gulp-plumber": "^1.2.0",
"gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.4",
"gulp-twig": "^1.2.0",
"gulp-watch": "^5.0.1"
}
}
Or you could just clone the project and run npm install
to get started.
Creating a project directories root structure:
— project_root/
— — build/
— — — assets/
— — — — css/
— — — — — main.css
— — — — js/
— — — — — script.js
— — client/
— — — data/
— — — — index.twig.json
— — — templates/
— — — — index.twig
— — — — blocks/
— — — — — block-main-top.twig
— — — — — block-main-bottom.twig
— — — — includes/
— — — — — footer.twig
— — — — — head.twig
— — — — —header.twig
— — — — — scripts.twig
— — — — —styles.twig
— — — — layouts/
— — — — — default.twig
— — gulpfile.js
— — node_modules/
— — package.json
— — scss/
— — — vendors/
— — — — bootstrap/
— — — — — bootstrap.scss
— — — — main.scss
Create a gulpfile.js
in the project root and add these Gulp file setting for the project:
/*global require*/
"use strict";var gulp = require('gulp'),
path = require('path'),
data = require('gulp-data'),
twig = require('gulp-twig'), // Decided to use twig instead of pug, because already familiar with it
prefix = require('gulp-autoprefixer'),
sass = require('gulp-sass'),
plumber = require('gulp-plumber'),
concat = require('gulp-concat'),
sourcemaps = require('gulp-sourcemaps'),
browserSync = require('browser-sync'),
fs = require('fs');/*
* Directories here
*/var paths = {
build: './build/',
sass: './scss/',
css: './build/assets/css/',
data: './client/data/'
};/**
* Compile .twig files and pass data from json file
* matching file name. index.twig - index.twig.json into HTMLs
*/gulp.task('twig', function () {
return gulp.src(['./client/templates/*.twig'])
// Stay live and reload on error
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe(data(function (file) {
return JSON.parse(fs.readFileSync(paths.data +
path.basename(file.path) + '.json'));
}))
.pipe(twig())
.on('error', function (err) {
process.stderr.write(err.message + '\n');
this.emit('end');
})
.pipe(gulp.dest(paths.build));
});/**
* Recompile .twig files and live reload the browser
*/gulp.task('rebuild', ['twig'], function () {
// BrowserSync Reload
browserSync.reload();
});/**
* Wait for twig, js and sass tasks, then launch the browser-sync Server
*/gulp.task('browser-sync', ['sass', 'twig', 'js'], function () {
browserSync({
server: {
baseDir: paths.build
},
notify: false,
browser:"google chrome"
});
});/**
* Compile .scss files into build css directory With autoprefixer no
* need for vendor prefixes then live reload the browser.
*/gulp.task('sass', function () {
return gulp.src(paths.sass + 'vendors/main.scss')
.pipe(sourcemaps.init())
// Stay live and reload on error
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe(
sass({
includePaths: [paths.sass + 'vendors/'],
outputStyle: 'expanded'
}).on('error', function (err) {
console.log(err.message);
this.emit('end');
})
)
.pipe(prefix(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], {
cascade: true
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.css));
});/**
* Compile .js files into build js directory With app.min.js
*/gulp.task('js', function(){
return gulp.src('build/assets/js/script.js')
.pipe(sourcemaps.init())
.pipe(concat('script.min.js'))
.on('error', function (err) {
console.log(err.toString());
this.emit('end');
})
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('build/assets/js'));
});/**
* Watch scss files for changes & recompile
* Watch .twig files run twig-rebuild then reload BrowserSync
*/gulp.task('watch', function () {
gulp.watch(paths.build + 'assets/js/script.js', ['js', browserSync.reload]);
gulp.watch(paths.sass + 'vendors/main.scss', ['sass', browserSync.reload]);
gulp.watch([
'client/templates/**/*.twig',
'client/data/**/*.twig.json'
],
{cwd:'./'},
['rebuild']);
});// Build task compile sass and twig.
gulp.task('build', ['sass', 'twig']);/**
* Default task, running just `gulp` will compile the sass,
* compile the project site, launch BrowserSync then watch
* files for changes
*/
gulp.task('default', ['browser-sync', 'watch']);
SCSS files
Vendors
./scss/vendors/main.scss will be compile into ./build/assets/css/main.css
We can include SCSS library such as Bootstrap SCSS in our project by imports on the main.scss:
// ****** Our base variables ******* //$font-family-base : 'Raleway', sans-serif;
$font-family-head-base : 'Nothing You Could Do', cursive; // Custom
$font-family-lead-base : 'Montserrat', sans-serif; // Custom// Font Weight Base
$font-weight-light: 100 !default;
$font-weight-normal: 500 !default;
$font-weight-bold: 700 !default;@import "_variables"; // --- Vendors Variables
@import "bootstrap/bootstrap"; // --- Vendors Bootstrap 4
Twig templates
Layouts
./client/templates/layouts/default.twig
<!doctype html>
<html lang="zxx">
<head>
{% include "../includes/head.twig" %}
</head>
<body>
<!-- HEADER -->
{% include "../includes/header.twig" %}
<!-- MAIN -->
<main>
{% block content %} {% endblock %}
</main>
<!-- FOOTER -->
{% include "../includes/footer.twig" %}
<!-- SCRIPTS -->
{% include "../includes/scripts.twig" %}</body>
</html>
Include Tags
./client/templates/includes/head.twig
<title>{{ title }}</title>
{% include "../includes/styles.twig" %}
./client/templates/includes/styles.twig
<!-- fonts.googleapis.com/css -->
<style>@import url('https://fonts.googleapis.com/css?family=Nothing+You+Could+Do%7CRaleway:100,200,300,400,500,600,700,800,900%7CMontserrat:100,200,300,400,500,600,700,800,900');</style> <!-- main.css -->
<link rel="stylesheet" href="assets/css/main.css">
./client/templates/includes/header.twig
<header>
<!-- insert your header here -->
</header>
./client/templates/includes/footer.twig
<footer>
<!-- insert your footer here -->
</footer>
HTML Blocks
./client/templates/blocks/block-main-top.twig
<!-- insert your top html blocks here -->
./client/templates/blocks/block-main-bottom.twig
<!-- insert your bottom html blocks here -->
Index HTML Page
./client/templates/index.twig
{% extends "layouts/default.twig" %}{% block content %} <!-- =============== Block Main Top =============== -->
{% include 'blocks/block-main-top.twig' %} <div class="container">
<div class="col-lg-7 text-center mx-auto border border-warning py-4 px-5 my-5">
<h1 class="display-1 text-warning">Gulp, Twig and SCSS</h1>
<span class="text-secondary">{{description}}</span>
</div>
</div> <!-- =============== Block Main Bottom =============== -->
{% include 'blocks/block-main-bottom.twig' %}{% endblock %}
Json Data for index page
./client/data/index.twig.json will be directly injected and processed into our HTML tags, this will be done by Gulp on gulp-data
section, see thegulpfile.js
for more information.
{
"title":"Web title page",
"description":"A Gulp setup by <a href=\"https://github.com/dyarfi\">@dyarfi</a>"
}
After the setup you can begin the project by typing $ gulp
in your terminal at the project root and Gulp will watch and compile all the files.
Gulp will open up a browser automatically in this case “chrome browser” just like in the “browser-sync” gulpfile.js setting.
The development workflow is to create HTML pages with the .twig template pages inside the client/templates/ folder and then create the JSON data twig file on each created twig page in the client/data/ folder. All *.twig.json and *.twig files created will be processed and automatically reload and produces the HTML pages in the build/ folder that Gulp serves.
Gulp will automatically reload browser if there is any changes on the .twig, .json, .scss, and .js files and build/assets/ folders. All your final HTML project production ready will be all compiled in ./build/ directory.
Live preview on the project how Gulp builds all the files.
You can see the whole project here https://github.com/dyarfi/gulp-twig-scss
Cheers and happy coding!
[Updated: 01–14–2019]: The complete HTML pages project link or preview
[Updated: 24–04–2020]: Add link for upgrading Gulp 3 to Gulp 4 workflow