Commit d49c925b authored by Nikolay Gromov's avatar Nikolay Gromov

Пилю автоматизацию (не завершено)

parent 2a343e3d
build/*
!build/readme.md
design/
src/blocks/sprite-svg--localstorage/img/*.svg
src/docs-files/docs.css
src/blocks/sprite-svg/img/*.svg
.Saved/
_arc/
......
......@@ -40,7 +40,7 @@
## Парадигма
- Используется именование классов, файлов и переменных по БЭМ.
- Список использованных в проекте БЭМ-блоков и оп. файлов указан в `./package.json`.
- Список использованных в проекте БЭМ-блоков и доп. файлов указан в `./package.json`.
- Каждый БЭМ-блок в своей папке внутри `./src/blocks/` (стили, js, картинки, разметка; обязателен только стилевой файл).
- Есть глобальные файлы: стилевые, js, шрифты, картинки.
- Диспетчер подключения стилей `./src/scss/style.scss` генерируется автоматически при старте любой gulp-задачи.
......@@ -48,6 +48,12 @@
### Стили
Файл-диспетчер подключений (`.src/scss/style.scss`) формируется автоматически на основании указанных в `./package.json` блоков и доп. файлов.
### Блоки
Каждый блок лежит в `./src/blocks/` в своей папке. Каждый блок — как минимум, папка и одноимённый scss-файл.
......@@ -82,7 +88,7 @@ node createBlock.js new-block js pug # создаст папку блока, new
## Подключение блоков
### Подключение блоков
Настройки подключаемых файлов указаны в `./package.json`, в секции `configProject`:
......
......@@ -4,18 +4,20 @@
const fs = require('fs');
const gulp = require('gulp');
const gulpSequence = require('gulp-sequence');
const sass = require('gulp-sass');
const browserSync = require('browser-sync').create();
const postcss = require('gulp-postcss');
const autoprefixer = require("autoprefixer")
const mqpacker = require("css-mqpacker")
const cleanss = require('gulp-cleancss');
const notify = require('gulp-notify');
const gulpIf = require('gulp-if');
const debug = require('gulp-debug');
const sourcemaps = require('gulp-sourcemaps');
const cleanss = require('gulp-cleancss');
const rename = require('gulp-rename');
const size = require('gulp-size');
const del = require('del');
const newer = require('gulp-newer');
// Получим настройки проекта из package.json
let pjson = require('./package.json');
......@@ -34,6 +36,14 @@ fs.writeFileSync('./src/scss/style.scss', styleImports);
// Запуск `NODE_ENV=production npm start [задача]` приведет к сборке без sourcemaps
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV == 'dev';
// Плагины postCSS, которыми обрабатываются все стилевые файлы
let postCssPlugins = [
autoprefixer({browsers: ['last 2 version']}),
mqpacker({
sort: true
}),
];
// Очистка папки сборки
gulp.task('clean', function () {
console.log('---------- Очистка папки сборки');
......@@ -45,17 +55,14 @@ gulp.task('clean', function () {
// Компиляция стилей
gulp.task('style', function () {
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
console.log('---------- Компиляция стилей');
return gulp.src(dirs.srcPath + 'scss/style.scss')
.pipe(gulpIf(isDev, sourcemaps.init()))
.pipe(debug({title: "Style:"}))
.pipe(sass())
.pipe(postcss([
autoprefixer({browsers: ['last 2 version']}),
mqpacker({
sort: true
}),
]))
.pipe(postcss(postCssPlugins))
.on('error', notify.onError(function(err){
return {
title: 'Styles compilation error',
......@@ -70,10 +77,221 @@ gulp.task('style', function () {
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'))
.pipe(browserSync.stream());
});
// Копирование добавочных CSS, которые хочется иметь отдельными файлами
gulp.task('copy:css', function() {
return gulp.src(pjson.configProject.copiedCss)
.pipe(postcss(postCssPlugins))
.pipe(cleanss())
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/css'));
// .pipe(browserSync.stream());
});
// Копирование изображений
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 () {
console.log('---------- Копирование отдельных JS-файлов');
return gulp.src(pjson.configProject.copiedJs)
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
});
// Копирование шрифтов
gulp.task('copy:fonts', function () {
console.log('---------- Копирование шрифтов');
return gulp.src(dirs.source + '/fonts/*.{ttf,woff,woff2,eot,svg}')
.pipe(newer(dirs.buildPath + '/fonts')) // оставить в потоке только изменившиеся файлы
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/fonts'));
});
// Сборка SVG-спрайта для блока sprite-svg
gulp.task('sprite:svg', function (callback) {
const svgstore = require('gulp-svgstore');
const svgmin = require('gulp-svgmin');
const cheerio = require('gulp-cheerio');
let spritePath = dirs.srcPath + dirs.blocksDirName + '/sprite-svg/svg/';
if(fileExist(spritePath) !== false) {
console.log('---------- Сборка SVG спрайта');
return gulp.src(spritePath + '*.svg')
.pipe(svgmin(function (file) {
return {
plugins: [{
cleanupIDs: {
minify: true
}
}]
}
}))
.pipe(svgstore({ inlineSvg: true }))
.pipe(cheerio(function ($) {
$('svg').attr('style', 'display:none');
}))
.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();
}
});
// Сборка HTML
gulp.task('html', function() {
const fileinclude = require('gulp-file-include');
const replace = require('gulp-replace');
console.log('---------- сборка HTML');
return gulp.src(dirs.srcPath + '/*.html')
.pipe(fileinclude({
prefix: '@@',
basepath: '@file',
indent: true,
}))
.pipe(replace(/\n\s*<!--DEV[\s\S]+?-->/gm, ''))
.pipe(gulp.dest(dirs.buildPath));
});
// Конкатенация и углификация 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(concat('script.min.js'))
.pipe(gulpIf(!isDev, uglify()))
.on('error', notify.onError(function(err){
return {
title: 'Javascript uglify error',
message: err.message
}
}))
.pipe(size({
title: 'Размер',
showFiles: true,
showTotal: false,
}))
.pipe(gulp.dest(dirs.buildPath + '/js'));
}
else {
console.log('---------- Обработка JS: в сборке нет JS-файлов');
callback();
}
});
// Оптимизация изображений // 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({
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
}))
.pipe(gulp.dest(folder));
}
else {
console.log('---------- Оптимизация картинок: ошибка (не указана папка)');
console.log('---------- Пример вызова команды: folder=src/blocks/block-name/img npm start img:opt');
callback();
}
});
// Сборка всего
gulp.task('build', function (callback) {
gulpSequence(
'clean',
'sprite:svg',
['style', 'copy:css', 'copy:img', 'copy:js', 'copy:fonts'],
'html',
callback);
});
// Локальный сервер, слежение
gulp.task('serve', ['build'], function() {
browserSync.init({
server: dirs.buildPath,
startPath: 'index.html',
open: false,
});
// Слежение за стилями
gulp.watch([
dirs.srcPath + dirs.blocksDirName + '/**/*.scss',
dirs.srcPath + '/scss/**/*.scss',
], function (event) {
gulpSequence('style')(function (err) {
if (err) console.log(err);
})
});
// Слежение за html
gulp.watch([
dirs.srcPath + '/*.html',
dirs.srcPath + '/_include/*.html',
dirs.srcPath + dirs.blocksDirName + '/**/*.html',
], function (event) {
gulpSequence('html', browserSync.reload())(function (err) {
if (err) console.log(err);
})
});
// Слежение за изображениями
if(lists.img) {
gulp.watch(lists.img, function (event) {
gulpSequence('copy:img', browserSync.reload())(function (err) {
if (err) console.log(err);
})
});
}
});
// Отправка в GH pages (ветку gh-pages репозитория)
// gulp.task('deploy', function() {
// console.log('---------- Публикация ./build/ на GH pages');
// console.log('---------- '+ ghPagesUrl);
// return gulp.src('./build/**/*')
// .pipe(ghPages());
// });
// Задача по умолчанию
gulp.task('default',
gulpSequence(['serve'])
);
/**
......@@ -115,9 +333,23 @@ function getFilesList(config){
// Images
for (let blockName in config.blocks) {
res.img.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/img');
res.img.push(config.dirs.srcPath + config.dirs.blocksDirName + '/' + blockName + '/img/*.{jpg,jpeg,gif,png,svg}');
}
res.img = config.addImages.concat(res.img);
return res;
}
/**
* Проверка существования файла или папки
* @param {string} path Путь до файла или папки]
* @return {boolean}
*/
function fileExist(path) {
const fs = require('fs');
try {
fs.statSync(path);
} catch(err) {
return !(err && err.code === 'ENOENT');
}
}
......@@ -20,14 +20,17 @@
"./src/scss/print.scss"
],
"addJsBefore": [
"./src/js/jquery.3.1.1.min.js"
"./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/"
"./src/img/*.{jpg,jpeg,gif,png,svg}"
],
"copiedCss": [],
"copiedJs": [],
"dirs": {
"srcPath": "./src/",
"buildPath": "./build/",
......@@ -42,19 +45,33 @@
},
"devDependencies": {
"autoprefixer": "^6.7.7",
"browser-sync": "^2.18.8",
"const": "^1.0.0",
"cross-env": "^3.2.4",
"css-mqpacker": "^5.0.1",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-cheerio": "^0.6.2",
"gulp-cleancss": "^0.2.2",
"gulp-concat": "^2.6.1",
"gulp-debug": "^3.1.0",
"gulp-file-include": "^1.0.0",
"gulp-if": "^2.0.2",
"gulp-imagemin": "^3.1.1",
"gulp-newer": "^1.3.0",
"gulp-notify": "^3.0.0",
"gulp-postcss": "^6.3.0",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.5.4",
"gulp-sass": "^3.1.0",
"gulp-sequence": "^0.4.6",
"gulp-size": "^2.1.0",
"gulp-sourcemaps": "^2.4.1"
"gulp-sourcemaps": "^2.4.1",
"gulp-svgmin": "^1.2.3",
"gulp-svgstore": "^6.1.0",
"gulp-uglify": "^2.1.0",
"imagemin-pngquant": "^5.0.0",
"jquery": "^3.1.1",
"jquery-migrate": "^3.0.0"
}
}
// В этом файле должны быть стили только для БЭМ-блока page-header, его элементов,
// В этом файле должны быть стили только для БЭМ-блока page-header, его элементов,
//модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Не пишите здесь другие селекторы.
.page-header {
display: block;
}
body {
// background-color: #ff0;
}
# SVG-спрайт с использованием символов
Из файлов папки `svg/` в папку `img/` будет сгенерирован файл спрайта `sprite-svg--ls.svg`.
Если less-файл импортирован, то в сборку будет взят `sprite-svg--localstorage.js` и изображения из `img/` будут скопированы в папку сборки, можно использовать спрайт.
**ВНИМАНИЕ: При начале новой разработки на localhost не забудьте стереть записи `inlineSVGdata` и `inlineSVGrev` из localStorage!**
## Как это работает
После загрузки страницы срабатывает JS, который проверяет: есть ли в localStorage запись с текстом спрайта. Если есть, текст спрайта вставляется после открывающего `body`, если нет, JS делает асинхронный запрос на сервер, получает файл спрайта, пишет его в localStorage и потом вставляет на страницу.
В JS-файле есть переменная с ревизией спрайта. Если её поменять, произойдёт обновление спрайта в localStorage.
Сам спрайт имеет вид:
```svg
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-1" viewBox="0 0 30 30"><path fill="#444" d="..."/></symbol>
<symbol id="icon-2" viewBox="0 0 28 28"><path fill="#444" d="..."/></symbol>
</svg>
```
Для вставки на страницу используйте конструкции `svg > use` со ссылками на `id` символа:
```html
<svg width="30" height="30"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-1"></use></svg>
```
Работает только в условиях работы localStorage! (При запросе страниц с сервера).
## Другие похожие варианты
1. [Ещё пример использования SVG-спрайта](http://codepen.io/nicothin/pen/qbmwNP?editors=1100) (вставка скрытого SVG со спрайтом происходит не JS-ом, а простой вставкой в разметку).
2. Инклуд файла спрайта в разметку при сборке html: `@@include('blocks/sprite-svg--localstorage/img/sprite-svg--ls.svg')`
// На самом деле, это не БЭМ-блок, но чтобы спрайт и JS-файл попали в сборку, в диспетчере подключений импортируется этот файл и он не пустой.
# SVG-спрайт с использованием символов
Из файлов папки `svg/` в папку `img/` будет сгенерирован файл спрайта `sprite-svg.svg`.
Сам спрайт имеет вид:
```svg
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-1" viewBox="0 0 30 30"><path fill="#444" d="..."/></symbol>
<symbol id="icon-2" viewBox="0 0 28 28"><path fill="#444" d="..."/></symbol>
</svg>
```
Для вставки на страницу используйте конструкции `svg > use` со ссылками на `id` символа:
```html
<svg width="30" height="30"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-1"></use></svg>
```
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31.494 31.494">
<path d="M10.273 5.01c.444-.445 1.143-.445 1.587 0 .43.428.43 1.142 0 1.57l-8.047 8.047h26.554c.62 0 1.127.492 1.127 1.11 0 .62-.508 1.128-1.127 1.128H3.813l8.047 8.032c.43.444.43 1.16 0 1.587-.444.444-1.143.444-1.587 0L.32 16.532c-.428-.43-.428-1.143 0-1.57l9.953-9.953z" fill="#1E201D"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31.49 31.49">
<path d="M21.205 5.007c-.43-.444-1.143-.444-1.587 0-.43.43-.43 1.143 0 1.57l8.047 8.048H1.11c-.618 0-1.11.493-1.11 1.112 0 .62.492 1.127 1.11 1.127h26.555l-8.047 8.032c-.43.444-.43 1.16 0 1.587.444.444 1.16.444 1.587 0l9.952-9.952c.444-.426.444-1.14 0-1.57l-9.952-9.95z" fill="#1E201D"/>
</svg>
Дополнительные CSS-файлы, которые отчего-то, «не тянут» на полноценные БЭМ-блоки.
Укажите эти файлы в `package.json` для попадания их в обработку.
@import url(./src/css/variables.css);
@import url(./src/blocks/page-header/page-header.css);
@import url(./src/blocks/page-footer/page-footer.css);
@import url(./src/blocks/page-footer/page-footer__inner.css);
@import url(./src/blocks/page-footer/page-footer--some-mod.css);
@import url(./src/css/print.css);
:root {
--black: hsl(0, 0%, 0%);
--gray-darkest: hsl(0, 0%, 10%);
--gray: hsl(0, 0%, 10%);
--text-color: var(--gray-darkest, hsl(0, 0%, 10%));
}
Шрифты проекта. Будут автоматически скопированы в папку сборки.
Изображения из корня этой папки будут скопированы в папку сборки и оптимизированы. Подпапки игнорируются.
Какие-то общие изображения проекта (контентные, к примеру).
Укажите эту папку в `package.json` для попадания графических файлов в обработку.
// Свой код с jQuery
// $( document ).ready(function() {
// });
This diff is collapsed.
# Javascript
Файлы из этой папки предполагается конкатенировать в один и сжимать. Очередность конкатенации определяется в `gulpfile.js` вручную.
Дополнительные JS-файлы, которые отчего-то, «не тянут» на полноценные БЭМ-блоки.
**ВНИМАНИЕ!** По умолчанию из этой папки в сборку берется только `global-script.js`.
## Если нужно добавить какие-то JS-файлы
Создайте блок в папке `src/` и подключите less-файл этого блока в диспетчере подключений. Очередность подключения js-файлов блоков определяется очередностью подключений less-файлов блоков.
Укажите эти файлы в `package.json` для попадания их в обработку.
......@@ -3,3 +3,8 @@
* Не пишите сюда ничего вручную, все такие правки будут потеряны.
* Читайте ./README.md для понимания.
*/
@import "./src/scss/variables.scss";
@import "./src/blocks/page-header/page-header.scss";
@import "./src/blocks/page-footer/page-footer.scss";
@import "./src/scss/print.scss";
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