Created
February 2, 2018 08:32
-
-
Save Bogdan808/c9c502ef28bcb6c82f932a07e1195e8a to your computer and use it in GitHub Desktop.
My new gulp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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> </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