В этом документе описан наш gulp файл который мы используем в ежедневной работе над простыми проектами. Он постоянно меняется и дополняется под наши нужды. Описываем в первую очередь для себя и надеемся что кому-то будет полезно.

Цель нашего gulp файла - быть простым и гибким, легко изменяться и быть понятным.

Стек используемых технологий: sass twig browser-sync imagemin autoprefixer

Архитектура проекта

front
├── pages
│	├── fonts
│	│   └── Roboto_mono
│	├── img
│	│   ├── logo.png
│	│   └── logo.webp
│	├── index.html
│	├── main.min.js
│	├── pages.html
│	├── style.css
│	└── svg
├── src
│	├── assets
│	│   ├── img
│	│   │   └── logo.png
│	│   ├── js
│	│   │   ├── jquery.min.js
│	│   │   ├── main.js
│	│   │   └── validator.js
│	│   ├── scss
│	│   │   ├── base
│	│   │   │   ├── default.scss
│	│   │   │   ├── fonts.scss
│	│   │   │   ├── mixins.scss
│	│   │   │   ├── normalize.scss
│	│   │   │   ├── typography.scss
│	│   │   │   └── variables.scss
│	│   │   └── style.scss
│	│   └── svg
│	│	└── ... все svg
│	├── blocks
│	│   ├── footer
│	│   │   ├── footer.twig
│	│   │   └── footer.scss
│	│   └── header
│	│       ├── header.twig
│	│       └── header.scss
│	├── layouts
│	│   └── layout.twig
│	├── custom-page
│	│   ├── custom-page.twig
│	│   └── custom-page.scss
│	├── index.twig
│	└── pages.twig
├── babel.config.json
├── package.json
└── gulp.js

Проект состоит из двух основных папок pages и src в первой хранится результат сборки(туда лезть не стоит) в src хранятся исходники, то место где происходит сама работа.

Src/assets

Картинки, svg, общий js, общий scss
s
css хранится в папке src/assets/scss - основной файл style.scss в нем подключаются все стили компонент (да - это делается в ручную так как важен порядок).

Src/assets/scss/base

  • default.scss
    Основные глобальные стили, по умолчанию прописан контейнер
  • fonts.scss
    Подключение всех шрифтов проекта, по умолчанию пусто - комментарий с примером правильного подключения. Сервис для конвертирования шрифтов - Online Font Converter
  • mixins.scss
    Файл для миксинов - по умочанию миксин для адаптивной разработки
  • normalize.scss
    Стандартный normalize убирающий дефолтные стили браузеров
  • typography.scss
    Прописываем дефолтные стили для всех инлайновых элементов
  • variables.scss
    Файл переменных, по умолчанию набор часто используемых переменных

Src/assets/svg

Мы не используем спрайты, храним все svg в отдельной папке, подключаются svg с помощью twig include. Все svg минифицируются и кладутся в pages.

Src/blocks

Папка содержит все блоки/компоненты , каждый компонент хранится в своей папке. Пример:

blocks
blocks
└── footer
	├── footer.twig
	├── footer.js
	└── footer.scss

Все относящееся к компоненту должно храниться в папке компонента. Js всех компонент собирается в min файл /pages/main.min.js

Src/layouts

Папка содержит шаблоны проекта, которые наследуются страницами {% extends "layouts/layout.twig" %} по умолчанию имеем стандартный шаблон с подключенными стилями и js и размеченными блоками под контент.

Страницы

Страницы хранятся в корне проекта - как twig файл (если это простая страница) либо как папка, пример:

├── custom-page
│   ├── custom-page.twig
│   └── custom-page.scss
├── index.twig

Таск sass

В этом таске мы превращаем scss в css и кладем его в один файл src/assets/scss/style.scss предварительно объединяем медиа запросы и минифицируем итоговый css с помощью clean-css. Ну и в конце обновляем браузер.

gulp.task('sass', () =>
{
  return gulp.src('src/assets/scss/style.scss')
    .pipe(sass({includePaths: ['src/']}).on('error', sass.logError))
    .pipe(autoprefixer(['last 10 versions', '> 1%'], {cascade: true}))
    .pipe(gcmq())
    .pipe(cleanCSS())
    .pipe(gulp.dest('pages'))
    .pipe(browserSync.reload({stream: true}));
});

Таск scripts 

В этом таске мы проходимся по всем js файлам прогоняем их через babel объединяем минифицируем и кладем в pages/main.min.js

var jsFiles = ['src/assets/js/*.js', 'src/**/*.js'];

