Commit 1e654d43 authored by Nikolay Gromov's avatar Nikolay Gromov

Написал обработку разметки и получение классов-блоков

parent dae7879a
# Стартовый проект с gulp ![Test Status](https://travis-ci.org/nicothin/NTH-start-project.svg?branch=master) [![devDependencies Status](https://david-dm.org/nicothin/NTH-start-project/dev-status.svg)](https://david-dm.org/nicothin/NTH-start-project?type=dev) [![dependencies Status](https://david-dm.org/nicothin/NTH-start-project/status.svg)](https://david-dm.org/nicothin/NTH-start-project) # Стартовый проект с gulp ![Test Status](https://travis-ci.org/nicothin/NTH-start-project.svg?branch=master) [![devDependencies Status](https://david-dm.org/nicothin/NTH-start-project/dev-status.svg)](https://david-dm.org/nicothin/NTH-start-project?type=dev) [![dependencies Status](https://david-dm.org/nicothin/NTH-start-project/status.svg)](https://david-dm.org/nicothin/NTH-start-project)
## НОВОЕ (как должно работать)
### Полная сборка
- Создаются переменные:
- `blocksList = []` — массив классов-Блоков, которые будут получены из html.
- `configOld = require('./config.json')` — конфиг, который уже есть.
- `config = {}` — актуальный конфиг.
- Из pug собирается html.
- Получившийся HTML анализируется, из атрибутов `class` формируется массив `blocksList`.
- Из `blocksList` исключаются игнорируемые блоки, упомянутые в массиве `configOld.ignoredBlocks`.
- Формируем актуальный конфиг `config`:
- Добавляем не касающиеся блоков разделы из `configOld`.
- Обходим `blocksList` и проверяем для каждого блока существование стилевого файла, JS-файла, папки картинок. Записываем данные, идентичные старому конфигу по структуре.
- Записываем актуальный конфиг в файл `config.json`.
- Формируем список стилевых файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Сравниваем список стилевых файлов с содержимым диспетчера подключений. Если отличаются, перезаписываем ДП стилей.
- Компилируем стили.
- Формируем список JS-файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Собираем и обрабатываем JS.
- Формируем список картинок: дополнительные из конфига, картинки блоков. Копируем картинки.
- Копируем доп. файлы: дополнительные из конфига, доп. файлы блоков.
- Копируем шрифты.
- Копируем стилевые и js-файлы, указанные как копируемые в конфиге.
- Обновляем страницу
### Изменение любого файла разметки
- Из pug собирается html.
- Получившийся HTML анализируется, из атрибутов `class` формируется массив `blocksListNew`.
- Из `blocksListNew` исключаются игнорируемые блоки, упомянутые в массиве `config.ignoredBlocks`.
- Сравниваются `blocksListNew` и `blocksList`:
- Если отличий нет, просто обновляется браузер.
- Если отличия есть:
- `configOld = config`
-ПОВТОР Формируем актуальный конфиг `config`:
- Добавляем не касающиеся блоков разделы из `configOld`.
- Обходим `blocksList` и проверяем для каждого блока существование стилевого файла, JS-файла, папки картинок. Записываем данные, идентичные старому конфигу по структуре.
- Записываем актуальный конфиг в файл `config.json`.
- Формируем список стилевых файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Сравниваем список стилевых файлов с содержимым диспетчера подключений. Если отличаются, перезаписываем ДП стилей.
- Компилируем стили.
- Формируем список JS-файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Собираем и обрабатываем JS.
- Формируем список картинок: дополнительные из конфига, картинки блоков. Копируем картинки.
- Копируем доп. файлы: дополнительные из конфига, доп. файлы блоков.
- Копируем шрифты.
- Копируем стилевые и js-файлы, указанные как копируемые в конфиге.
- Обновляем страницу
### Изменение любого стилевого файла
- Компилируем стили.
- Обновляем CSS страницы.
### Добавление или удаление стилевого файла
- `configOld = config`
- Формируем актуальный конфиг `config`:
- Добавляем не касающиеся блоков разделы из `configOld`.
- Обходим `blocksList` и проверяем для каждого блока существование стилевого файла. Про js-файл и картинки не проверяем, берем существующие данные. Записываем данные, идентичные старому конфигу по структуре.
- Записываем актуальный конфиг в файл `config.json`.
- Формируем список стилевых файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Перезаписываем ДП стилей.
- Компилируем стили.
- Обновляем CSS страницы.
### Изменение любого js-файла
### Изменение в папке, откуда собирается растровый спрайт
### Изменение в папке, откуда собирается векторный спрайт
### Изменение в папке добавочных картинок
### Изменение в папке добавочных файлов
### Изменение файла `config.json`
## СТАРОЕ
---
<table> <table>
<thead> <thead>
<tr> <tr>
......
let config =
{
"notGetBlocks": [
"blocks-demo.html",
],
"ignoredBlocks": [
"no-js",
],
"blocks": {
"page": {
"style": [
"src/blocks/page/page.scss",
],
"js": [],
"img": [],
"assets": [],
},
"page-header": {
"style": [
"src/blocks/page-header/page-header.scss",
],
"js": [],
"img": [],
"assets": [],
},
"logo": {
"style": [
"src/blocks/logo/logo.scss",
],
"js": [],
"img": [],
"assets": [],
},
"main-nav": {
"style": [
"src/blocks/main-nav/main-nav.scss",
],
"js": [
"src/blocks/main-nav/main-nav.js"
],
"img": [],
"assets": [],
},
"burger": {
"style": [
"src/blocks/burger/burger.scss",
],
"js": [
"src/blocks/burger/burger.js"
],
"img": [],
"assets": [],
},
"page-footer": {
"style": [
"src/blocks/page-footer/page-footer.scss",
],
"js": [],
"img": [],
"assets": [],
}
},
"addStyleBefore": [
"./src/scss/functions.scss",,
"./src/scss/variables.scss",,
"./src/scss/mixins.scss",
],
"addStyleAfter": [
"./src/scss/print.scss",
],
"addJsBefore": [],
"addJsAfter": [
"./src/js/global-script.js",
],
"addImages": [],
"addAssets": [],
"copiedCss": [],
"copiedJs": [],
"dir": {
"src": "./src/",
"build": "./build/",
"blocks": "./src/blocks/",
},
};
module.exports = config;
'use strict'; 'use strict';
// Подключения зависимостей
const fs = require('fs'); const fs = require('fs');
const gulp = require('gulp');
const browserSync = require('browser-sync').create();
const postcss = require('gulp-postcss'); // Настройки из файла
const autoprefixer = require("autoprefixer"); let config = require('./config.js');
const mqpacker = require("css-mqpacker"); // Директории из настроек (dir.src = "./src/", dir.build = "./build/", dir.blocks = "./src/blocks/")
const atImport = require("postcss-import"); let dir = config.dir;
const cleanss = require('gulp-cleancss'); // Список блоков, который будет получен из классов HTML после компиляции pug
const inlineSVG = require('postcss-inline-svg'); let blocksList = [];
const objectFitImages = require('postcss-object-fit-images'); // Адрес репозитория
let repoUrl = require('./package.json').repository.url.replace(/\.git$/g, '');
// Пакеты, использующиеся при обработке
const { series, parallel, src, dest, watch } = require('gulp');
const plumber = require('gulp-plumber'); 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 del = require('del');
const newer = require('gulp-newer'); const pug = require('gulp-pug');
const through2 = require('through2');
// Получение настроек проекта из projectConfig.json const replace = require('gulp-replace');
let projectConfig = require('./projectConfig.json'); const getClassesFromHtml = require('get-classes-from-html');
let dirs = projectConfig.dirs;
let lists = getFilesList(projectConfig);
// console.log(lists);
// Получение адреса репозитория
let repoUrl = require('./package.json').repository.url.replace(/\.git$/g, '');
// console.log(repoUrl);
// Сообщение, записываемое в стилевой файл
let styleFileMsg = '/*!*\n * ВНИМАНИЕ! Этот файл генерируется автоматически.\n * Не пишите сюда ничего вручную, все такие правки будут потеряны при следующей компиляции.\n * Правки без возможности компиляции ДОЛЬШЕ И ДОРОЖЕ в 2-3 раза.\n * Нужны дополнительные стили? Создайте новый css-файл и подключите его к странице.\n * Читайте ./README.md для понимания.\n */\n\n';
// Формирование и запись диспетчера подключений (style.scss), который компилируется в style.min.css
let styleImports = styleFileMsg;
lists.css.forEach(function(blockPath) {
styleImports += '@import \''+blockPath+'\';\n';
});
styleImports = styleImports += styleFileMsg;
fs.writeFileSync(dirs.srcPath + 'scss/style.scss', 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, дабы получать их для любой задачи
mqpacker({
sort: true
}),
atImport(),
inlineSVG(),
objectFitImages(),
];
// Очистка папки сборки
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(wait(100))
.pipe(gulpIf(isDev, sourcemaps.init()))
.pipe(debug({title: "Style:"}))
.pipe(sass({includePaths: [__dirname+'/']}))
.pipe(postcss(postCssPlugins))
.pipe(insert.append(styleFileMsg))
.pipe(gulpIf(!isDev, cleanss()))
.pipe(rename('style.min.css'))
.pipe(gulpIf(isDev, sourcemaps.write('/')))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
.pipe(browserSync.stream());
});
// Компиляция отдельных файлов
gulp.task('style:single', function (callback) {
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());
}
else {
callback();
}
});
// Копирование добавочных 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 function compilePug() {
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('copy:favicon', function () {
console.log('---------- Копирование фавиконок');
return gulp.src(dirs.srcPath + '/favicon/*.{png,ico,svg}')
.pipe(gulp.dest(dirs.buildPath + '/img/favicon'));
});
gulp.task('copy:favicon:data', function () {
return gulp.src(dirs.srcPath + '/favicon/*.{xml,webmanifest}')
.pipe(gulp.dest(dirs.buildPath + '/'));
});
// Сборка SVG-спрайта для блока sprite-svg
let spriteSvgPath = dirs.srcPath + dirs.blocksDirName + '/sprite-svg/svg/';
gulp.task('sprite:svg', function (callback) {
if((projectConfig.blocks['sprite-svg']) !== undefined) {
const svgstore = require('gulp-svgstore');
const svgmin = require('gulp-svgmin');
const cheerio = require('gulp-cheerio');
if(fileExist(spriteSvgPath) !== false) {
console.log('---------- Сборка SVG спрайта');
return gulp.src(spriteSvgPath + '*.svg')
.pipe(svgmin(function (file) {
return {
plugins: [{
cleanupIDs: {
minify: true
}
}]
}
}))
.pipe(svgstore({ inlineSvg: true }))
.pipe(cheerio({
run: function($) {
$('svg').attr('style', 'display:none');
},
parserOptions: {
xmlMode: true
}
}))
.pipe(rename('sprite-svg.svg'))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-svg/img/'));
}
else {
console.log('---------- Сборка SVG спрайта: ОТМЕНА, нет папки с картинками');
callback();
}
}
else {
console.log('---------- Сборка SVG спрайта: ОТМЕНА, блок не используется на проекте');
callback();
}
});
// Сборка растрового спрайта для блока sprite-png
let spritePngPath = dirs.srcPath + dirs.blocksDirName + '/sprite-png/png/';
gulp.task('sprite:png', function (callback) {
if((projectConfig.blocks['sprite-png']) !== undefined) {
const spritesmith = require('gulp.spritesmith');
const buffer = require('vinyl-buffer');
const merge = require('merge-stream');
const imagemin = require('gulp-imagemin');
if(fileExist(spritePngPath) !== false) {
del(dirs.srcPath + dirs.blocksDirName + '/sprite-png/img/*.png');
let fileName = 'sprite-' + Math.random().toString().replace(/[^0-9]/g, '') + '.png';
let spriteData = gulp.src(spritePngPath + '*.png')
.pipe(spritesmith({
imgName: fileName,
cssName: 'sprite-png.scss',
padding: 4,
imgPath: '../img/' + fileName
}));
let imgStream = spriteData.img
.pipe(buffer())
.pipe(imagemin([
imagemin.optipng({ optimizationLevel: 5 }),
]))
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-png/img/'));
let cssStream = spriteData.css
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-png/'));
return merge(imgStream, cssStream);
}
else {
console.log('---------- Сборка PNG спрайта: ОТМЕНА, нет папки с картинками');
callback();
}
}
else {
console.log('---------- Сборка PNG спрайта: ОТМЕНА, блок не используется на проекте');
callback();
}
});
// Сборка Pug
let classes = [];
gulp.task('pug', function() {
const pug = require('gulp-pug');
const through2 = require('through2');
const chalk = require('chalk');
const getClassesFromHtml = require('get-classes-from-html');
const htmlbeautify = require('gulp-html-beautify');
const replace = require('gulp-replace');
console.log('---------- Сборка Pug');
// Pug-фильтр, выводящий содержимое pug-файла в виде форматированного текста // Pug-фильтр, выводящий содержимое pug-файла в виде форматированного текста
const filterShowCode = function (text, options) { const filterShowCode = function (text, options) {
...@@ -330,354 +37,77 @@ gulp.task('pug', function() { ...@@ -330,354 +37,77 @@ gulp.task('pug', function() {
return result; return result;
} }
return gulp.src([ return src([
dirs.srcPath + '*.pug', dir.src + '*.pug',
]) ])
.pipe(plumber()) .pipe(plumber())
.pipe(pug({ .pipe(pug({
data: { data: {
repoUrl: repoUrl, // передаем pug-у адрес репозитория проекта // Передаем pug-у адрес репозитория проекта
repoUrl: repoUrl,
}, },
filters: { filters: {
// Фильтр используется на странице библиотеки блоков
'show-code': filterShowCode 'show-code': filterShowCode
}, },
// compileDebug: false,
})) }))
.pipe(through2.obj(function (file, enc, cb) { .pipe(through2.obj(getClassesToBlocksList))
if (file.isNull()) {
cb(null, file);
return;
}
if(file.relative != 'blocks-demo.html'){
const data = file.contents.toString();
let thisClasses = getClassesFromHtml(data);
thisClasses.forEach(function(item, i, arr) {
if (item.indexOf('__') + 1 === 0 && item.indexOf('--') + 1 === 0) {
classes.push(item)
}
});
file.contents = new Buffer(data);
}
this.push(file);
cb();
}))
.on('end', function(){ .on('end', function(){
console.log(classes); console.log(blocksList);
}) })
.pipe(htmlbeautify()) .pipe(dest(dir.build));
// и... привет бьютификатору! }
.pipe(replace(/^(\s*)(<header.+?>)(.*)(<\/header>)/gm, '$1$2\n$1 $3\n$1$4')) exports.compilePug = compilePug;
.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().on('error', function(e){console.log(e);})))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
}
else {
console.log('---------- Обработка JS: в сборке нет JS-файлов');
callback();
}
});
gulp.task('browserify', function () {
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var log = require('gulplog');
var b = browserify({
entries: dirs.srcPath + '/js/global-script.js',
debug: true
})
// .add([dirs.srcPath + '/js/scri.js']) // добавить все необходимые файлы
.transform('babelify', {presets: ['@babel/preset-env']});
return b.bundle()
.pipe(source('script.js'))
.pipe(gulp.dest(dirs.buildPath + '/js'))
.pipe(rename('script.min.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify())
.on('error', function(){ console.log('error'); })
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(dirs.buildPath + '/js'));
});
// Ручная оптимизация изображений
// Использование: folder=src/img npm start img:opt
const folder = process.env.folder;
gulp.task('img:opt', function (callback) {
const imagemin = require('gulp-imagemin');
// const pngquant = require('imagemin-pngquant');
if(folder){
console.log('---------- Оптимизация картинок');
return gulp.src(folder + '/*.{jpg,jpeg,gif,png,svg}')
.pipe(imagemin([
imagemin.gifsicle({ interlaced: true }),
imagemin.jpegtran({ progressive: true }),
imagemin.optipng({ optimizationLevel: 5 }),
imagemin.svgo({
plugins: [
{ removeViewBox: false },
{ cleanupIDs: false }
]
})
]))
.pipe(gulp.dest(folder));
}
else {
console.log('---------- Оптимизация картинок: ошибка (не указана папка)');
console.log('---------- Пример вызова команды: folder=src/blocks/block-name/img npm start img:opt');
callback();
}
});
// Сборка всего
gulp.task('build', gulp.series(
'clean',
gulp.parallel('sprite:svg', 'sprite:png', 'copy:favicon', 'copy:favicon:data'),
gulp.parallel('style', 'style:single', 'js', 'copy:css', 'copy:img', 'copy:js', 'copy:fonts'),
'pug'
));
// Отправка в GH pages (ветку gh-pages репозитория)
gulp.task('deploy', function(cb) {
const ghpages = require('gh-pages');
const path = require('path');
console.log('---------- Публикация содержимого ./build/ на GH pages');
var ghPagesUrl;
if (repoUrl) {
var urlParts = repoUrl.split('/');
if (urlParts[2] == 'github.com') {
ghPagesUrl = 'http://' + urlParts[3] + '.github.io/' + urlParts[4] + '/';
}
console.log('---------- ' + ghPagesUrl);
}
ghpages.publish(path.join(process.cwd(), dirs.buildPath), cb);
// return gulp.src(dirs.buildPath + '**/*')
// .pipe(ghPages());
});
// Локальный сервер, слежение
gulp.task('serve', gulp.series('build', function() {
browserSync.init({
server: dirs.buildPath,
port: 8080,
startPath: 'index.html',
open: false,
});
// Стили
let stylePaths = [
dirs.srcPath + 'scss/style.scss',
dirs.srcPath + 'scss/variables.scss',
dirs.srcPath + 'scss/mixins/*.scss',
];
for (let i = 0, len = lists.blocksDirs.length; i < len; ++i) {
stylePaths.push(dirs.srcPath + lists.blocksDirs[i] + '*.scss');
}
stylePaths.concat(projectConfig.addCssBefore, projectConfig.addCssAfter);
// console.log(stylePaths);
gulp.watch(stylePaths, gulp.series('style'));
// Стили, которые нужно компилировать отдельно
if(projectConfig.singleCompiled.length) {
gulp.watch(projectConfig.singleCompiled, gulp.series('style:single'));
}
// CSS-файлы, которые нужно просто копировать
if(projectConfig.copiedCss.length) {
gulp.watch(projectConfig.copiedCss, gulp.series('copy:css', reload));
}
// Изображения
if(lists.img.length) {
gulp.watch(lists.img, gulp.series('copy:img', reload));
}
// JS-файлы, которые нужно просто копировать
if(projectConfig.copiedJs.length) {
gulp.watch(projectConfig.copiedJs, gulp.series('copy:js', reload));
}
// Шрфты
gulp.watch(dirs.srcPath + 'fonts/*.{ttf,woff,woff2,eot,svg}', gulp.series('copy:fonts', reload));
// Pug-файлы
let pugPaths = [
dirs.srcPath + '*.pug',
dirs.srcPath + 'pug/*.pug',
];
for (let i = 0, len = lists.blocksDirs.length; i < len; ++i) {
pugPaths.push(dirs.srcPath + lists.blocksDirs[i] + '*.pug');
}
// console.log(pugPaths);
if(lists.pug.length) {
gulp.watch(pugPaths, gulp.series('pug', reload));
}
// JS-файлы блоков
if(lists.js.length) {
gulp.watch(lists.js, gulp.series('js', reload));
}
// SVG-изображения, попадающие в спрайт function clearBuildDir() {
if((projectConfig.blocks['sprite-svg']) !== undefined) { return del([
gulp.watch('*.svg', {cwd: spriteSvgPath}, gulp.series('sprite:svg', reload)); dir.build + '/**/*',
} '!' + dir.build + '/readme.md'
]);
}
exports.clearBuildDir = clearBuildDir;
// PNG-изображения, попадающие в спрайт
if((projectConfig.blocks['sprite-png']) !== undefined) {
gulp.watch('*.png', {cwd: spritePngPath}, gulp.series('sprite:png', reload));
}
}));
// Задача по умолчанию
gulp.task('default',
gulp.series('serve')
);
// Функции, не являющиеся задачами Gulp ----------------------------------------
/** /**
* Вернет объект с обрабатываемыми файлами и папками * Добавляет список классов из принятого HTML в переменную blocksList, используется в потоке обработки Pug.
* @param {object} * Крива и безрука, ибо требует существования глобальных переменных, с которыми работает.
* @return {object} * @param {object} file Обрабатываемый файл
* @param {string} enc Кодировка
* @param {Function} cb Коллбэк
*/ */
function getFilesList(config){ function getClassesToBlocksList(file, enc, cb) {
// Передана херь — выходим
let res = { if (file.isNull()) {
'css': [], cb(null, file);
'js': [], return;
'img': [], }
'pug': [], // Проверяем, не является ли обрабатываемый файл исключением
'blocksDirs': [], let processThisFile = true;
}; config.notGetBlocks.forEach(function(item) {
if (file.relative.trim() == item.trim()) processThisFile = false;
// Обходим массив с блоками проекта });
for (let blockName in config.blocks) { // Файл не исключён из обработки, погнали
var blockPath = config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/'; if(processThisFile){
const fileContent = file.contents.toString();
if(fileExist(blockPath)) { let classesInFile = getClassesFromHtml(fileContent);
// Обойдём все найденные классы
// Разметка (Pug) for (let item of classesInFile) {
if(fileExist(blockPath + blockName + '.pug')){ // Если это не Блок или этот Блок уже присутствует, не будем добавлять
res.pug.push('../' + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + '.pug'); if ((item.indexOf('__') + 1 !== 0) || (item.indexOf('--') + 1 !== 0) || (blocksList.indexOf(item) + 1)) continue;
// TODO переделать так, чтобы можно было использовать в вотчере // Если этот класс совпадает с классом-исключением из настроек, не будем добавлять
} if( config.ignoredBlocks.indexOf(item) + 1 ) continue;
else { // Добавляем
console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет pug-файла.'); blocksList.push(item);
}
// Стили
if(fileExist(blockPath + blockName + '.scss')){
res.css.push(blockPath + blockName + '.scss');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
if(fileExist(blockPath + blockName + elementName + '.scss')){
res.css.push(blockPath + blockName + elementName + '.scss');
}
});
}
}
else {
console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет scss-файла.');
}
// Скрипты
if(fileExist(blockPath + blockName + '.js')){
res.js.push(blockPath + blockName + '.js');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
if(fileExist(blockPath + blockName + elementName + '.js')){
res.js.push(blockPath + blockName + elementName + '.js');
}
});
}
}
else {
// console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет JS-файла.');
}
// Картинки (тупо от всех блоков, без проверки)
res.img.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/img/*.{jpg,jpeg,gif,png,svg}');
// Список директорий
res.blocksDirs.push(config.dirs.blocksDirName + '/' + blockName + '/');
}
else {
console.log('ERR ------ Блок ' + blockPath + ' указан как используемый, но такой папки нет!');
} }
file.contents = new Buffer(fileContent);
} }
this.push(file);
// Добавления cb();
res.css = res.css.concat(config.addCssAfter);
res.css = config.addCssBefore.concat(res.css);
res.js = res.js.concat(config.addJsAfter);
res.js = config.addJsBefore.concat(res.js);
res.img = config.addImages.concat(res.img);
return res;
}
/**
* Проверка существования файла или папки
* @param {string} path Путь до файла или папки]
* @return {boolean}
*/
function fileExist(filepath){
let flag = true;
try{
fs.accessSync(filepath, fs.F_OK);
}catch(e){
flag = false;
}
return flag;
}
// Перезагрузка браузера
function reload (done) {
browserSync.reload();
done();
} }
'use strict';
// Подключения зависимостей
const fs = require('fs');
const gulp = require('gulp');
const browserSync = require('browser-sync').create();
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 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);
// Сообщение, записываемое в стилевой файл
let styleFileMsg = '/*!*\n * ВНИМАНИЕ! Этот файл генерируется автоматически.\n * Не пишите сюда ничего вручную, все такие правки будут потеряны при следующей компиляции.\n * Правки без возможности компиляции ДОЛЬШЕ И ДОРОЖЕ в 2-3 раза.\n * Нужны дополнительные стили? Создайте новый css-файл и подключите его к странице.\n * Читайте ./README.md для понимания.\n */\n\n';
// Формирование и запись диспетчера подключений (style.scss), который компилируется в style.min.css
let styleImports = styleFileMsg;
lists.css.forEach(function(blockPath) {
styleImports += '@import \''+blockPath+'\';\n';
});
styleImports = styleImports += styleFileMsg;
fs.writeFileSync(dirs.srcPath + 'scss/style.scss', 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, дабы получать их для любой задачи
mqpacker({
sort: true
}),
atImport(),
inlineSVG(),
objectFitImages(),
];
// Очистка папки сборки
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(wait(100))
.pipe(gulpIf(isDev, sourcemaps.init()))
.pipe(debug({title: "Style:"}))
.pipe(sass({includePaths: [__dirname+'/']}))
.pipe(postcss(postCssPlugins))
.pipe(insert.append(styleFileMsg))
.pipe(gulpIf(!isDev, cleanss()))
.pipe(rename('style.min.css'))
.pipe(gulpIf(isDev, sourcemaps.write('/')))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
.pipe(browserSync.stream());
});
// Компиляция отдельных файлов
gulp.task('style:single', function (callback) {
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());
}
else {
callback();
}
});
// Копирование добавочных 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('copy:favicon', function () {
console.log('---------- Копирование фавиконок');
return gulp.src(dirs.srcPath + '/favicon/*.{png,ico,svg}')
.pipe(gulp.dest(dirs.buildPath + '/img/favicon'));
});
gulp.task('copy:favicon:data', function () {
return gulp.src(dirs.srcPath + '/favicon/*.{xml,webmanifest}')
.pipe(gulp.dest(dirs.buildPath + '/'));
});
// Сборка SVG-спрайта для блока sprite-svg
let spriteSvgPath = dirs.srcPath + dirs.blocksDirName + '/sprite-svg/svg/';
gulp.task('sprite:svg', function (callback) {
if((projectConfig.blocks['sprite-svg']) !== undefined) {
const svgstore = require('gulp-svgstore');
const svgmin = require('gulp-svgmin');
const cheerio = require('gulp-cheerio');
if(fileExist(spriteSvgPath) !== false) {
console.log('---------- Сборка SVG спрайта');
return gulp.src(spriteSvgPath + '*.svg')
.pipe(svgmin(function (file) {
return {
plugins: [{
cleanupIDs: {
minify: true
}
}]
}
}))
.pipe(svgstore({ inlineSvg: true }))
.pipe(cheerio({
run: function($) {
$('svg').attr('style', 'display:none');
},
parserOptions: {
xmlMode: true
}
}))
.pipe(rename('sprite-svg.svg'))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-svg/img/'));
}
else {
console.log('---------- Сборка SVG спрайта: ОТМЕНА, нет папки с картинками');
callback();
}
}
else {
console.log('---------- Сборка SVG спрайта: ОТМЕНА, блок не используется на проекте');
callback();
}
});
// Сборка растрового спрайта для блока sprite-png
let spritePngPath = dirs.srcPath + dirs.blocksDirName + '/sprite-png/png/';
gulp.task('sprite:png', function (callback) {
if((projectConfig.blocks['sprite-png']) !== undefined) {
const spritesmith = require('gulp.spritesmith');
const buffer = require('vinyl-buffer');
const merge = require('merge-stream');
const imagemin = require('gulp-imagemin');
if(fileExist(spritePngPath) !== false) {
del(dirs.srcPath + dirs.blocksDirName + '/sprite-png/img/*.png');
let fileName = 'sprite-' + Math.random().toString().replace(/[^0-9]/g, '') + '.png';
let spriteData = gulp.src(spritePngPath + '*.png')
.pipe(spritesmith({
imgName: fileName,
cssName: 'sprite-png.scss',
padding: 4,
imgPath: '../img/' + fileName
}));
let imgStream = spriteData.img
.pipe(buffer())
.pipe(imagemin([
imagemin.optipng({ optimizationLevel: 5 }),
]))
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-png/img/'));
let cssStream = spriteData.css
.pipe(gulp.dest(dirs.srcPath + dirs.blocksDirName + '/sprite-png/'));
return merge(imgStream, cssStream);
}
else {
console.log('---------- Сборка PNG спрайта: ОТМЕНА, нет папки с картинками');
callback();
}
}
else {
console.log('---------- Сборка PNG спрайта: ОТМЕНА, блок не используется на проекте');
callback();
}
});
// Сборка Pug
let classes = [];
gulp.task('pug', function() {
const pug = require('gulp-pug');
const through2 = require('through2');
// const chalk = require('chalk');
const getClassesFromHtml = require('get-classes-from-html');
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(through2.obj(function (file, enc, cb) {
if (file.isNull()) {
cb(null, file);
return;
}
if(file.relative != 'blocks-demo.html'){
const data = file.contents.toString();
let thisClasses = getClassesFromHtml(data);
thisClasses.forEach(function(item, i, arr) {
if (item.indexOf('__') + 1 === 0 && item.indexOf('--') + 1 === 0) {
classes.push(item)
}
});
file.contents = new Buffer(data);
}
this.push(file);
cb();
}))
.on('end', function(){
console.log(classes);
})
.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().on('error', function(e){console.log(e);})))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
}
else {
console.log('---------- Обработка JS: в сборке нет JS-файлов');
callback();
}
});
gulp.task('browserify', function () {
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var log = require('gulplog');
var b = browserify({
entries: dirs.srcPath + '/js/global-script.js',
debug: true
})
// .add([dirs.srcPath + '/js/scri.js']) // добавить все необходимые файлы
.transform('babelify', {presets: ['@babel/preset-env']});
return b.bundle()
.pipe(source('script.js'))
.pipe(gulp.dest(dirs.buildPath + '/js'))
.pipe(rename('script.min.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify())
.on('error', function(){ console.log('error'); })
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(dirs.buildPath + '/js'));
});
// Ручная оптимизация изображений
// Использование: folder=src/img npm start img:opt
const folder = process.env.folder;
gulp.task('img:opt', function (callback) {
const imagemin = require('gulp-imagemin');
// const pngquant = require('imagemin-pngquant');
if(folder){
console.log('---------- Оптимизация картинок');
return gulp.src(folder + '/*.{jpg,jpeg,gif,png,svg}')
.pipe(imagemin([
imagemin.gifsicle({ interlaced: true }),
imagemin.jpegtran({ progressive: true }),
imagemin.optipng({ optimizationLevel: 5 }),
imagemin.svgo({
plugins: [
{ removeViewBox: false },
{ cleanupIDs: false }
]
})
]))
.pipe(gulp.dest(folder));
}
else {
console.log('---------- Оптимизация картинок: ошибка (не указана папка)');
console.log('---------- Пример вызова команды: folder=src/blocks/block-name/img npm start img:opt');
callback();
}
});
// Сборка всего
gulp.task('build', gulp.series(
'clean',
gulp.parallel('sprite:svg', 'sprite:png', 'copy:favicon', 'copy:favicon:data'),
gulp.parallel('style', 'style:single', 'js', 'copy:css', 'copy:img', 'copy:js', 'copy:fonts'),
'pug'
));
// Отправка в GH pages (ветку gh-pages репозитория)
gulp.task('deploy', function(cb) {
const ghpages = require('gh-pages');
const path = require('path');
console.log('---------- Публикация содержимого ./build/ на GH pages');
var ghPagesUrl;
if (repoUrl) {
var urlParts = repoUrl.split('/');
if (urlParts[2] == 'github.com') {
ghPagesUrl = 'http://' + urlParts[3] + '.github.io/' + urlParts[4] + '/';
}
console.log('---------- ' + ghPagesUrl);
}
ghpages.publish(path.join(process.cwd(), dirs.buildPath), cb);
// return gulp.src(dirs.buildPath + '**/*')
// .pipe(ghPages());
});
// Локальный сервер, слежение
gulp.task('serve', gulp.series('build', function() {
browserSync.init({
server: dirs.buildPath,
port: 8080,
startPath: 'index.html',
open: false,
});
// Стили
let stylePaths = [
dirs.srcPath + 'scss/style.scss',
dirs.srcPath + 'scss/variables.scss',
dirs.srcPath + 'scss/mixins/*.scss',
];
for (let i = 0, len = lists.blocksDirs.length; i < len; ++i) {
stylePaths.push(dirs.srcPath + lists.blocksDirs[i] + '*.scss');
}
stylePaths.concat(projectConfig.addCssBefore, projectConfig.addCssAfter);
// console.log(stylePaths);
gulp.watch(stylePaths, gulp.series('style'));
// Стили, которые нужно компилировать отдельно
if(projectConfig.singleCompiled.length) {
gulp.watch(projectConfig.singleCompiled, gulp.series('style:single'));
}
// CSS-файлы, которые нужно просто копировать
if(projectConfig.copiedCss.length) {
gulp.watch(projectConfig.copiedCss, gulp.series('copy:css', reload));
}
// Изображения
if(lists.img.length) {
gulp.watch(lists.img, gulp.series('copy:img', reload));
}
// JS-файлы, которые нужно просто копировать
if(projectConfig.copiedJs.length) {
gulp.watch(projectConfig.copiedJs, gulp.series('copy:js', reload));
}
// Шрфты
gulp.watch(dirs.srcPath + 'fonts/*.{ttf,woff,woff2,eot,svg}', gulp.series('copy:fonts', reload));
// Pug-файлы
let pugPaths = [
dirs.srcPath + '*.pug',
dirs.srcPath + 'pug/*.pug',
];
for (let i = 0, len = lists.blocksDirs.length; i < len; ++i) {
pugPaths.push(dirs.srcPath + lists.blocksDirs[i] + '*.pug');
}
// console.log(pugPaths);
if(lists.pug.length) {
gulp.watch(pugPaths, gulp.series('pug', reload));
}
// JS-файлы блоков
if(lists.js.length) {
gulp.watch(lists.js, gulp.series('js', reload));
}
// SVG-изображения, попадающие в спрайт
if((projectConfig.blocks['sprite-svg']) !== undefined) {
gulp.watch('*.svg', {cwd: spriteSvgPath}, gulp.series('sprite:svg', reload));
}
// PNG-изображения, попадающие в спрайт
if((projectConfig.blocks['sprite-png']) !== undefined) {
gulp.watch('*.png', {cwd: spritePngPath}, gulp.series('sprite:png', reload));
}
}));
// Задача по умолчанию
gulp.task('default',
gulp.series('serve')
);
/**
* Вернет объект с обрабатываемыми файлами и папками
* @param {object}
* @return {object}
*/
function getFilesList(config){
let res = {
'css': [],
'js': [],
'img': [],
'pug': [],
'blocksDirs': [],
};
// Обходим массив с блоками проекта
for (let blockName in config.blocks) {
var blockPath = config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/';
if(fileExist(blockPath)) {
// Разметка (Pug)
if(fileExist(blockPath + blockName + '.pug')){
res.pug.push('../' + config.dirs.blocksDirName + '/' + blockName + '/' + blockName + '.pug');
// TODO переделать так, чтобы можно было использовать в вотчере
}
else {
console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет pug-файла.');
}
// Стили
if(fileExist(blockPath + blockName + '.scss')){
res.css.push(blockPath + blockName + '.scss');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
if(fileExist(blockPath + blockName + elementName + '.scss')){
res.css.push(blockPath + blockName + elementName + '.scss');
}
});
}
}
else {
console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет scss-файла.');
}
// Скрипты
if(fileExist(blockPath + blockName + '.js')){
res.js.push(blockPath + blockName + '.js');
if(config.blocks[blockName].length) {
config.blocks[blockName].forEach(function(elementName) {
if(fileExist(blockPath + blockName + elementName + '.js')){
res.js.push(blockPath + blockName + elementName + '.js');
}
});
}
}
else {
// console.log('---------- Блок ' + blockName + ' указан как используемый, но не имеет JS-файла.');
}
// Картинки (тупо от всех блоков, без проверки)
res.img.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/img/*.{jpg,jpeg,gif,png,svg}');
// Список директорий
res.blocksDirs.push(config.dirs.blocksDirName + '/' + blockName + '/');
}
else {
console.log('ERR ------ Блок ' + blockPath + ' указан как используемый, но такой папки нет!');
}
}
// Добавления
res.css = res.css.concat(config.addCssAfter);
res.css = config.addCssBefore.concat(res.css);
res.js = res.js.concat(config.addJsAfter);
res.js = config.addJsBefore.concat(res.js);
res.img = config.addImages.concat(res.img);
return res;
}
/**
* Проверка существования файла или папки
* @param {string} path Путь до файла или папки]
* @return {boolean}
*/
function fileExist(filepath){
let flag = true;
try{
fs.accessSync(filepath, fs.F_OK);
}catch(e){
flag = false;
}
return flag;
}
// Перезагрузка браузера
function reload (done) {
browserSync.reload();
done();
}
extends pug/layout.pug
block meta
title Главная
meta(name='description', content='')
//- block append head
//- link(rel='stylesheet', href='css/some.css')
block header
+page-header()
+logo('/')
span Логотип
+main-nav('10')
.some-new-class Class
.some-new-class__eee EEE!
.some-new-class.some-new-class--error Class
.some-new-class__eee EEE!
block content
p Содержимое. #[a(href='blocks-demo.html') Библиотека блоков].
block footer
+page-footer()
p «Подвал»
p Контактный телефон: #[a(href="tel:+70000000000") +7 000 000 00 00]
//- block page-bottom
//- script(src='js/some.js')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment