I am a quite heavy gulp user and use it for all kind of stuff. I like to work with a /dist folder, where an optimized version of the website will get created. That version then will get uploaded to the server. I would like to automate this process further but at the moment git-ftp and all the other ftp solutions did not really work out for me.
However here are the highlights that might be different from others.
-
I use gulp-load-plugins
so you have an automated loader that makes the modules accessible via $.modulename
. If you remove something from your gulpfile you also donāt have to remove the "require āxyz;ā which is handy to keep everything free from legacy code.
-
I use libsass for the fast sass compiling (way faster then ruby-sass, which made me crazy)
-
Gulp-rev handles my cache busting. It generates a manifest.json file where the name mapping gets saved. I use that mapping to replace the <link src="">
with the appropriate css name of the cache busted version.
-
With gulp-rewrite I am doing some renaming so the <?php echo js('...') ?>
matches the cache busted file.
-
I added a image resize task so when I need test images and just have high resolution photos then I can just resize all of them to max 1920px in one swipe without the need of an external program or tool.
-
The images get optimized (progressive images) and adjusted in quality.
-
Via curl I generate a static index.html
from the webpage. The index.html then gets used by critical to create the above the fold css. The saved file then gets inlined with a little snippet that gets called in my header.php.
<?php
$filename = kirby()->roots()->assets() . DS . 'css' . DS . 'inline.css';
if (file_exists($filename))
{
echo '<style>';
echo (file_get_contents( $filename ));
echo '</style>';
}
?>
The Gulpfile:
'use strict';
var gulp = require('gulp'),
fs = require('fs'),
critical = require('critical');
// load plugins
var $ = require('gulp-load-plugins')({
pattern: '*',
rename: {
'gulp-gm': 'gm',
'run-sequence': 'runSequence',
'browserSync': 'browser-sync'
}
}
);
// preprocess sass
gulp.task('sass', function () {
return gulp.src('app/assets/css/*.scss')
.pipe($.sourcemaps.init())
.pipe($.sass({outputStyle: 'expanded'}).on('error', $.sass.logError))
.pipe($.sourcemaps.write())
.pipe(gulp.dest('app/assets/css/'));
});
// autoprefix styles and add hash for cache busting via gulp rev
gulp.task('styles', ['sass'], function() {
return gulp.src(['app/assets/css/*.css'])
.pipe($.csso())
.pipe($.autoprefixer({
browsers: ['last 2 versions'],
cascade: true
}))
.pipe($.buffer())
.pipe($.rev()) // use gulp-rev for cache busting
.pipe(gulp.dest('dist/assets/css'))
.pipe($.rev.manifest({
base: './',
}))
.pipe(gulp.dest('dist/'));
});
// minify and concat all scripts
gulp.task('scripts', ['defer'], function(){
return gulp.src('app/assets/scripts/*.js')
// .pipe($.jshint())
.pipe($.concat('vendor.js'))
.pipe(gulp.dest('./app/assets/scripts/vendor/'))
.pipe($.uglify())
.pipe($.rename('vendor.min.js'))
// .pipe($.jshint.reporter(require('jshint-stylish')))
.pipe(gulp.dest('./dist/assets/scripts/vendor/'))
.pipe($.size());
});
// minify and concat the scripts that can be loaded defered
gulp.task('defer', function(){
return gulp.src(['app/assets/scripts/defer/*.js', '!app/assets/scripts/defer/defer.js'])
.pipe($.concat('defer.js'))
.pipe(gulp.dest('./app/assets/scripts/defer/'))
.pipe($.uglify())
.pipe($.rename('defer.min.js'))
.pipe(gulp.dest('./dist/assets/scripts/defer/'))
.pipe($.size());
});
// adjust the javascript and css linking so they match their minified version (via regex)
// vendor.js => vendor.min.js
// defer.js => defer.min.js
// main.css => main.min.css
gulp.task('rewrite', function(){
var data = JSON.parse(fs.readFileSync('dist/rev-manifest.json', 'utf8'));
return gulp.src(['dist/site/patterns/footer/footer.html.php', 'dist/site/snippets/header.php'], { base: './' }) //must define base so I can overwrite the src file below. Per http://stackoverflow.com/questions/22418799/can-gulp-overwrite-all-src-files
.pipe($.if('**/footer.html.php', $.replace(/<\?php.*echo.*js\(\'assets\/scripts\/vendor\/vendor\.js\'\).*\?>/g, '<?php echo js(\"assets/scripts/vendor/vendor.min.js\") ?>')))
.pipe($.if('**/footer.html.php', $.replace(/<\?php.*echo.*js\(\'assets\/scripts\/defer\/defer\.js\'.*\).*\?>/g, '<?php echo js(\"assets/scripts/defer/defer.min.js\", true) ?>')))
.pipe($.if('**/header.php', $.replace(/<\?php.*echo.*css\(\'assets\/css\/main.css\'.*\).*\?>/g, '<?php echo css(\"assets/css/' + data["main.css"] + '\") ?>')))
.pipe(gulp.dest('./')); //Write the file back to the same spot.
});
// requires graphicsmagick http://www.graphicsmagick.org/download.html
// brew install graphicsmagick
gulp.task('imageResize', function() {
gulp.src(['app/assets/images/**/*.jpg', 'app/assets/images/**/*.png'])
.pipe($.gm(function (gmfile) {
return gmfile.resize(1920);
}))
.pipe(gulp.dest('dist/assets/images/'))
});
gulp.task('images', function () {
return gulp.src('app/assets/images/**/*')
.pipe($.size({title: 'Image size', showFiles: 'true'}))
.pipe($.cache($.imagemin({
optimizationLevel: 5,
progressive: true,
interlaced: true
})))
.pipe(gulp.dest('dist/assets/images'))
.pipe($.size({title: 'Image size after compression', showFiles: 'true'}));
});
gulp.task('copy', function () {
return gulp.src([
'app/**/*',
'!app/assets/scripts/custom.js',
'!app/assets/scripts/vendor/*',
'!app/assets/images/**/*.*',
'!app/assets/css/**/*',
],{
dot:true
}).pipe(gulp.dest('dist'))
.pipe($.size({title: 'Copy'}));
});
// generate index.html via curl for inlining the above the fold css
gulp.task('generate-index', function() {
return $.run('curl http://localhost/yourproject/dist/ > dist/index.html').exec()
.pipe(gulp.dest('output'));
})
// inline the above the fold
gulp.task('critical', ['generate-index'], function (cb) {
var data = JSON.parse(fs.readFileSync('dist/rev-manifest.json', 'utf8'));
critical.generate({
inline: false,
base: '.',
css: ['dist/assets/css/' + data['main.css']],
src: 'dist/index.html',
dest: 'dist/assets/css/inline.css',
minify: true,
width: 375,
height: 600
});
});
// Optimize web fonts
gulp.task('fonts', function () {
return gulp.src('app/assets/fonts/*')
.pipe($.filter('**/*.{eot,svg,ttf,woff}'))
.pipe($.flatten())
.pipe(gulp.dest('dist/assets/fonts'))
.pipe($.size());
});
// Clean dist Directory
gulp.task('clean', $.del.bind(null, ['dist']));
// Build Production Files, the Default Task
gulp.task('build', ['clean'], function (cb) {
$.runSequence(['styles', 'fonts', 'images', 'copy', 'scripts'], ['rewrite', 'critical'], cb);
});
gulp.task('default', function () {
console.log('Please choose npm run build or npm run serve');
});
gulp.task('open', ['styles', 'scripts'], function () {
require('opn')('http://localhost:9090');
});
gulp.task('dev', $.shell.task([
'php -S localhost:9090',
'echo "completed"'
],{
verbose: true
}));
gulp.task('watch', function() {
// watch for changes
gulp.watch([
'app/assets/css/**/*.css',
'app/assets/scripts/**/*.js',
'app/**/*.php'
]).on('change', $.browserSync.reload);
gulp.watch('app/assets/css/**/*.scss', ['sass']);
gulp.watch('app/assets/images/**/*', ['images']);
gulp.watch('app/assets/scripts/**/*.js', ['scripts']);
});
gulp.task('serve', function () {
$.browserSync({
proxy: "localhost/wunderwelten/app",
port: 8080
});
// watch for changes
gulp.watch([
'app/assets/css/*.css',
'app/assets/scripts/**/*.js',
'app/**/*.php'
]).on('change', $.browserSync.reload);
gulp.watch('app/assets/css/**/*.scss', ['sass']);
gulp.watch('app/assets/images/**/*', ['images']);
gulp.watch('app/assets/scripts/**/*.js', ['scripts']);
});