Commit ddcc6454 authored by Nikolay Gromov's avatar Nikolay Gromov

Доделал механизм компиляции pug

parent c7bf28df
# Стартовый проект с 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)
## НОВОЕ (как должно работать) ## Сборка разметки из pug
Директории, содержащие какие-либо файлы с разметкой:
```bash
./src/
blocks/ # Блоки
some-block/ # Директория блока (все технологии блока, в т.ч. и pug)
some-block.pug # Разметка блока (pug-примесь!)
pages/ # Страницы проекта
index.pug # Главная страница
pug/ # Служебные файлы (шаблоны, примеси)
layout.pug # Шаблон всех страниц
mixins.pug # Примеси (создаётся автоматически, инклудит ВСЕ блоки (из ./src/blocks/), имеющие одноимённый блоку pug-файл)
```
### Как собирается pug
При `npm start`:
1. Создаётся файл `./src/pug/mixins.pug`, содержащий инклуды всех pug-файлов блоков, независимо от использования на проекте. Инклуд добавляется только если в папке блока есть одноимённый блоку pug-файл.
2. Компилируются в html и пишутся в `./build/` все pug-файлы из `./src/pages/`.
3. Запускает сервер автообновления и слежения:
- если изменился pug-файл из `./src/pages/`, заново компилируется только изменённый файл,
- если изменился pug-файл блока или файл из `./src/pug/`, заново компилируются все файлы из `./src/pages/`.
### Полная сборка
- Определяются переменные, в т.ч. `config` из `./config.js` (все настройки).
- Из pug собирается html.
- Получившийся HTML анализируется, из атрибутов `class` формируется массив `blocksList` (файлы, перечисленные в `config.notGetBlocks` игнорируются; блоки, перечисленные в `config.ignoredBlocks` игнорируются).
- Формируется список использованных сейчас на проекте блоков:
- Из массива `config.blocks` убираются не использующиеся сейчас в разметке блоки.
- В массив `config.blocks` добавляются блоки, которые используются, но отсутствовали в нём (добавляются в конец).
- Если изменился список блоков, формируется контент `./config.js` и файл записывается на диск.
- Формируем список стилевых файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ. Перезаписываем ДП стилей.
- Компилируем стили.
- Формируем список JS-файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Собираем и обрабатываем JS.
- Формируем список картинок: дополнительные из конфига, картинки блоков. Копируем картинки.
- Копируем доп. файлы: дополнительные из конфига, доп. файлы блоков.
- Копируем шрифты.
- Копируем стилевые и js-файлы, указанные как копируемые в конфиге.
- Обновляем страницу
### Изменение любого файла разметки
- Из pug собирается html.
- Получившийся HTML анализируется, из атрибутов `class` формируется массив `blocksListNew`.
- Из `blocksListNew` исключаются игнорируемые блоки, упомянутые в массиве `config.ignoredBlocks`.
- Сравниваются `blocksListNew` и `blocksList`:
- Если отличий нет, просто обновляется браузер.
- Если отличия есть:
- `configOld = config`
-ПОВТОР Формируем актуальный конфиг `config`:
- Добавляем не касающиеся блоков разделы из `configOld`.
- Обходим `blocksList` и проверяем для каждого блока существование стилевого файла, JS-файла, папки картинок. Записываем данные, идентичные старому конфигу по структуре.
- Записываем актуальный конфиг в файл `config.json`.
- Формируем список стилевых файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Сравниваем список стилевых файлов с содержимым диспетчера подключений. Если отличаются, перезаписываем ДП стилей.
- Компилируем стили.
- Формируем список JS-файлов: файлы ДО, файлы блоков (если есть), файлы ПОСЛЕ.
- Собираем и обрабатываем JS.
- Формируем список картинок: дополнительные из конфига, картинки блоков. Копируем картинки.
- Копируем доп. файлы: дополнительные из конфига, доп. файлы блоков.
- Копируем шрифты.
- Копируем стилевые и js-файлы, указанные как копируемые в конфиге.
- Обновляем страницу
### Изменение любого стилевого файла ### Изменение любого стилевого файла
......
...@@ -14,9 +14,7 @@ let config = ...@@ -14,9 +14,7 @@ let config =
"main-nav", "main-nav",
"burger", "burger",
"page-footer", "page-footer",
"catalog", "some-new-class",
"catalog",
"catalog",
"catalog" "catalog"
], ],
"addStyleBefore": [ "addStyleBefore": [
......
...@@ -10,8 +10,11 @@ let blocksList = []; ...@@ -10,8 +10,11 @@ let blocksList = [];
let oldBlocksListString = JSON.stringify(config.blocks); let oldBlocksListString = JSON.stringify(config.blocks);
// Адрес репозитория // Адрес репозитория
let repoUrl = require('./package.json').repository.url.replace(/\.git$/g, ''); let repoUrl = require('./package.json').repository.url.replace(/\.git$/g, '');
// Установка режима компиляции pug (1 — только изменившийся файл, 0 — все) // Настройки pug-компилятора
process.env.PUG_COMP_WITH_LASTRUN = 1; let pugOption = {
data: { repoUrl: repoUrl, },
filters: { 'show-code': filterShowCode, },
};
// Определение: разработка это или финальная сборка // Определение: разработка это или финальная сборка
// NODE_ENV=production npm start [задача]` приведет к сборке без sourcemaps // NODE_ENV=production npm start [задача]` приведет к сборке без sourcemaps
...@@ -33,66 +36,28 @@ const debug = require('gulp-debug'); ...@@ -33,66 +36,28 @@ const debug = require('gulp-debug');
function compilePug() { function compilePug() {
return src([ return src([ `${dir.src}pages/**/*.pug` ])
`${dir.src}pages/**/*.pug`,
], { since: process.env.PUG_COMP_WITH_LASTRUN === '1' ? lastRun(compilePug) : null })
.pipe(plumber()) .pipe(plumber())
.pipe(debug({title: 'Compiles '})) .pipe(debug({title: 'Compiles '}))
.pipe(pug({ .pipe(pug(pugOption))
data: {
repoUrl: repoUrl,
},
filters: {
'show-code': filterShowCode, // Фильтр используется на странице библиотеки блоков
},
}))
.pipe(through2.obj(getClassesToBlocksList)) .pipe(through2.obj(getClassesToBlocksList))
.on('end', function(){ .on('end', function checkBlockListWithClear(){checkBlockList(true)}) // компилируются все; можно убирать блоки, которых больше нет
if(blocksList.length) {
// Убрать из списка блоков те элементы, которых нет в списке блоков, полученном из HTML
if (process.env.PUG_COMP_WITH_LASTRUN === '0') { // только если в потоке ВСЕ файлы
config.blocks = config.blocks.filter(item => blocksList.indexOf(item) >= 0);
}
// Добавить в конец списка блоков те элементы, которые использованы в HTML, но отсутствуют в списке
Array.prototype.push.apply(config.blocks, getArraysDiff(blocksList, config.blocks));
// ИМЕЕМ СПИСОК ИСПОЛЬЗОВАННЫХ СЕЙЧАС НА ПРОЕКТЕ БЛОКОВ
console.log(config.blocks);
// Если есть изменения списка блоков
if(oldBlocksListString != JSON.stringify(config.blocks)) {
// Записать новый конфиг
writeConfig(config);
// Подновить старый список блоков
oldBlocksListString = JSON.stringify(config.blocks);
}
}
else {
console.log('---------- В проекте нет блоков. Сурово. По-челябински.');
}
})
.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(dest(dir.build)); .pipe(dest(dir.build));
} }
exports.compilePug = compilePug; exports.compilePug = compilePug;
// Компиляция только изменившегося (с последнего запуска задачи) pug-файла // Компиляция только изменившегося (с последнего запуска задачи) pug-файла
function compilePugLastrun(cb) { function compilePugFast() {
process.env.PUG_COMP_WITH_LASTRUN = 1; return src([ `${dir.src}pages/**/*.pug` ], { since: lastRun(compilePugFast) })
return series(compilePug)(cb); .pipe(plumber())
} .pipe(debug({title: 'Compiles '}))
exports.compilePugLastrun = compilePugLastrun; .pipe(pug(pugOption))
// Компиляция всех pug-файлов .pipe(through2.obj(getClassesToBlocksList))
function compilePugDefault(cb) { .on('end', checkBlockList)
process.env.PUG_COMP_WITH_LASTRUN = 0; .pipe(dest(dir.build));
return series(compilePug)(cb);
} }
exports.compilePugDefault = compilePugDefault; exports.compilePugFast = compilePugFast;
function writePugMixinsFile(cb) { function writePugMixinsFile(cb) {
...@@ -109,18 +74,6 @@ function writePugMixinsFile(cb) { ...@@ -109,18 +74,6 @@ function writePugMixinsFile(cb) {
exports.writePugMixinsFile = writePugMixinsFile; exports.writePugMixinsFile = writePugMixinsFile;
function ttsk(cb) {
compilePug();
// console.log('test task');
// process.env.PUG = 'test';
// console.log(process.env.PUG);
// process.env.PUG = 'test2';
// console.log(process.env.PUG);
cb();
}
exports.ttsk = ttsk;
function clearBuildDir() { function clearBuildDir() {
return del([ return del([
`${dir.build}**/*`, `${dir.build}**/*`,
...@@ -144,33 +97,38 @@ function serve() { ...@@ -144,33 +97,38 @@ function serve() {
open: false, open: false,
}); });
// Файлы разметки страниц (изменение, добавление) // Файлы разметки страниц (изменение, добавление)
watch([dir.src + 'pages/**/*.pug'], { events: ['change', 'add'] }, series(compilePugLastrun, reload)); watch([`${dir.src}pages/**/*.pug`], { events: ['change', 'add'], delay: 100 }, series(compilePugFast, reload));
// Файлы разметки страниц (удаление) // Файлы разметки страниц (удаление)
watch([dir.src + 'pages/**/*.pug']) watch([`${dir.src}pages/**/*.pug`], { delay: 100 })
.on('unlink', function(path, stats) { .on('unlink', function(path, stats) {
let filePathInBuildDir = path.replace(dir.src.replace('./','') + 'pages/', dir.build).replace('.pug', '.html'); let filePathInBuildDir = path.replace(dir.src.replace('./','') + 'pages/', dir.build).replace('.pug', '.html');
fs.unlink(filePathInBuildDir, (err) => { fs.unlink(filePathInBuildDir, (err) => {
if (err) throw err; if (err) throw err;
console.log('---------- ' + filePathInBuildDir + ' удалён'); console.log(`---------- ${filePathInBuildDir} удалён`);
}); });
}); });
// Файлы разметки БЭМ-блоков (изменение, добавление) // Файлы разметки БЭМ-блоков (изменение, добавление)
watch([dir.blocks + '**/*.pug'], { events: ['change', 'add'] }, series(compilePugDefault, reload)); watch([`${dir.blocks}**/*.pug`], { events: ['change', 'add'], delay: 100 }, series(compilePug, reload));
// Файлы разметки БЭМ-блоков (удаление) // Файлы разметки БЭМ-блоков (удаление)
watch([dir.blocks + '**/*.pug'], { events: ['unlink'] }, series(writePugMixinsFile)); watch([`${dir.blocks}**/*.pug`], { events: ['unlink'], delay: 100 }, series(writePugMixinsFile));
// Прочие pug-файлы, кроме файла примесей (все события) // Прочие pug-файлы, кроме файла примесей (все события)
watch([dir.src + 'pug/**/*.pug', '!' + dir.src + 'pug/mixins.pug'], series(compilePugDefault, reload)); watch([`${dir.src}pug/**/*.pug`, `!${dir.src}pug/mixins.pug`], { delay: 100 }, series(compilePug, reload));
} }
// exports.serve = serve;
exports.default = series( exports.default = series(
parallel(clearBuildDir, writePugMixinsFile), parallel(clearBuildDir, writePugMixinsFile),
compilePugDefault, compilePugFast,
serve, serve,
); );
// Функции, не являющиеся задачами Gulp ---------------------------------------- // Функции, не являющиеся задачами Gulp ----------------------------------------
/** /**
...@@ -275,7 +233,6 @@ function getClassesToBlocksList(file, enc, cb) { ...@@ -275,7 +233,6 @@ function getClassesToBlocksList(file, enc, cb) {
cb(null, file); cb(null, file);
return; return;
} }
blocksList = [];
// Проверяем, не является ли обрабатываемый файл исключением // Проверяем, не является ли обрабатываемый файл исключением
let processThisFile = true; let processThisFile = true;
config.notGetBlocks.forEach(function(item) { config.notGetBlocks.forEach(function(item) {
...@@ -299,3 +256,30 @@ function getClassesToBlocksList(file, enc, cb) { ...@@ -299,3 +256,30 @@ function getClassesToBlocksList(file, enc, cb) {
this.push(file); this.push(file);
cb(); cb();
} }
/**
* СЛУЖЕБНАЯ: Обновляет глобальную переменную с актуальным список блоков
* @param {Boolean} removeBlocks Удалять ли не найденные блоки
*/
function checkBlockList(removeBlocks = false) {
if(blocksList.length) {
if (removeBlocks) {
// Убрать из списка блоков те элементы, которых нет в списке блоков, полученном из HTML
config.blocks = config.blocks.filter(item => blocksList.indexOf(item) >= 0);
}
// Добавить в конец списка блоков те элементы, которые использованы в HTML, но отсутствуют в списке
Array.prototype.push.apply(config.blocks, getArraysDiff(blocksList, config.blocks));
// ИМЕЕМ СПИСОК ИСПОЛЬЗОВАННЫХ СЕЙЧАС НА ПРОЕКТЕ БЛОКОВ
// console.log(config.blocks);
// Если есть изменения списка блоков
if(oldBlocksListString != JSON.stringify(config.blocks)) {
// Записать новый конфиг
writeConfig(config);
// Подновить старый список блоков
oldBlocksListString = JSON.stringify(config.blocks);
}
}
else {
console.log('---------- В проекте нет блоков. Сурово. По-челябински.');
}
}
...@@ -10,7 +10,7 @@ block meta ...@@ -10,7 +10,7 @@ block meta
block header block header
+page-header() +page-header()
+logo('/') +logo('/')
span Логотип 1 span Логотип
+main-nav('10') +main-nav('10')
block content block content
......
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