// таск для объединения js файлов
gulp.task('scripts', () =>
{
  process.env.NODE_ENV = "release";
  return gulp.src(jsFiles)
    .pipe(babel())
    .pipe(concat('main.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest('pages'))
    .pipe(browserSync.reload({stream: true}));
});

Таск twig

Запуск шаблонизатора, проходимся по всем twig файлам кроме /src/pages.twig и кладет результат в pages/. В конце обновляется страница.

const htmlbeautifyOptions = {
  indentSize: 4,
  unformatted: [
    'abbr', 'area', 'b', 'bdi', 'bdo', 'br', 'cite',
    'code', 'data', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'ins', 'kbd', 'keygen', 'map', 'mark', 'math', 'meter', 'noscript',
    'object', 'output', 'progress', 'q', 'ruby', 's', 'samp', 'small',
    'strong', 'sub', 'sup', 'template', 'time', 'u', 'var', 'wbr', 'text',
    'acronym', 'address', 'big', 'dt', 'ins', 'strike', 'tt', 'a'
  ],
  "indent_level": 1,
  "indent_with_tabs": true,
};

gulp.task('twig', function ()
{
  return gulp.src(['./src/*.twig','!./src/pages.twig'])
    .pipe(plumber())
    .pipe(twig({base:'./src/'}))
    .pipe(htmlbeautify(htmlbeautifyOptions))
    .pipe(gulp.dest("pages/",))
    .pipe(browserSync.reload({stream: true}));
});

Таск browser-sync

Синхронизирует работу браузера. Помогает обновлять браузер при изменении файлов.

gulp.task('browser-sync', () =>
{
  browserSync({
    server: {baseDir: './pages/'},
    startPath: './index.html',
    serveStaticOptions: {extensions: ["html"] },
    ghostMode: {scroll: false },
    notify: false,
  });
});

Таск img

Таск сжимает картинки формата png и jpg находящиеся в папке src/assets/img/ без потери качества. Конвертирует их в формат webp и переносит сжатый вариант и webp в папку pages/img/.

gulp.task('img', function()
{
  return gulp.src(['src/assets/img/*.png', 'src/assets/img/*.jpg']) // откуда брать картинки
    .pipe(imagemin([imagemin.gifsicle(), imagemin.optipng(), imagemin.svgo() ]))
    .pipe(gulp.dest('pages/img/'))
    .pipe(webp())
    .pipe(gulp.dest('pages/img/'));
});

Таск svg-min

Таск обрабатывает все svg файлы находящие в папке src/assets/svg/ с помощью gulp-svgmin, оптимизирует их и удаляет лишние свойства и переносит файлы в pages/svg.

Список всех плагинов для оптимизатора gulp-svgmin

gulp.task('svg-min', () =>
{
  return gulp.src('src/assets/svg/*.svg')
    .pipe(
      svgmin(file =>
      {
        const { relative } = file;
        const prefix = path.basename(relative, path.extname(relative));
        return {
          js2svg: {pretty: true, },
          plugins: [
            {cleanupIDs: { prefix: '${prefix}-' + Math.floor(Math.random() * (100 - 10)) + 10 }, },
            {removeDoctype: true, },
            {removeXMLProcInst: true, },
            {removeViewBox: false },
            {removeTitle: true, },
            {removeDesc: { removeAny: true }, },
            {convertTransform: {}, },
          ],
        };
      }))
    .pipe(
      cheerio({
        run: ($, file) =>
        {
          const $clipPath = $('clipPath');
          const $mask = $('mask');
          let $defs = $('defs');
          const hasClipPath = $clipPath.length > 0;
          const hasMask = $mask.length > 0;
          const hasDefs = $defs.length > 0;

          if (!hasClipPath && !hasMask) return;

          if (!hasDefs)
          {
            $defs = $('');
            $defs.prependTo('svg');
          }

          function copyToDefs(i, el)
          {
            const $el = $(el);
            const $clone = $el.clone();
            $clone.appendTo($defs);
            $el.remove();
          }
          if (hasClipPath) $clipPath.each(copyToDefs);
          if (hasMask) $mask.each(copyToDefs);
        },
        parserOptions: {xmlMode: true, },
      })
    )
    .pipe(gulp.dest('pages/svg'));
});

Таск build

Запускает другие таски для финальной сборки проекта.

gulp.task('build', gulp.series('svg-min', 'sass', 'twig', 'scripts', 'img', async () => { console.log('builded');}));

Таск pages-list

Таск собирает список путей ко всем страницам (html файлам) из папки pages/ кроме pages/pages.html, собирает из него массив состоящий из названий фалов и передает этот массив в src/pages.twig. В этом файле мы проходимся циклом по массиву и выводим список всех имен страниц для удобной навигации по страницам людям которые будут тестировать верстку. Дальше этот файл переносится через gulp-twig в папку pages.

За место http://localhost:3000/ пишем свой необходимый путь или домен.

// фрагмент из файла src/pages.twig
{% for page in fileList %}
      <li>
            {{ page }}
      </li>
{% endfor %}

gulp.task('pages-list', () =>
{
    let fileList = [];
    let pathSetting = ['./pages/*.html', '!./pages/pages.html'];
    return gulp.src(pathSetting)
      .pipe(map(function(file, cb)
      {
        var f = file.path.replace(file.cwd, '.');
        fileList.push((f).substr((f).lastIndexOf('/') + 1,(f).lastIndexOf('.') - 1));
        cb(null, null);
      }))
      .on('end', () =>
      {
        gulp.src('./src/pages.twig')
          .pipe(
            twig({
              base:'./src/',
              data: { fileList: fileList }
            })
          )
          .pipe(gulp.dest('./pages/'));
      });
});

Таск watch

Таск следит за изменениями файлов и вызывает другие таски.

gulp.task('watch', function()
{
    gulp.watch(['scss/**/*.scss','src/**/*.scss'], gulp.parallel('sass'));
    gulp.watch('src/**/*.twig', gulp.parallel('twig'));
    gulp.watch('src/**/*.twig', gulp.parallel('pages-list'));
    gulp.watch(['src/**/*.js'], gulp.parallel('scripts'));
    gulp.watch('src/**/*.js', gulp.parallel(() => { browserSync.reload(); }));
    gulp.watch('img/*', gulp.parallel(() => { browserSync.reload(); }));
});

Таск default

Таск по умолчанию. Запускается при вводе в терминал gulp. Запускает локальный сервер http://localhost:3000/ и другие таски для разработки в реальном времени и сборки проекта. В нем используются другие таски которые перезагружают локальный сервер по необходимости, например при изменении и сборке js файлов.

gulp.task('default', gulp.parallel('watch', 'browser-sync', 'sass', 'twig', 'svg-min', 'pages-list', 'scripts',  () => { console.log('dev start');}));

Share with friends:

Facebook Twitter Vkontakte