Hugo + Gulp
←Hugo
Сложность использования Hugo в связке с Gulp в том, что нам нужно выполнять два процесса watch для наблюдения за изменениями файлов и автоматической сборки (компиляции) файлов сайта:
- Gulp следит за файлами Sass
*.scssи компилирует их в CSS (а также минифицирует, добавляет source maps и т.п.), плюс аналогично обрабатывает JavaScript файлы, собирает спрайты, оптимизирует изображения; - Hugo следит за готовыми файлами
*.cssи контентом сайта и собирает их в готовый статичный сайт.
Кроме того, и Gulp, и Hugo умеют запускать LiveReload сервер, который показывает сайт в браузере и автоматически обновляет окно браузера при изменениях на сайте.
Но делают все это они каждый по-своему, а нам нужно объединить оба процесса.
Установите Gulp:
npm init --yes bower init bower install --save bootstrap-sass cp bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss src/sass/ npm install --save-dev gulp gulp-sass gulp-autoprefixer gulp-uglify gulp-rigger gulp-sourcemaps gulp.spritesmith gulp-plumber gulp-watch browser-sync child_process run-sequence del
Замечание: последнюю команду можно выполнить в сокращенном виде npm install --save-dev, если предварительно положить в корневую директорию проекта файл gulpfile.js с инициализацией нужных пакетов, на основе которого команда npm init --yes сформирует файл package.json с перечнем пакетов.
Установите Hugo:
hugo new site --format yaml --force .
Добавьте в config.yaml:
publishdir = "html"
Разберемся c директориями:
src— директорииsass,js,sprite,fonts. Здесь вручную редактируются файлы Sass, JavaScript и изображений, а затем обрабатываются Gulp'ом и в обработанном виде складываются в директориюstatic.
static— директорииcss,img,js,fonts— сюда Gulp кладет обработанные файлы, а затем их использует Hugo при сборке статичного сайта.layouts— шаблоны сайта для Hugo.content— файлы сайта для Hugo: страницы в виде файлов.mdи разделы сайта в виде директорий.
html— готовый статичный сайт. Hugo берет содержимое папокstatic,layoutsиcontentи собирает сайт в папкуhtml.
В процессе работы над сайтом нам нужно:
- Наблюдать за директорией
srcи собирать Gulp'ом в директориюstatic - Наблюдать за директориями
static,layoutsиcontentи делать:run_hugo— собирать сайт в папкуhtmllivereload— обновить окно браузера
С помощью этого gulpfile.js работа над проектом Hugo сводится к запуску в корне проекта команды gulp, после которой начинается магия: сначала очищается папка html, затем компилируются CSS и JS, запускается hugo и сразу собирает html-файлы сайта, затем запускается сервер BrowserSync и в браузере на порту 3131 открывает локальный хост проекта (должен быть создан в Apache), после чего запускается процесс watch — наблюдение за изменяемыми файлами в проекте и автоматическая сборка проекта и обновление окна браузера.
Иногда, если Hugo выдает ошибки, бывает полезно прервать gulp по команде Ctrl-C, очистить html-файлы командой gulp clear и затем запустить hugo, чтобы посмотреть более подробно, какую именно ошибку он возвращает.
'use strict';
var gulp = require('gulp');
var sass = require('gulp-sass');
var prefixer = require('gulp-autoprefixer');
var uglify = require('gulp-uglify');
var rigger = require('gulp-rigger');
var sourcemaps = require('gulp-sourcemaps');
var spritesmith = require('gulp.spritesmith');
var plumber = require('gulp-plumber');
var watch = require('gulp-watch');
var browserSync = require('browser-sync').create();
var exec = require('child_process').execSync;
var runSequence = require('run-sequence').use(gulp); // Последовательное выполнение задач
var del = require('del');
// var reload = browserSync.reload;
var reload_timeout = null;
function reload() {
if(reload_timeout) {
return;
}
reload_timeout = setTimeout(function() {
browserSync.reload();
reload_timeout = null;
}, 0);
}
var rootDir = process.cwd();
var hugoDir = rootDir + '/hugo';
var srcDir = rootDir + '/src';
var htmlDir = rootDir + '/html';
var staticDir = rootDir + '/static';
var path = {
src: { // Где брать исходники
style: srcDir + '/sass/style.scss',
sprite: srcDir + '/sprite/*.png',
js: srcDir + '/js/main.js',
img: srcDir + '/img/**/*.{png,gif,jpg,jpeg}',
fonts: srcDir + '/fonts/**/*.otf',
},
static: { // Куда складывать после сборки готовые файлы для Gulp
style: staticDir + '/css/',
sprite: staticDir + '/img/',
js: staticDir + '/js/',
img: staticDir + '/img/',
fonts: staticDir + '/fonts/',
},
watch: { // За изменением каких файлов будем наблюдать
src_style: srcDir + '/sass/**/*.scss',
src_js: srcDir + '/js/**/*.js',
src_sprite: srcDir + '/sprite/**/*.png',
// hugo: hugoDir + '/(static|layouts)/**/*',
hugo_config: rootDir + '/config.yaml',
hugo_layouts: hugoDir + '/layouts/**/*',
hugo_static: rootDir + '/static/**/*',
hugo_content: rootDir + '/content/**/*',
public_html: htmlDir + '/**/*.html',
public_css: htmlDir + '/css/*.css',
public_js: htmlDir + '/js/*.js',
public_img: htmlDir + '/img/**/*.{png,gif,jpg,jpeg}',
public_fonts: htmlDir + '/fonts/**/*.otf',
}
};
// console.log(path); // Вывести список всех путей
// Компилирование Sass в CSS
gulp.task('style', function () {
return gulp.src(path.src.style) // Возьмем наш основной Sass файл 'style.scss'
.pipe(sourcemaps.init()) // Инициализируем SourceMap
.pipe(sass({ // Скомпилируем Sass в CSS
includePaths: [ // Включим папки для поиска файлов Bootstrap
rootDir + '/src/sass/',
rootDir + '/bower_components/bootstrap-sass/assets/stylesheets/',
],
// outputStyle: 'compressed', // Минифицируем CSS
}))
.pipe(prefixer({ // Добавим вендорные префиксы
browsers: [
'last 2 versions',
'> 1%'
]
}))
// .pipe(sourcemaps.write()) // Добавим SourceMap
.pipe(gulp.dest(path.static.style)) // Положим готовый 'style.css' в build
});
// Сборка JavaScript файлов
gulp.task('js', function () {
return gulp.src(path.src.js) // Возьмем наш основной файл 'main.js'
.pipe(rigger()) // Включим в него все импортируемые файлы
.pipe(sourcemaps.init()) // Инициализируем SourceMap
.pipe(uglify()) // Сожмем полученный JS
.pipe(sourcemaps.write()) // Добавим SourceMap
.pipe(gulp.dest(path.static.js)) // Положим готовый 'main.js' в build
});
// Сборка CSS спрайтов
gulp.task('sprite', function () {
var spriteData = gulp.src(rootDir + '/src/sprite/*.png')
.pipe(spritesmith({
imgName: 'sprite.png',
cssName: 'sprite.css'
}));
spriteData.img.pipe(gulp.dest(path.static.img));
spriteData.css.pipe(gulp.dest(path.static.style));
return spriteData;
});
gulp.task('img', function() {
return gulp.src(path.src.img) // Возьмем наши файлы изображений
.pipe(gulp.dest(path.static.img)); // и положим в build
});
gulp.task('fonts', function() {
return gulp.src(path.src.fonts) // Возьмем файлы шрифтов
.pipe(gulp.dest(path.static.fonts)); // и положим в build
});
// gulp.task('copyfonts', function() {
// gulp.src('./bower_components/font-awesome/fonts/**/*.{ttf,woff,eof,svg}')
// .pipe(gulp.dest('./fonts'));
// });
// Сборка статичного сайта средствами Hugo
gulp.task('hugo', function() {
// process.chdir(hugoDir);
exec('hugo', {encoding: 'utf-8'});
// process.chdir(rootDir);
});
// Очистка папок static и html
gulp.task('clear', function() {
return del([htmlDir + '/*', path.static.style, path.static.js]).then(paths => {
// console.log('Deleted content of folders: \n' + htmlDir + '\n' + path.static.style + '\n' + path.static.js)
console.log('Deleted content of folders:');
console.log(' ' + htmlDir);
console.log(' ' + path.static.style);
console.log(' ' + path.static.js);
})
});
// Сборка проекта (запуск нескольких задач)
gulp.task('build', function() {
return runSequence([
// 'sprite',
// 'img',
// 'fonts',
'style',
'js'],
'hugo',
function() {console.log('Сборка сайта завершена.');}
);
});
// Отслеживание изменений файлов и запуск соответствующих задач
gulp.task('watch', function() {
watch([path.watch.src_style], function(event, cb) {
gulp.start('style');
});
watch([path.watch.src_js], function(event, cb) {
gulp.start('js');
});
watch([path.watch.src_sprite], function(event, cb) {
gulp.start('sprite');
});
// watch([path.watch.src_img], function(event, cb) {
// gulp.start('img');
// });
// watch([path.watch.hugo_static], function(event, cb) {
// gulp.start('hugo');
// });
watch([path.watch.hugo_config], function(event, cb) {
gulp.start('hugo');
});
watch([path.watch.hugo_layouts], function(event, cb) {
gulp.start('hugo');
});
watch([path.watch.hugo_content], function(event, cb) {
gulp.start('hugo');
});
});
// Автоматическое обновление окна браузера с помощью BrowserSync
gulp.task('live', function () {
browserSync.init({
open: 'external',
host: 'zina.design.dev',
proxy: "zina.design.dev",
});
gulp.watch([path.watch.public_html]).on("change", reload);
gulp.watch([path.watch.public_css]).on("change", reload);
gulp.watch([path.watch.public_js]).on("change", reload);
gulp.watch([path.watch.public_img]).on("change", reload);
gulp.watch([path.watch.public_fonts]).on("change", reload);
});
// Задача по умолчанию
gulp.task('default', function() {
// return runSequence('clean', ['sprite', 'img', 'fonts', 'style', 'js'], 'hugo', 'live', 'watch', function() {
// return runSequence('clear', ['img', 'fonts', 'style', 'js'], 'hugo', 'live', 'watch', function() {
return runSequence('clear', ['style', 'js'], 'hugo', 'live', 'watch', function() {
console.log('Сборка сайта завершена.\nВключено автоматическое обновление окна браузера.');
});
});