Commit c8639409 authored by Nikolay Gromov's avatar Nikolay Gromov

Допилил новый автомат (без библиотеки компонентов)

parent cc1d9053
# перечисление игнорируемых stylelint-ом файлов # перечисление игнорируемых stylelint-ом файлов
src/scss/blocks-lib.scss
src/scss/style.scss
src/blocks/sprite-png/sprite-png.scss src/blocks/sprite-png/sprite-png.scss
src/blocks/page/page.scss src/blocks/page/page.scss
src/blocks/blocks-library/blocks-library.scss
# Стартовый проект с 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)
## Структура проекта ## Структура проекта
```bash ```bash
...@@ -8,12 +9,13 @@ src/ ...@@ -8,12 +9,13 @@ src/
blocks/ # Блоки blocks/ # Блоки
favicon/ # Фавиконки favicon/ # Фавиконки
fonts/ # Шрифты fonts/ # Шрифты
img/ # Изображения, не принадлежащие ни одному БЭМ-блоку img/ # Доп. изображения
pages/ # Страницы проекта pages/ # Страницы проекта
pug/ # Служебные pug-файлы (шаблоны, примеси) pug/ # Служебные pug-файлы
scss/ # Служебные стилевые файлы scss/ # Служебные стилевые файлы
``` ```
## Как это работает ## Как это работает
При `npm start` (запускается дефолтная задача gulp): При `npm start` (запускается дефолтная задача gulp):
...@@ -25,149 +27,57 @@ src/ ...@@ -25,149 +27,57 @@ src/
5. Генерируются спрайты, в папку сборки копируются доп. файлы и картинки. 5. Генерируются спрайты, в папку сборки копируются доп. файлы и картинки.
5. Записывается `./src/scss/style.scss`, в котором: 5. Записывается `./src/scss/style.scss`, в котором:
- Импорты файлов из `config.js#addStyleBefore`. - Импорты файлов из `config.js#addStyleBefore`.
- Импорты файлов БЭМ-блоков, использующихся на проекте (если scss-файлы существуют). - Импорты файлов БЭМ-блоков, использующихся на проекте (если их scss-файлы существуют).
- Импорты файлов из `config.js#addStyleAfter`. - Импорты файлов из `config.js#addStyleAfter`.
5. Записывается `./src/js/entry.js`, в котором:
- `require` файлов из `config.js#addJsBefore`.
- `require` файлов БЭМ-блоков, использующихся на проекте (если их js-файлы существуют).
- `require` файлов из `config.js#addJsAfter`.
5. Компилируются и обрабатываются PostCSS-ом стили (`./src/scss/style.scss`), собирается скрипт (`./src/js/entry.js`).
5. Запускается локальный сервер и слежение за файлами для пересборки.
## Прочие команды
`npm run build` — Сборка со сжатыми css- и js-файлами
`npm run deploy` — Сборка проекта без карт кода и отправка содержимого папки сборки на gh-pages
## Как это работает
При `npm start` (запускается дефолтная задача gulp):
1. Создаётся глобальная переменная `config` с настройками (из `./config.js`).
2. Очищается папка сборки (`./build/`).
3. Записывается `./src/pug/mixins.pug` и компилируются в html файлы страниц (`./src/pages/`). **В процессе обновляется список блоков** (`config.blocks`), если есть какие-то новые блоки, записывается файл `./config.js`.
4. Записывается `./src/scss/style.scss`, в котором:
- Импорты файлов из `config.addStyleBefore`.
- Импорты файлов БЭМ-блоков, использующихся на проекте (из `config.blocks`, но только если сами scss-файлы существуют в папках блоков).
- Импорты файлов из `config.addStyleAfter`.
5. Записывается `./src/js/entry.js`, в котором:
- Подключения файлов из `config.addJsBefore`.
- Подключения js-файлов js-файлов БЭМ-блоков, использующихся на проекте (из `config.blocks`, но только если сами js-файлы существуют в папках блоков).
- Подключения файлов из `config.addJsAfter`.
6. Компилируется и обрабатывается PostCSS-ом Sass, собирается JS.
7. Копируются все статичные файлы (список в `config.copyAssets`) и картинки БЭМ-блоков (подпапка `img/` в папке используемого блока).
8. Запускается слежение и сервер.
9. PROFIT
### Изменение в папке, откуда собирается растровый спрайт
### Изменение в папке, откуда собирается векторный спрайт
### Изменение в папке добавочных картинок
### Изменение в папке добавочных файлов
### Изменение файла `config.json`
добавить возможность включать в сборку блоки, не найденные на странице
## СТАРОЕ
---
<table>
<thead>
<tr>
<th>Команда</th>
<th>Результат</th>
</tr>
</thead>
<tbody>
<tr>
<td width="22%"><code>npm i</code></td>
<td>Установить зависимости</td>
</tr>
<tr>
<td><code>npm start</code></td>
<td>Запустить сборку, сервер и слежение за файлами</td>
</tr>
<tr>
<td><code>npm start ЗАДАЧА</code></td>
<td>Запустить задачу с названием ЗАДАЧА (список задач в <code>./gulpfile.js</code>)</td>
</tr>
<tr>
<td><code>npm run img-opt</code></td>
<td>Оптимизация изображений из папки <code>./src/img</code></td>
</tr>
<tr>
<td><code>npm run build</code></td>
<td>Сборка проекта без карт кода (сжатый вид, как результат работы)</td>
</tr>
<tr>
<td><code>npm run deploy</code></td>
<td>Сборка проекта без карт кода и отправка содержимого папки сборки на github-pages</td>
</tr>
<tr>
<td><code>npm run test:style</code></td>
<td>Проверка стилевой составляющей проекта <a href="https://stylelint.io/">stylelint</a></td>
</tr>
<tr>
<td><code>npm start test:pug</code></td>
<td>Проверка pug-файлов проекта <a href="https://github.com/nicothin/gulp-pug-lint">форкнутым gulp-pug-lint</a></td>
</tr>
</tbody>
</table>
Предполагается, что все команды вы выполняете в bash (для OSX и Linux это самый обычный встроенный терминал, для Windows это, к примеру, Git Bash). В Windows установку пакетов (`npm i`) нужно выполять в терминале, запущенном от имени администратора.
## Как начать новый проект c этим репозиторием ## Как начать новый проект c этим репозиторием
1. Клонировать этот репозиторий в новую папку (`git clone https://github.com/nicothin/NTH-start-project.git new-project`, см. [шпаргалку](https://github.com/nicothin/web-development/tree/master/git#%D0%9A%D0%BB%D0%BE%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F)) и зайти в неё (`cd new-project`). 1. Клонировать этот репозиторий в новую папку (`git clone https://github.com/nicothin/NTH-start-project.git new-project`, см. [шпаргалку](https://github.com/nicothin/web-development/tree/master/git#%D0%9A%D0%BB%D0%BE%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F)) и зайти в неё (`cd new-project`).
2. Стереть историю разработки этого репозитория (`rm -rf .git`), инициировать новый (`git init`), создать удалённый репозиторий и привязать его (`git remote add origin АДРЕС`, см. [шпаргалку](https://github.com/nicothin/web-development/tree/master/git#%D0%A3%D0%B4%D0%B0%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B5-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8)). 2. Стереть историю разработки этого репозитория (`rm -rf .git`), инициировать новый (`git init`), создать удалённый репозиторий и привязать его (`git remote add origin АДРЕС`, см. [шпаргалку](https://github.com/nicothin/web-development/tree/master/git#%D0%A3%D0%B4%D0%B0%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B5-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8)).
3. Отредактировать `README.md`, `package.json` (название проекта, автор, лицензия, сторонние пакеты и пр.) и `projectConfig.json` (нужные на проекте блоки, сторонние пакеты). Удалив пакет из `package.json`, не забудьте убрать его из сборки в `projectConfig.json`. 3. Отредактировать `LICENSE`, `README.md`, `package.json` (название проекта, автор, лицензия, необходимые пакеты и пр.) и `config.js` (нужные на проекте блоки, сторонние пакеты). Удалив пакет из `package.json`, не забудьте убрать его из `config.js`.
4. Установить зависимости (`npm i`). 4. Установить зависимости (`npm i`).
5. Запустить сервер разработки (`npm start`). 5. Запустить сервер разработки (`npm start`).
Если при вызове `npm start` ничего не происходит, смотрите `./projectConfig.json` (вероятно, он содержит синтаксическую ошибку, проверить можно [линтером](http://jsonlint.com/)).
## Парадигма ## Парадигма
- Именование классов по БЭМ, разметка в [pug](https://pugjs.org/) и стилизация [Sass](http://sass-lang.com/). См. [Как работать с CSS-препроцессорами и БЭМ](http://nicothin.github.io/idiomatic-pre-CSS/) - Именование классов по БЭМ, разметка в [pug](https://pugjs.org/) и стилизация [Sass](http://sass-lang.com/). См. [Как работать с CSS-препроцессорами и БЭМ](http://nicothin.github.io/idiomatic-pre-CSS/)
- Каждый БЭМ-блок в своей папке внутри `./src/blocks/`. - Каждый БЭМ-блок в своей папке внутри `src/blocks/`.
- Список использованных в проекте БЭМ-блоков и доп. файлов указан в `./projectConfig.json`. Это главный конфигурационный файл проекта. - Список использованных в проекте доп. файлов указан в `config.js`.
- Есть глобальные файлы: стилевые (стили печати), js (по умолчанию пуст), шрифты, картинки. - Есть глобальные файлы: стилевые (стили печати), js (по умолчанию пуст), шрифты, картинки.
- Диспетчер подключения стилей `./src/scss/style.scss` генерируется автоматически при старте любой gulp-задачи (на основе данных из `./projectConfig.json`). - Список pug-примесей `src/pug/mixins.pug` генерируется автоматически, содержит `include` всех существующих pug-файлов блоков.
- Список pug-примесей `./src/pug/mixins.pug` генерируется автоматически при старте любой gulp-задачи (на основе данных из `./projectConfig.json`), содержит `include` всех существующих pug-файлов блоков (pug-файл блока не является обязательным). - Диспетчер подключения стилей `src/scss/style.scss` генерируется автоматически.
- Перед созданием коммита запускается проверка стилевых файлов, входящих в коммит и всех pug-файлов. При наличии ошибок коммит не происходит (ошибки будут выведены в терминал). - Входная точка обработки js (`src/js/entry.js`) генерируется автоматически.
- Есть механизм быстрого создания нового блока: `node createBlock.js new-block` (создаёт файлы, папки, прописывает блок в `./projectConfig.json`). - Перед созданием коммита запускается проверка файлов, входящих в коммит. При наличии ошибок коммит не происходит, ошибки будут выведены в терминал.
- Есть механизм быстрого создания нового блока: `node createBlock.js new-block` (создаёт файлы, папки).
## Разметка ## Разметка
Используется [pug](https://pugjs.org/api/getting-started.html). HTML никак не обрабатывается. Используется [pug](https://pugjs.org/api/getting-started.html). HTML никак не обрабатывается.
По умолчанию используются [наследование шаблонов](https://pugjs.org/language/inheritance.html) — все страницы (см. `./src/index.pug`) являются расширениями шаблонов, в страницах описывается только содержимое «шапки», «подвала» и контентной области посредством [блоков](https://pugjs.org/language/inheritance.html#block-append-prepend). По умолчанию используются [наследование шаблонов](https://pugjs.org/language/inheritance.html) — все страницы (см. `src/index.pug`) являются расширениями шаблонов, в страницах описывается только содержимое «шапки», «подвала» и контентной области посредством [блоков](https://pugjs.org/language/inheritance.html#block-append-prepend).
Каждый блок (в `./src/blocks/`) может содержать pug-файл с одноименной примесью, который будет взят includ-ом в файле `./src/pug/mixins.pug` (формируется автоматически на основании списка используемых на проекте блоков).
Каждый блок (в `src/blocks/`) может содержать pug-файл с одноименной примесью, который будет взят includ-ом в файле `src/pug/mixins.pug`.
## Стили ## Стили
Файл-диспетчер подключений (`./src/scss/style.scss`) формируется автоматически на основании указанных в `./projectConfig.json` блоков и доп. файлов. Писать в `./src/scss/style.scss` что-либо руками бессмысленно: при старте автоматизации файл будет перезаписан. Диспетчер подключений (`src/scss/style.scss`) формируется автоматически, писать в него что-либо руками бессмысленно: при старте автоматизации файл будет перезаписан.
Используемый постпроцессинг: Используемый постпроцессинг:
...@@ -175,9 +85,9 @@ src/ ...@@ -175,9 +85,9 @@ src/
2. [css-mqpacker](https://github.com/hail2u/node-css-mqpacker) 2. [css-mqpacker](https://github.com/hail2u/node-css-mqpacker)
3. [postcss-import](https://github.com/postcss/postcss-import) 3. [postcss-import](https://github.com/postcss/postcss-import)
4. [postcss-inline-svg](https://github.com/TrySound/postcss-inline-svg) 4. [postcss-inline-svg](https://github.com/TrySound/postcss-inline-svg)
5. [gulp-cleancss](https://github.com/mgcrea/gulp-cleancss) (только в режиме сборки без карт кода)
6. [postcss-object-fit-images](https://github.com/ronik-design/postcss-object-fit-images) (в паре с [полифилом](https://github.com/bfred-it/object-fit-images)) 6. [postcss-object-fit-images](https://github.com/ronik-design/postcss-object-fit-images) (в паре с [полифилом](https://github.com/bfred-it/object-fit-images))
### Модульная сетка (flexbox) ### Модульная сетка (flexbox)
По умолчанию в сборку берётся [файл с примесями](https://github.com/nicothin/NTH-start-project/blob/master/src/scss/mixins/grid-mixins.scss), возвращающими правила модульной сетки. Никаких селекторов в CSS не добавляет, нужно писать семантические селекторы и вызывать примеси, передавая им настройки сетки. Настройки по умолчанию вынесены в переменные (`$grid-columns: 12;` и `$grid-gutter-width: 30px;`). По умолчанию в сборку берётся [файл с примесями](https://github.com/nicothin/NTH-start-project/blob/master/src/scss/mixins/grid-mixins.scss), возвращающими правила модульной сетки. Никаких селекторов в CSS не добавляет, нужно писать семантические селекторы и вызывать примеси, передавая им настройки сетки. Настройки по умолчанию вынесены в переменные (`$grid-columns: 12;` и `$grid-gutter-width: 30px;`).
...@@ -185,227 +95,43 @@ src/ ...@@ -185,227 +95,43 @@ src/
Посмотреть примеры и попробовать вживую можно в [этом примере с codepen.io](https://codepen.io/nicothin/pen/aJEOwE?editors=1100). Посмотреть примеры и попробовать вживую можно в [этом примере с codepen.io](https://codepen.io/nicothin/pen/aJEOwE?editors=1100).
## Блоки ## Блоки
Каждый блок лежит в `./src/blocks/` в своей папке. Каждый блок — как минимум, папка и одноимённые scss- и pug-файл. Каждый блок лежит в `src/blocks/` в своей папке.
Возможное содержимое блока: Возможное содержимое блока:
```bash ```bash
demo-block/ # Папка блока. demo-block/ # Папка блока.
img/ # Изображения, используемые блоком и обрабатываемые автоматикой сборки.
bg-img/ # Изображения для использования в стилях (не обрабатываются автоматикой сборки). bg-img/ # Изображения для использования в стилях (не обрабатываются автоматикой сборки).
img/ # Изображения, используемые блоком и обрабатываемые автоматикой сборки.
demo-block.pug # Разметка (pug-примесь, отдающая разметку блока, описание API примеси). demo-block.pug # Разметка (pug-примесь, отдающая разметку блока, описание API примеси).
demo-block.scss # Стилевой файл блока. demo-block.scss # Стилевой файл блока.
demo-block.js # js-файл блока. demo-block.js # js-файл блока.
demo-block--mod.scss # Отдельный стилевой файл БЭМ-модификатора блока.
demo-block--mod.js # js-файл для отдельного БЭМ-модификатора блока.
readme.md # Описание для документации, подсказки. readme.md # Описание для документации, подсказки.
``` ```
## Подключение блоков ## Подключение блоков
Список используемых блоков и доп. файлов указан в `./projectConfig.json`. Список файлов и папок, взятых в обработку можно увидеть в терминале, если раскомментировать строку `console.log(lists);` в `gulpfile.js`. Если блок (css-класс блока) использован в разметке, то блок будет взят в сборку.
**ВНИМАНИЕ!** `./projectConfig.json` — это JSON. Это строгий синтаксис, у последнего элемента в любом контексте не должно быть запятой в конце строки.
### `blocks`
Объект с блоками, используемыми на проекте. Каждый блок — отдельная папка с файлами, по умолчанию лежат в `./src/blocks/`.
Каждое подключение блока — массив, который можно оставить пустым или указать файлы элементов или модификаторов, если они написаны в виде отдельных файлов. В обоих случаях в обработку будут взяты одноименные стилевые файлы, pug-файл, js-файлы и картинки из папки `img/` блока.
Пример, подключающий 3 блока:
```
"blocks": {
"page": [],
"page-header": [],
"page-footer": []
}
```
### `addCssBefore`
Массив с дополнительными стилевыми файлами, которые будут взяты в компиляцию ПЕРЕД стилевыми файлами блоков.
Пример, берущий в компиляцию переменные, примеси, функции и один дополнительный файл из папки зависимостей (он будет преобразован в css-импорт, который при постпроцессинге ([postcss-import](https://github.com/postcss/postcss-import)) будет заменен на содержимое файла).
```
"addCssBefore": [
"./src/scss/variables.scss",
"./src/scss/mixins.scss",
"./src/scss/functions.scss",
"../../node_modules/owl.carousel/dist/assets/owl.carousel.css"
],
```
### `addCssAfter`
Массив с дополнительными стилевыми файлами, которые будут взяты в компиляцию ПОСЛЕ стилевых файлов блоков.
```
"addCssAfter": [
"./src/scss/print.scss"
],
```
### `singleCompiled`
Массив стилевых файлов, которые будут скомпилированы независимо.
Пример: указанный файл будет скомпилирован в папку сборки как `blocks-library.css`
```
"singleCompiled": [
"./src/scss/blocks-library.scss"
],
```
### `addJsBefore`
Массив js-файлов, которые будут взяты в обработку (конкатенация/сжатие) ПЕРЕД js-файлами блоков.
Пример, добавляющий в список обрабатываемых js-файлов несколько зависимостей:
```
"addJsBefore": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery-migrate/dist/jquery-migrate.min.js",
"./node_modules/nouislider/distribute/nouislider.js"
],
```
### `addJsAfter`
Массив js-файлов, которые будут взяты в обработку (конкатенация/сжатие) ПОСЛЕ js-файлов блоков.
Пример, добавляющий в конец списка обрабатываемых js-файлов глобальный скрипт.
```
"addJsAfter": [
"./src/js/global-script.js"
],
```
### `addImages`
Массив дополнительных изображений, добавляемый ПЕРЕД массивом изображений из блоков (внимание: при совпадении имен файлов, файлы из блоков имеют более высокий приоритет и затрут файлы из этого массива).
```
"addImages": [
"./src/img/*.{jpg,jpeg,gif,png,svg,ico}"
],
```
### `copiedCss`
Массив css-файлов, которые копируются в папку сборки, подпапку `css/`
### `copiedJs`
Массив js-файлов, которые копируются в папку сборки, подпапку `js/`
### Пример `./projectConfig.json`
```json
{
"blocks": {
"page-header": [],
"page-footer": [
"__extra-element",
"--extra-modifier"
]
},
"addCssBefore": [
"./src/scss/variables.scss"
],
"addCssAfter": [
"./src/scss/print.scss"
],
"singleCompiled": [],
"addJsBefore": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery-migrate/dist/jquery-migrate.min.js"
],
"addJsAfter": [
"./src/js/global-script.js"
],
"addImages": [
"./src/img/*.{jpg,jpeg,gif,png,svg}"
],
"copiedCss": [],
"copiedJs": [],
"dirs": {
"srcPath": "./src/",
"buildPath": "./build/",
"blocksDirName": "blocks"
}
}
```
В результате в обработку будут взяты (в указанной последовательности):
```bash
css:
[ './src/scss/variables.scss',
'./src/blocks/page-header/page-header.scss',
'./src/blocks/page-footer/page-footer.scss',
'./src/blocks/page-footer/page-footer__extra-element.scss',
'./src/blocks/page-footer/page-footer--extra-modifier.scss',
'./src/scss/print.scss' ],
js:
[ './node_modules/jquery/dist/jquery.min.js',
'./node_modules/jquery-migrate/dist/jquery-migrate.min.js',
'./src/blocks/page-header/page-header.js',
'./src/blocks/page-footer/page-footer.js',
'./src/blocks/page-footer/page-footer__extra-element.js',
'./src/blocks/page-footer/page-footer--extra-modifier.js',
'./src/js/global-script.js' ],
img:
[ './src/img/*.{jpg,jpeg,gif,png,svg}',
'./src/blocks/page-header/img/*.{jpg,jpeg,gif,png,svg}',
'./src/blocks/page-footer/img/*.{jpg,jpeg,gif,png,svg}' ]
pug:
[ './src/blocks/page-header/page-header.pug',
'./src/blocks/page-footer/page-footer.pug' ]
```
Если нужно взять в сборку блок без использования его класса в разметке, нужно упомянуть блок в `config.js#alwaysAddBlocks`.
## Удобное создание нового блока ## Удобное создание нового блока
Предусмотрена команда для быстрого создания файловой структуры нового блока. По умолчанию создаются: scss- и pug-файл, `readme.md` блока и его подпапки `img` и `bg-img` Предусмотрена команда для быстрого создания файловой структуры нового блока. По умолчанию создаются: scss-файл и подпапки `img`, `bg-img`
```bash ```bash
# формат: node createBlock.js ИМЯБЛОКА [доп. расширения через пробел] # формат: node createBlock.js ИМЯБЛОКА [доп. расширения через пробел]
node createBlock.js block-test # создаст папку блока, block-test.pug, block-test.scss, подпапки img/ и bg-img/ для этого блока node createBlock.js block-test # создаст папку блока, block-test.scss, подпапки img/ и bg-img/ для этого блока
node createBlock.js block-test pug js # создаст папку блока, block-test.scss, block-test.pug, block-test.js, подпапки img/ и bg-img/ для этого блока
``` ```
Если блок уже существует, файлы не будут затёрты, но создадутся те файлы, которые ещё не существуют. Если блок уже существует, файлы не будут затёрты, но создадутся те файлы, которые ещё не существуют.
## Назначение папок
```bash
build/ # Папка сборки, здесь работает сервер автообновлений.
src/ # Исходные файлы.
blocks/ # - блоки проекта.
css/ # - добавочные css-файлы (нужно подключить в copiedCss, иначе игнорируются).
favicon/ # - файлы для фавиконок и смежных технологий.
fonts/ # - шрифты проекта (будут автоматически скопированы в папку сборки).
img/ # - добавочные или общие для нескольких блоков картинки (нужно подключить в addImages, иначе игнорируются).
js/ # - добавочные js-файлы (нужно подключить в addJsBefore, addJsAfter или copiedJs, иначе игнорируются).
pug/ # - примеси, шаблоны pug.
scss/ # - стили (файл style.scss скомпилируется, прочие нужно подключить в addCssBefore, addCssAfter или singleCompiled, иначе игнорируются).
index.pug # - главная страница проекта.
blocks-demo.pug # - библиотека блоков.
```
## Нравится проект? ## Нравится проект?
Ставьте звезду в верхнем правом углу и/или [угостите меня кофе](https://money.yandex.ru/to/41001252765094), переведя сколь угодно символическую сумму. Ставьте звезду в верхнем правом углу и/или [угостите меня кофе](https://money.yandex.ru/to/41001252765094), переведя сколь угодно символическую сумму.
...@@ -21,7 +21,7 @@ let config = ...@@ -21,7 +21,7 @@ let config =
], ],
"addJsBefore": [], "addJsBefore": [],
"addJsAfter": [ "addJsAfter": [
"script.js" "./script.js"
], ],
"addAssets": { "addAssets": {
"src/img/demo-avatar-*": "img/", "src/img/demo-avatar-*": "img/",
......
...@@ -5,19 +5,19 @@ ...@@ -5,19 +5,19 @@
// Использование: node createBlock.js [имя блока] [доп. расширения через пробел] // Использование: node createBlock.js [имя блока] [доп. расширения через пробел]
const fs = require('fs'); const fs = require('fs');
const projectConfig = require('./projectConfig.json'); const projectConfig = require('./config.js');
const dirs = projectConfig.dirs; const dir = projectConfig.dir;
const mkdirp = require('mkdirp'); const mkdirp = require('mkdirp');
const blockName = process.argv[2]; // получим имя блока const blockName = process.argv[2];
const defaultExtensions = ['scss', 'md', 'pug', 'img', 'bg-img']; // расширения по умолчанию const defaultExtensions = ['scss', 'img', 'bg-img']; // расширения по умолчанию
const extensions = uniqueArray(defaultExtensions.concat(process.argv.slice(3))); // добавим введенные при вызове расширения (если есть) const extensions = uniqueArray(defaultExtensions.concat(process.argv.slice(3)));
// Если есть имя блока // Если есть имя блока
if (blockName) { if (blockName) {
const dirPath = `${dirs.srcPath + dirs.blocksDirName}/${blockName}/`; // полный путь к создаваемой папке блока const dirPath = `${dir.blocks}${blockName}/`; // полный путь к создаваемой папке блока
mkdirp(dirPath, (err) => { // создаем mkdirp(dirPath, (err) => { // создаем
// Если какая-то ошибка — покажем // Если какая-то ошибка — покажем
if (err) { if (err) {
console.error(`[NTH] Отмена операции: ${err}`); console.error(`[NTH] Отмена операции: ${err}`);
...@@ -25,45 +25,31 @@ if (blockName) { ...@@ -25,45 +25,31 @@ if (blockName) {
// Нет ошибки, поехали! // Нет ошибки, поехали!
else { else {
console.log(`[NTH] Создание папки ${dirPath} (если отсутствует)`); console.log(`[NTH] Создание папки: ${dirPath} (если отсутствует)`);
// Обходим массив расширений и создаем файлы, если они еще не созданы // Обходим массив расширений и создаем файлы, если они еще не созданы
extensions.forEach((extension) => { extensions.forEach((extension) => {
const filePath = `${dirPath + blockName}.${extension}`; // полный путь к создаваемому файлу const filePath = `${dirPath + blockName}.${extension}`; // полный путь к создаваемому файлу
let fileContent = ''; // будущий контент файла let fileContent = ''; // будущий контент файла
let fileCreateMsg = ''; // будущее сообщение в консоли при создании файла let fileCreateMsg = ''; // будущее сообщение в консоли при создании файла
// Если это SCSS
if (extension === 'scss') { if (extension === 'scss') {
fileContent = `// В этом файле должны быть стили для БЭМ-блока ${blockName}, его элементов,\n// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...\n// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority\n\n.${blockName} {\n\n $block-name: &; // #{$block-name}__element\n}\n`; fileContent = `// В этом файле должны быть стили для БЭМ-блока ${blockName}, его элементов,\n// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...\n// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority\n\n.${blockName} {\n\n $block-name: &; // #{$block-name}__element\n}\n`;
// fileCreateMsg = ''; // fileCreateMsg = '';
// Добавление импорта файла в диспетчер подключений, если он есть и в нем есть импорты
// TODO
} }
// Если это HTML
else if (extension === 'html') {
fileContent = `<div class="${blockName}">content</div>\n`;
}
// Если это JS
else if (extension === 'js') { else if (extension === 'js') {
fileContent = `// document.addEventListener(\'DOMContentLoaded\', function(){});\n// (function(){\n// код\n// }());\n`; fileContent = `// document.addEventListener(\'DOMContentLoaded\', function(){});\n// (function(){\n// код\n// }());\n`;
} }
// Если это md else if (extension === 'md') {
else if (extension === 'js') {
fileContent = ''; fileContent = '';
} }
// Если это pug
else if (extension === 'pug') { else if (extension === 'pug') {
fileContent = `//- Все примеси в этом файле должны начинаться c имени блока (${blockName})\n\nmixin ${blockName}(text, mods)\n\n //- Принимает:\n //- text {string} - текст\n //- mods {string} - список модификаторов\n //- Вызов:\n +${blockName}('Текст', 'some-mod')\n\n -\n // список модификаторов\n var allMods = '';\n if(typeof(mods) !== 'undefined' && mods) {\n var modsList = mods.split(',');\n for (var i = 0; i < modsList.length; i++) {\n allMods = allMods + ' ${blockName}--' + modsList[i].trim();\n }\n }\n\n .${blockName}(class=allMods)&attributes(attributes)\n .${blockName}__inner!= text\n`; fileContent = `//- Все примеси в этом файле должны начинаться c имени блока (${blockName})\n\nmixin ${blockName}(text, mods)\n\n //- Принимает:\n //- text {string} - текст\n //- mods {string} - список модификаторов\n //- Вызов:\n +${blockName}('Текст', 'some-mod')\n\n -\n // список модификаторов\n var allMods = '';\n if(typeof(mods) !== 'undefined' && mods) {\n var modsList = mods.split(',');\n for (var i = 0; i < modsList.length; i++) {\n allMods = allMods + ' ${blockName}--' + modsList[i].trim();\n }\n }\n\n .${blockName}(class=allMods)&attributes(attributes)\n .${blockName}__inner!= text\n block\n`;
// Добавление примеси файл примесей, если он есть и в нем есть подключение примесей
// TODO
} }
// Если нужна подпапка для картинок
else if (extension === 'img') { else if (extension === 'img') {
const imgFolder = `${dirPath}img/`; const imgFolder = `${dirPath}img/`;
if (fileExist(imgFolder) === false) { if (fileExist(imgFolder) === false) {
...@@ -76,7 +62,6 @@ if (blockName) { ...@@ -76,7 +62,6 @@ if (blockName) {
} }
} }
// Если нужна подпапка для необрабатываемых картинок
else if (extension === 'bg-img') { else if (extension === 'bg-img') {
const imgFolder = `${dirPath}bg-img/`; const imgFolder = `${dirPath}bg-img/`;
if (fileExist(imgFolder) === false) { if (fileExist(imgFolder) === false) {
...@@ -89,7 +74,6 @@ if (blockName) { ...@@ -89,7 +74,6 @@ if (blockName) {
} }
} }
// Создаем файл, если он еще не существует
if (fileExist(filePath) === false && extension !== 'img' && extension !== 'bg-img' && extension !== 'md') { if (fileExist(filePath) === false && extension !== 'img' && extension !== 'bg-img' && extension !== 'md') {
fs.writeFile(filePath, fileContent, (err) => { fs.writeFile(filePath, fileContent, (err) => {
if (err) { if (err) {
...@@ -117,38 +101,23 @@ if (blockName) { ...@@ -117,38 +101,23 @@ if (blockName) {
} }
}); });
// Добавим созданный блок в projectConfig.json
let hasThisBlock = false;
for (const block in projectConfig.blocks) {
if (block === blockName) {
hasThisBlock = true;
break;
}
}
if (!hasThisBlock) {
projectConfig.blocks[blockName] = [];
const newPackageJson = JSON.stringify(projectConfig, '', 2);
fs.writeFileSync('./projectConfig.json', newPackageJson);
console.log('[NTH] Подключение блока добавлено в projectConfig.json');
}
} }
}); });
} else { } else {
console.log('[NTH] Отмена операции: не указан блок'); console.log('[NTH] Отмена операции: не указан блок');
} }
// Оставить в массиве только уникальные значения (убрать повторы)
function uniqueArray(arr) { function uniqueArray(arr) {
const objectTemp = {}; const objectTemp = {};
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
const str = arr[i]; const str = arr[i];
objectTemp[str] = true; // запомнить строку в виде свойства объекта objectTemp[str] = true;
} }
return Object.keys(objectTemp); return Object.keys(objectTemp);
} }
// Проверка существования файла
function fileExist(path) { function fileExist(path) {
const fs = require('fs'); const fs = require('fs');
try { try {
......
...@@ -14,17 +14,15 @@ const jsonFormat = require('json-format'); ...@@ -14,17 +14,15 @@ const jsonFormat = require('json-format');
const browserSync = require('browser-sync').create(); const browserSync = require('browser-sync').create();
const debug = require('gulp-debug'); const debug = require('gulp-debug');
const sass = require('gulp-sass'); const sass = require('gulp-sass');
const notify = require('gulp-notify');
const gulpIf = require('gulp-if'); const gulpIf = require('gulp-if');
const browserify = require('browserify'); const webpackStream = require('webpack-stream');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer'); const buffer = require('vinyl-buffer');
const uglify = require('gulp-uglify'); const uglify = require('gulp-uglify');
const postcss = require('gulp-postcss'); const postcss = require('gulp-postcss');
const autoprefixer = require("autoprefixer"); const autoprefixer = require("autoprefixer");
const mqpacker = require("css-mqpacker"); const mqpacker = require("css-mqpacker");
const atImport = require("postcss-import"); const atImport = require("postcss-import");
const cleanss = require('gulp-cleancss'); const csso = require('gulp-csso');
const inlineSVG = require('postcss-inline-svg'); const inlineSVG = require('postcss-inline-svg');
const objectFitImages = require('postcss-object-fit-images'); const objectFitImages = require('postcss-object-fit-images');
const cpy = require('cpy'); const cpy = require('cpy');
...@@ -34,6 +32,8 @@ const spritesmith = require('gulp.spritesmith'); ...@@ -34,6 +32,8 @@ const spritesmith = require('gulp.spritesmith');
const merge = require('merge-stream'); const merge = require('merge-stream');
const imagemin = require('gulp-imagemin'); const imagemin = require('gulp-imagemin');
const prettyHtml = require('gulp-pretty-html'); const prettyHtml = require('gulp-pretty-html');
const ghpages = require('gh-pages');
const path = require('path');
// Глобальные настройки этого запуска // Глобальные настройки этого запуска
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV == 'dev'; const isDev = !process.env.NODE_ENV || process.env.NODE_ENV == 'dev';
...@@ -62,7 +62,7 @@ let prettyOption = { ...@@ -62,7 +62,7 @@ let prettyOption = {
// Список и настройки плагинов postCSS // Список и настройки плагинов postCSS
let postCssPlugins = [ let postCssPlugins = [
autoprefixer(), autoprefixer({grid: true}),
mqpacker({ mqpacker({
sort: true sort: true
}), }),
...@@ -216,43 +216,25 @@ function compileSass() { ...@@ -216,43 +216,25 @@ function compileSass() {
.pipe(debug({title: 'Compiles:'})) .pipe(debug({title: 'Compiles:'}))
.pipe(sass({includePaths: [__dirname+'/']})) .pipe(sass({includePaths: [__dirname+'/']}))
.pipe(postcss(postCssPlugins)) .pipe(postcss(postCssPlugins))
.pipe(gulpIf(!isDev, cleanss())) .pipe(csso({
restructure: false,
}))
.pipe(dest(`${dir.build}/css`, { sourcemaps: '.' })) .pipe(dest(`${dir.build}/css`, { sourcemaps: '.' }))
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
exports.compileSass = compileSass; exports.compileSass = compileSass;
function buildJs() {
// TODO впилить сюда вебпацкЪ
// var sourcemaps = require('gulp-sourcemaps');
return browserify({
entries: dir.src + '/js/entry.js',
debug: true
})
.transform('babelify', {presets: ['@babel/preset-env',]})
.bundle()
.pipe(source('bundle.js'))
.pipe(buffer())
// .pipe(sourcemaps.init({loadMaps: true}))
.pipe(gulpIf(!isDev, uglify()))
// .pipe(sourcemaps.write('./'))
.pipe(dest(dir.build + '/js'));
}
exports.buildJs = buildJs;
function writeJsRequiresFile(cb) { function writeJsRequiresFile(cb) {
// console.log( config.blocks );
let msg = `\n/*!*${doNotEditMsg.replace(/\n /gm,'\n * ').replace(/\n\n$/,'\n */\n\n')}`; let msg = `\n/*!*${doNotEditMsg.replace(/\n /gm,'\n * ').replace(/\n\n$/,'\n */\n\n')}`;
let jsRequires = msg; let jsRequires = msg;
config.addJsBefore.forEach(function(src) { nth.config.addJsBefore.forEach(function(src) {
jsRequires += `require('${src}');\n`; jsRequires += `require('${src}');\n`;
}); });
config.blocks.forEach(function(block) { nth.blocksFromHtml.forEach(function(block) {
if(fileExist(`${dir.blocks}${block}/${block}.js`)) jsRequires += `require('../blocks/${block}/${block}.js');\n`; if(fileExist(`${dir.blocks}${block}/${block}.js`)) jsRequires += `require('../blocks/${block}/${block}.js');\n`;
}); });
config.addJsAfter.forEach(function(src) { nth.config.addJsAfter.forEach(function(src) {
jsRequires += `require('${src}');\n`; jsRequires += `require('${src}');\n`;
}); });
jsRequires += msg; jsRequires += msg;
...@@ -262,68 +244,71 @@ function writeJsRequiresFile(cb) { ...@@ -262,68 +244,71 @@ function writeJsRequiresFile(cb) {
exports.writeJsRequiresFile = writeJsRequiresFile; exports.writeJsRequiresFile = writeJsRequiresFile;
function writeBlocksLibSass(cb) { function buildJs() {
let allBlocksWithStyleFiles = getDirectories('scss'); return src(`${dir.src}js/entry.js`)
let styleImports = ''; .pipe(plumber())
config.addStyleBefore.forEach(function(src) { .pipe(webpackStream({
styleImports += `@import "${src}";\n`; mode: 'development',
}); output: {
allBlocksWithStyleFiles.forEach(function(block) { filename: 'bundle.js',
let src = `${dir.blocks}${block}/${block}.scss`; },
styleImports += `@import "${src}";\n`; module: {
}); rules: [
config.addStyleAfter.forEach(function(src) { {
styleImports += `@import "${src}";\n`; test: /\.(js)$/,
}); exclude: /(node_modules)/,
fs.writeFileSync(`${dir.src}scss/blocks-lib.scss`, styleImports); loader: 'babel-loader',
cb(); query: {
presets: ['@babel/preset-env']
}
}
]
},
// externals: {
// jquery: 'jQuery'
// }
}))
.pipe(gulpIf(!isDev, uglify()))
.pipe(dest(`${dir.build}js`));
} }
exports.writeBlocksLibSass = writeBlocksLibSass; exports.buildJs = buildJs;
function writeBlocksLibJs(cb) { // function writeBlocksLibSass(cb) {
let allBlocksWithJsFiles = getDirectories('js'); // let allBlocksWithStyleFiles = getDirectories('scss');
let jsRequires = ''; // let styleImports = '';
config.addJsBefore.forEach(function(src) { // config.addStyleBefore.forEach(function(src) {
jsRequires += `require('${src}');\n`; // styleImports += `@import "${src}";\n`;
}); // });
allBlocksWithJsFiles.forEach(function(block) { // allBlocksWithStyleFiles.forEach(function(block) {
jsRequires += `require('../blocks/${block}/${block}.js');\n`; // let src = `${dir.blocks}${block}/${block}.scss`;
}); // styleImports += `@import "${src}";\n`;
config.addJsAfter.forEach(function(src) { // });
jsRequires += `require('${src}');\n`; // config.addStyleAfter.forEach(function(src) {
}); // styleImports += `@import "${src}";\n`;
fs.writeFileSync(`${dir.src}js/blocks-lib.js`, jsRequires); // });
cb(); // fs.writeFileSync(`${dir.src}scss/blocks-lib.scss`, styleImports);
} // cb();
exports.writeBlocksLibJs = writeBlocksLibJs; // }
// exports.writeBlocksLibSass = writeBlocksLibSass;
function compileBlocksLibSass() { // function writeBlocksLibJs(cb) {
return src(`${dir.src}scss/blocks-lib.scss`, { sourcemaps: true }) // let allBlocksWithJsFiles = getDirectories('js');
.pipe(plumber()) // let jsRequires = '';
.pipe(debug({title: 'Compiles:'})) // config.addJsBefore.forEach(function(src) {
.pipe(sass({includePaths: [__dirname+'/']})) // jsRequires += `require('${src}');\n`;
.pipe(postcss(postCssPlugins)) // });
.pipe(dest(`${dir.build}/css`, { sourcemaps: '.' })) // allBlocksWithJsFiles.forEach(function(block) {
.pipe(browserSync.stream()); // jsRequires += `require('../blocks/${block}/${block}.js');\n`;
} // });
exports.compileBlocksLibSass = compileBlocksLibSass; // config.addJsAfter.forEach(function(src) {
// jsRequires += `require('${src}');\n`;
// });
function buildBlocksLibJs() { // fs.writeFileSync(`${dir.src}js/blocks-lib.js`, jsRequires);
return browserify({ // cb();
entries: dir.src + '/js/blocks-lib.js', // }
debug: true // exports.writeBlocksLibJs = writeBlocksLibJs;
})
.transform('babelify', {presets: ['@babel/preset-env',]})
.bundle()
.pipe(source('blocks-lib.js'))
.pipe(buffer())
.pipe(gulpIf(!isDev, uglify()))
.pipe(dest(dir.build + '/js'));
}
exports.buildBlocksLibJs = buildBlocksLibJs;
function clearBuildDir() { function clearBuildDir() {
...@@ -340,6 +325,11 @@ function reload(done) { ...@@ -340,6 +325,11 @@ function reload(done) {
done(); done();
} }
function deploy(cb) {
ghpages.publish(path.join(process.cwd(), dir.build), cb);
}
exports.deploy = deploy;
function serve() { function serve() {
...@@ -354,9 +344,8 @@ function serve() { ...@@ -354,9 +344,8 @@ function serve() {
// Страницы: изменение, добавление // Страницы: изменение, добавление
watch([`${dir.src}pages/**/*.pug`], { events: ['change', 'add'], delay: 100 }, series( watch([`${dir.src}pages/**/*.pug`], { events: ['change', 'add'], delay: 100 }, series(
compilePugFast, compilePugFast,
parallel(writeSassImportsFile, ), parallel(writeSassImportsFile, writeJsRequiresFile),
// parallel(writeSassImportsFile, writeJsRequiresFile), parallel(compileSass, buildJs),
// parallel(compileSass, buildJs),
reload reload
)); ));
...@@ -375,7 +364,7 @@ function serve() { ...@@ -375,7 +364,7 @@ function serve() {
watch([`${dir.blocks}**/*.pug`], { events: ['change', 'add'], delay: 100 }, series( watch([`${dir.blocks}**/*.pug`], { events: ['change', 'add'], delay: 100 }, series(
compilePug, compilePug,
writeSassImportsFile, writeSassImportsFile,
// compileSass, compileSass,
reload reload
)); ));
...@@ -385,20 +374,28 @@ function serve() { ...@@ -385,20 +374,28 @@ function serve() {
// Шаблоны pug: все события // Шаблоны pug: все события
watch([`${dir.src}pug/**/*.pug`, `!${dir.src}pug/mixins.pug`], { delay: 100 }, series( watch([`${dir.src}pug/**/*.pug`, `!${dir.src}pug/mixins.pug`], { delay: 100 }, series(
compilePug, compilePug,
parallel(writeSassImportsFile, ), parallel(writeSassImportsFile, writeJsRequiresFile),
// parallel(writeSassImportsFile, writeJsRequiresFile), parallel(compileSass, buildJs),
// parallel(compileSass, buildJs),
reload, reload,
)); ));
// // Стили Блоков: все события // Стили Блоков: все события
// watch([`${dir.blocks}**/*.scss`], { events: ['all'], delay: 100 }, series(writeSassImportsFile, writeBlocksLibSass, compileSass, compileBlocksLibSass)); watch([`${dir.blocks}**/*.scss`], { events: ['all'], delay: 100 }, series(
writeSassImportsFile,
compileSass,
));
// // Стилевые глобальные файлы: все события // Стилевые глобальные файлы: все события
// watch([`${dir.src}scss/**/*.scss`, `!${dir.src}scss/style.scss`, `!${dir.src}scss/blocks-lib.scss`], { events: ['all'], delay: 100 }, series(compileSass, compileBlocksLibSass)); watch([`${dir.src}scss/**/*.scss`, `!${dir.src}scss/style.scss`, `!${dir.src}scss/blocks-lib.scss`], { events: ['all'], delay: 100 }, series(
compileSass,
));
// // Скриптовые глобальные файлы: все события // Скриптовые глобальные файлы: все события
// watch([`${dir.src}js/**/*.js`, `!${dir.src}js/entry.js`, `!${dir.src}js/blocks-lib.js`, `${dir.blocks}**/*.js`], { events: ['all'], delay: 100 }, series(writeJsRequiresFile, writeBlocksLibJs, buildJs, buildBlocksLibJs, reload)); watch([`${dir.src}js/**/*.js`, `!${dir.src}js/entry.js`, `!${dir.src}js/blocks-lib.js`, `${dir.blocks}**/*.js`], { events: ['all'], delay: 100 }, series(
writeJsRequiresFile,
buildJs,
reload
));
// Картинки: все события // Картинки: все события
watch([`${dir.blocks}**/img/*.{jpg,jpeg,png,gif,svg,webp}`], { events: ['all'], delay: 100 }, series(copyImg, reload)); watch([`${dir.blocks}**/img/*.{jpg,jpeg,png,gif,svg,webp}`], { events: ['all'], delay: 100 }, series(copyImg, reload));
...@@ -414,31 +411,27 @@ function serve() { ...@@ -414,31 +411,27 @@ function serve() {
watch([`${dir.blocks}sprite-png/png/*.png`], { events: ['all'], delay: 100 }, series( watch([`${dir.blocks}sprite-png/png/*.png`], { events: ['all'], delay: 100 }, series(
generatePngSprite, generatePngSprite,
copyImg, copyImg,
// compileSass, compileSass,
reload, reload,
)); ));
} }
exports.default = series( exports.build = series(
parallel(clearBuildDir, writePugMixinsFile), parallel(clearBuildDir, writePugMixinsFile),
parallel(compilePugFast, copyAssets, generateSvgSprite, generatePngSprite), parallel(compilePugFast, copyAssets, generateSvgSprite, generatePngSprite),
parallel(copyImg, writeSassImportsFile), parallel(copyImg, writeSassImportsFile, writeJsRequiresFile),
// parallel(writeSassImportsFile, writeJsRequiresFile, writeBlocksLibSass, writeBlocksLibJs), parallel(compileSass, buildJs),
serve,
); );
// exports.default = series(
// parallel(clearBuildDir, writePugMixinsFile),
// parallel(compilePugFast, copyAssets),
// parallel(generateSvgSprite, generatePngSprite),
// parallel(copyImg),
// parallel(writeSassImportsFile, writeJsRequiresFile, writeBlocksLibSass, writeBlocksLibJs),
// parallel(compileSass, compileBlocksLibSass, buildJs, buildBlocksLibJs),
// serve,
// );
exports.default = series(
parallel(clearBuildDir, writePugMixinsFile),
parallel(compilePugFast, copyAssets, generateSvgSprite, generatePngSprite),
parallel(copyImg, writeSassImportsFile, writeJsRequiresFile),
parallel(compileSass, buildJs),
serve,
);
...@@ -486,19 +479,6 @@ function getClassesToBlocksList(file, enc, cb) { ...@@ -486,19 +479,6 @@ function getClassesToBlocksList(file, enc, cb) {
cb(); cb();
} }
/**
* Запись конфигурационного файла
* @param {object} config Конфиг
*/
// function writeConfig(config) {
// var settings = { type: 'space', size: 2 }
// let configText = '// Файл перезаписывается программно при работе автоматизации\nlet config =\n' + jsonFormat(config, settings) + ';\n\nmodule.exports = config;\n';
// fs.writeFile('./config.js', configText, function(err){
// if (err) throw err;
// console.log('---------- Записан новый config.js');
// });
// }
// //
/** /**
* Pug-фильтр, выводящий содержимое pug-файла в виде форматированного текста * Pug-фильтр, выводящий содержимое pug-файла в виде форматированного текста
......
'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();
}
...@@ -10,12 +10,9 @@ ...@@ -10,12 +10,9 @@
}, },
"scripts": { "scripts": {
"test:style": "stylelint \"src/**/*.scss\" --syntax=scss", "test:style": "stylelint \"src/**/*.scss\" --syntax=scss",
"test:editorconfig": "editorconfig-cli src/**/*.{js,pug}",
"test": "npm run test:style && npm run test:editorconfig && npm run build",
"start": "gulp", "start": "gulp",
"deploy": "cross-env NODE_ENV=production ./node_modules/.bin/gulp build && cross-env ./node_modules/.bin/gulp deploy", "deploy": "cross-env NODE_ENV=production ./node_modules/.bin/gulp build && cross-env ./node_modules/.bin/gulp deploy",
"build": "cross-env NODE_ENV=production npm start build", "build": "cross-env NODE_ENV=production npm start build",
"img-opt": "cross-env folder=src/img npm start img:opt",
"lint-staged": "lint-staged" "lint-staged": "lint-staged"
}, },
"browserslist": [ "browserslist": [
...@@ -29,13 +26,12 @@ ...@@ -29,13 +26,12 @@
"*.scss": "stylelint --syntax=scss" "*.scss": "stylelint --syntax=scss"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.1.6", "@babel/core": "^7.2.2",
"@babel/preset-env": "^7.1.6", "@babel/preset-env": "^7.2.3",
"@htmlacademy/editorconfig-cli": "^1.0.0", "@htmlacademy/editorconfig-cli": "^1.0.0",
"autoprefixer": "^9.3.1", "autoprefixer": "^9.3.1",
"babelify": "^10.0.0", "babel-loader": "^8.0.4",
"browser-sync": "^2.18.8", "browser-sync": "^2.18.8",
"browserify": "^16.2.3",
"cpy": "^7.0.1", "cpy": "^7.0.1",
"cross-env": "^5.0.0", "cross-env": "^5.0.0",
"css-mqpacker": "^7.0.0", "css-mqpacker": "^7.0.0",
...@@ -43,28 +39,22 @@ ...@@ -43,28 +39,22 @@
"get-classes-from-html": "^1.0.1", "get-classes-from-html": "^1.0.1",
"gh-pages": "^2.0.1", "gh-pages": "^2.0.1",
"gulp": "^4.0.0", "gulp": "^4.0.0",
"gulp-cleancss": "^0.2.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-csso": "^3.0.1",
"gulp-debug": "^4.0.0", "gulp-debug": "^4.0.0",
"gulp-if": "^2.0.2", "gulp-if": "^2.0.2",
"gulp-imagemin": "^5.0.3", "gulp-imagemin": "^5.0.3",
"gulp-insert": "^0.5.0",
"gulp-newer": "^1.3.0",
"gulp-notify": "^3.0.0",
"gulp-plumber": "^1.1.0", "gulp-plumber": "^1.1.0",
"gulp-postcss": "^8.0.0", "gulp-postcss": "^8.0.0",
"gulp-pretty-html": "^2.0.9", "gulp-pretty-html": "^2.0.9",
"gulp-pug": "^4.0.1", "gulp-pug": "^4.0.1",
"gulp-pug-lint": "git+https://github.com/nicothin/gulp-pug-lint.git",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-replace": "^1.0.0", "gulp-replace": "^1.0.0",
"gulp-sass": "^4.0.1", "gulp-sass": "^4.0.1",
"gulp-size": "^3.0.0",
"gulp-sourcemaps": "^2.4.1", "gulp-sourcemaps": "^2.4.1",
"gulp-svgmin": "^2.1.0", "gulp-svgmin": "^2.1.0",
"gulp-svgstore": "^7.0.0", "gulp-svgstore": "^7.0.0",
"gulp-uglify": "^3.0.0", "gulp-uglify": "^3.0.0",
"gulp-wait": "0.0.2",
"gulp.spritesmith": "^6.3.0", "gulp.spritesmith": "^6.3.0",
"husky": "^1.1.4", "husky": "^1.1.4",
"json-format": "^1.0.1", "json-format": "^1.0.1",
...@@ -72,13 +62,15 @@ ...@@ -72,13 +62,15 @@
"lint-staged": "^8.0.4", "lint-staged": "^8.0.4",
"merge-stream": "^1.0.1", "merge-stream": "^1.0.1",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"path": "^0.12.7",
"postcss-import": "^12.0.1", "postcss-import": "^12.0.1",
"postcss-inline-svg": "^3.0.0", "postcss-inline-svg": "^3.0.0",
"postcss-object-fit-images": "^1.1.2", "postcss-object-fit-images": "^1.1.2",
"stylelint": "^9.1.1", "stylelint": "^9.1.1",
"through2": "^3.0.0", "through2": "^3.0.0",
"vinyl-buffer": "^1.0.1", "vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0" "webpack": "^4.27.1",
"webpack-stream": "^5.2.1"
}, },
"dependencies": { "dependencies": {
"baron": "^3.0.3", "baron": "^3.0.3",
......
{
"blocks": {
"page": [],
"typo": [],
"sprite-svg": [],
"sprite-png": [
"__demo"
],
"page-header": [],
"page-footer": [],
"logo": [],
"main-nav": [],
"close": [],
"burger": [],
"code": [],
"thumb": [],
"alert": [],
"menu": [],
"label": [],
"loader": [],
"table": [],
"table-responsive": [],
"pagination": [],
"breadcrumbs": [],
"progress": [],
"pie-chart": [],
"embed-responsive": [],
"comment": [],
"tooltip": [],
"btn": [],
"field-text": [
"--error"
],
"field-checkbox": [
"__input-wrap--error"
],
"field-radio": [
"__input-wrap--error"
],
"field-toggler": [],
"field-file": [
"--error"
],
"field-range": [],
"field-select": [
"--error"
],
"field-actions": [],
"fields-group": [],
"form": [],
"is-mobile": [],
"scroll-link": [],
"to-top": [],
"dropdown": [],
"owl-carousel": [],
"swipe": [],
"nouislider": [],
"off-canvas": [],
"modal": [],
"tabs": [],
"object-fit-polyfill": [],
"or": [],
"baron": [],
"blocks-library": []
},
"addCssBefore": [
"./src/scss/functions.scss",
"./src/scss/variables.scss",
"./src/scss/mixins.scss",
"../../node_modules/owl.carousel/dist/assets/owl.carousel.css",
"../../node_modules/nouislider/distribute/nouislider.css"
],
"addCssAfter": [
"./src/scss/print.scss"
],
"singleCompiled": [
"./src/scss/blocks-library.scss"
],
"addJsBefore": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery-migrate/dist/jquery-migrate.min.js",
"./node_modules/svg4everybody/dist/svg4everybody.js",
"./node_modules/ismobilejs/dist/isMobile.min.js",
"./node_modules/owl.carousel/dist/owl.carousel.js",
"./node_modules/swipejs/build/swipe.min.js",
"./node_modules/nouislider/distribute/nouislider.js",
"./node_modules/object-fit-images/dist/ofi.js",
"./node_modules/baron/baron.min.js"
],
"addJsAfter": [
"./src/js/global-script.js"
],
"addImages": [
"./src/img/*.{jpg,jpeg,gif,png,svg,ico}"
],
"copiedCss": [],
"copiedJs": [],
"dirs": {
"srcPath": "./src/",
"buildPath": "./build/",
"blocksDirName": "blocks"
}
}
\ No newline at end of file
...@@ -16,9 +16,6 @@ block header ...@@ -16,9 +16,6 @@ block header
block content block content
h1 Заголовок с каким-то эффектом h1 Заголовок с каким-то эффектом
p Содержимое. #[a(href='blocks-demo.html') Библиотека блоков]. p Содержимое. #[a(href='blocks-demo.html') Библиотека блоков].
.row
.closess
.alertfgdf
block footer block footer
+page-footer() +page-footer()
......
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