Skip to content

Instantly share code, notes, and snippets.

@Bogdan808
Created February 2, 2018 08:32
Show Gist options
  • Save Bogdan808/c9c502ef28bcb6c82f932a07e1195e8a to your computer and use it in GitHub Desktop.
Save Bogdan808/c9c502ef28bcb6c82f932a07e1195e8a to your computer and use it in GitHub Desktop.
My new gulp
'use strict';
// Подключения зависимостей
const fs = require('fs');
const gulp = require('gulp');
const gulpSequence = require('gulp-sequence');
const browserSync = require('browser-sync').create();
const realFavicon = require ('gulp-real-favicon');
const postcss = require('gulp-postcss');
const autoprefixer = require("autoprefixer");
const mqpacker = require("css-mqpacker");
const atImport = require("postcss-import");
const cleanss = require('gulp-cleancss');
const inlineSVG = require('postcss-inline-svg');
const objectFitImages = require('postcss-object-fit-images');
const imageInliner = require('postcss-image-inliner');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const gulpIf = require('gulp-if');
const debug = require('gulp-debug');
const rename = require('gulp-rename');
const size = require('gulp-size');
const del = require('del');
const newer = require('gulp-newer');
// Получение настроек проекта из projectConfig.json
let projectConfig = require('./projectConfig.json');
let dirs = projectConfig.dirs;
let lists = getFilesList(projectConfig);
// console.log(lists);
// Получение адреса репозитория
let repoUrl = require('./package.json').repository.url.replace(/\.git$/g, '');
// console.log(repoUrl);
// Файл с настройками фавиконок
const faviconData = './faviconData.json';
// Сообщение, записываемое в стилевой файл
let styleFileMsg = '';
// Формирование и запись диспетчера подключений (style.scss), который компилируется в style.min.css
let styleImports = styleFileMsg;
lists.css.forEach(function(blockPath) {
styleImports += '<link rel="stylesheet" type="text/css" href="'+blockPath+'">\n';
});
styleImports = styleImports += styleFileMsg;
fs.writeFileSync(dirs.srcPath + 'blocks/cssincludes/cssincludes.pug', styleImports);
// Формирование и запись списка примесей (mixins.pug) со списком инклудов всех pug-файлов блоков
let pugMixins = '//- ВНИМАНИЕ! Этот файл генерируется автоматически. Не пишите сюда ничего вручную!\n//- Читайте ./README.md для понимания.\n\n';
lists.pug.forEach(function(blockPath) {
pugMixins += 'include '+blockPath+'\n';
});
fs.writeFileSync(dirs.srcPath + 'pug/mixins.pug', pugMixins);
// Определение: разработка это или финальная сборка
// Запуск `NODE_ENV=production npm start [задача]` приведет к сборке без sourcemaps
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV == 'dev';
// Перечисление и настройки плагинов postCSS, которыми обрабатываются стилевые файлы
let postCssPlugins = [
autoprefixer(), // настройки вынесены в package.json, дабы получать их для любой задачи
atImport(),
inlineSVG(),
objectFitImages(),
imageInliner({
// Осторожнее с именами файлов картинок! Добавляйте имя блока как префикс к имени картинки.
assetPaths: [
'src/blocks/**/bg-img/',
],
// Инлайнятся только картинки менее 5 Кб.
maxFileSize: 5120
})
];
// Очистка папки сборки
gulp.task('clean', function () {
console.log('---------- Очистка папки сборки');
return del([
dirs.buildPath + '/**/*',
'!' + dirs.buildPath + '/readme.md'
]);
});
// Компиляция стилей блоков проекта (и добавочных)
gulp.task('style', function () {
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const wait = require('gulp-wait');
const insert = require('gulp-insert');
console.log('---------- Компиляция стилей');
return gulp.src(dirs.srcPath + 'scss/style.scss')
.pipe(plumber({
errorHandler: function(err) {
notify.onError({
title: 'Styles compilation error',
message: err.message
})(err);
this.emit('end');
}
}))
.pipe(debug({title: "Style:"}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
// .pipe(browserSync.stream({match: '**/*.css'}));
});
// Компиляция отдельных файлов
gulp.task('style:single', function () {
if(projectConfig.singleCompiled.length) {
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const wait = require('gulp-wait');
const insert = require('gulp-insert');
console.log('---------- Компиляция добавочных стилей');
return gulp.src(projectConfig.singleCompiled)
.pipe(plumber({
errorHandler: function(err) {
notify.onError({
title: 'Single style compilation error',
message: err.message
})(err);
this.emit('end');
}
}))
.pipe(wait(100))
.pipe(gulpIf(isDev, sourcemaps.init()))
.pipe(debug({title: "Single style:"}))
.pipe(sass())
.pipe(postcss(postCssPlugins))
.pipe(insert.append(styleFileMsg))
.pipe(gulpIf(!isDev, cleanss()))
.pipe(gulpIf(isDev, sourcemaps.write('/')))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
.pipe(browserSync.stream({match: '**/*.css'}));
}
});
// Копирование добавочных CSS, которые хочется иметь отдельными файлами
gulp.task('copy:css', function(callback) {
if(projectConfig.copiedCss.length) {
return gulp.src(projectConfig.copiedCss)
.pipe(postcss(postCssPlugins))
.pipe(cleanss())
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
.pipe(browserSync.stream());
}
else {
callback();
}
});
// Копирование изображений
gulp.task('copy:img', function () {
console.log('---------- Копирование изображений');
return gulp.src(lists.img)
.pipe(newer(dirs.buildPath + '/img')) // оставить в потоке только изменившиеся файлы
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/img'));
});
// Копирование JS
gulp.task('copy:js', function (callback) {
if(projectConfig.copiedJs.length) {
return gulp.src(projectConfig.copiedJs)
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
}
else {
callback();
}
});
// Копирование шрифтов
gulp.task('copy:fonts', function () {
console.log('---------- Копирование шрифтов');
return gulp.src(dirs.srcPath + '/fonts/*.{ttf,woff,woff2,eot,svg}')
.pipe(newer(dirs.buildPath + '/fonts')) // оставить в потоке только изменившиеся файлы
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/fonts'));
});
// Генератор фавиконок
gulp.task('favicons', function(done) {
realFavicon.generateFavicon({
masterPicture: dirs.srcPath + '/img/favicon-lg.png',
dest: dirs.buildPath + '/img',
iconsPath: '/img',
design: {
ios: {
pictureAspect: 'backgroundAndMargin',
backgroundColor: '#ffffff',
margin: '14%',
assets: {
ios6AndPriorIcons: false,
ios7AndLaterIcons: false,
precomposedIcons: false,
declareOnlyDefaultIcon: true
}
},
desktopBrowser: {},
windows: {
pictureAspect: 'noChange',
backgroundColor: '#ffffff',
onConflict: 'override',
assets: {
windows80Ie10Tile: false,
windows10Ie11EdgeTiles: {
small: false,
medium: true,
big: false,
rectangle: false
}
}
},
androidChrome: {
pictureAspect: 'noChange',
themeColor: '#ffffff',
manifest: {
display: 'standalone',
orientation: 'notSet',
onConflict: 'override',
declared: true
},
assets: {
legacyIcon: false,
lowResolutionIcons: false
}
},
safariPinnedTab: {
pictureAspect: 'silhouette',
themeColor: '#ffffff'
}
},
settings: {
scalingAlgorithm: 'Mitchell',
errorOnImageTooSmall: false
},
markupFile: faviconData
}, function() {
done();
});
});
// Ручная проверка актуальности данных для favicon. Запускать перед стартом нового проекта.
gulp.task('check:favicons:update', function(done) {
var currentVersion = JSON.parse(fs.readFileSync(faviconData)).version;
realFavicon.checkForUpdates(currentVersion, function(err) {
if (err) {
throw err;
}
});
});
// Сборка Pug
gulp.task('pug', function() {
const pug = require('gulp-pug');
const htmlbeautify = require('gulp-html-beautify');
const replace = require('gulp-replace');
console.log('---------- сборка Pug');
// Pug-фильтр, выводящий содержимое pug-файла в виде форматированного текста
const filterShowCode = function (text, options) {
var lines = text.split('\n');
var result = '<pre class="code">\n';
if (typeof(options['first-line']) !== 'undefined') result = result + '<code>' + options['first-line'] + '</code>\n';
for (var i = 0; i < (lines.length - 1); i++) { // (lines.length - 1) для срезания последней строки (пустая)
result = result + '<code>' + lines[i] + '</code>\n';
}
result = result + '</pre>\n';
result = result.replace(/<code><\/code>/g, '<code>&nbsp;</code>');
return result;
}
return gulp.src([
dirs.srcPath + '/*.pug',
])
.pipe(plumber())
.pipe(pug({
data: {
repoUrl: repoUrl, // передаем pug-у адрес репозитория проекта
},
filters: {
'show-code': filterShowCode
},
// compileDebug: false,
}))
.pipe(htmlbeautify())
// и... привет бьютификатору!
.pipe(replace(/^(\s*)(<header.+?>)(.*)(<\/header>)/gm, '$1$2\n$1 $3\n$1$4'))
.pipe(replace(/^(\s*)(<footer.+?>)(.*)(<\/footer>)/gm, '$1$2\n$1 $3\n$1$4'))
.pipe(replace(/^\s*<section.+>/gm, '\n$&'))
.pipe(replace(/^\s*<\/section>/gm, '$&\n'))
.pipe(replace(/^\s*<article.+>/gm, '\n$&'))
.pipe(replace(/^\s*<\/article>/gm, '$&\n'))
.pipe(replace(/\n\n\n/gm, '\n\n'))
.pipe(gulp.dest(dirs.buildPath));
});
gulp.task('test:pug', function () {
const pugLinter = require('gulp-pug-lint');
return gulp
.src('src/**/*.pug')
.pipe(pugLinter());
});
// Конкатенация и углификация Javascript
gulp.task('js', function (callback) {
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');
if(lists.js.length > 0){
console.log('---------- Обработка JS');
return gulp.src(lists.js)
.pipe(plumber({
errorHandler: function(err) {
notify.onError({
title: 'Javascript concat/uglify error',
message: err.message
})(err);
this.emit('end');
}
}))
.pipe(concat('script.min.js'))
.pipe(gulpIf(!isDev, uglify()))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
}
else {
console.log('---------- Обработка JS: в сборке нет JS-файлов');
callback();
}
});
// Сборка всего
gulp.task('build', function (callback) {
gulpSequence(
['clean'],
['style', 'style:single', 'js', 'copy:css', 'copy:img', 'copy:js', 'copy:fonts'],
'pug',
callback
);
});
// Отправка в GH pages (ветку gh-pages репозитория)
gulp.task('deploy', function() {
const ghPages = require('gulp-gh-pages');
console.log('---------- Публикация содержимого ./build/ на GH pages');
return gulp.src(dirs.buildPath + '**/*')
.pipe(ghPages());
});
// Задача по умолчанию
gulp.task('default', ['serve']);
// Локальный сервер, слежение
gulp.task('serve', ['build'], function() {
browserSync.init({
server: dirs.buildPath,
startPath: 'index.html',
open: false,
port: 8080,
});
// Слежение за стилями
gulp.watch([
dirs.srcPath + 'scss/**/*.scss',
dirs.srcPath + dirs.blocksDirName + '/**/*.scss',
projectConfig.addCssBefore,
projectConfig.addCssAfter,
], ['style']);
// Слежение за отдельными стилями
gulp.watch(projectConfig.singleCompiled, ['style:single',]);
// Слежение за добавочными стилями
if(projectConfig.copiedCss.length) {
gulp.watch(projectConfig.copiedCss, ['copy:css']);
}
// Слежение за изображениями
if(lists.img.length) {
gulp.watch(lists.img, ['watch:img']);
}
// Слежение за добавочными JS
if(projectConfig.copiedJs.length) {
gulp.watch(projectConfig.copiedJs, ['watch:copied:js']);
}
// Слежение за шрифтами
gulp.watch('/fonts/*.{ttf,woff,woff2,eot,svg}', {cwd: dirs.srcPath}, ['watch:fonts']);
// Слежение за pug
gulp.watch([
dirs.srcPath + '/**/*.pug',
], ['watch:pug']);
// Слежение за JS
if(lists.js.length) {
gulp.watch(lists.js, ['watch:js']);
}
});
// Браузерсинк с 3-м галпом — такой браузерсинк...
gulp.task('watch:img', ['copy:img'], reload);
gulp.task('watch:copied:js', ['copy:js'], reload);
gulp.task('watch:fonts', ['copy:fonts'], reload);
gulp.task('watch:pug', ['pug'], reload);
gulp.task('watch:js', ['js'], reload);
/**
* Вернет объект с обрабатываемыми файлами и папками
* @param {object}
* @return {object}
*/
function getFilesList(config){
let res = {
'css': [],
'js': [],
'img': [],
'pug': [],
};
// Style
for (let blockName in config.blocks) {
res.css.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + '.scss');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
res.css.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + elementName + '.scss');
});
}
}
res.css = res.css.concat(config.addCssAfter);
res.css = config.addCssBefore.concat(res.css);
// JS
for (let blockName in config.blocks) {
res.js.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + '.js');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
res.js.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + elementName + '.js');
});
}
}
res.js = res.js.concat(config.addJsAfter);
res.js = config.addJsBefore.concat(res.js);
// Images
for (let blockName in config.blocks) {
res.img.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/img/*.{jpg,jpeg,gif,png,svg}');
}
res.img = config.addImages.concat(res.img);
// Pug
for (let blockName in config.blocks) {
res.pug.push('../blocks/' + blockName + '/' + blockName + '.pug');
}
return res;
}
/**
* Проверка существования файла или папки
* @param {string} path Путь до файла или папки]
* @return {boolean}
*/
function fileExist(path) {
const fs = require('fs');
try {
fs.statSync(path);
} catch(err) {
return !(err && err.code === 'ENOENT');
}
}
// Перезагрузка браузера
function reload (done) {
browserSync.reload();
done();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment