Современная cборка Gulp — ES-модули, Git — 2 часть

В предыдущей статье (Современная cборка Gulp для веб-разработки) мы создали самую простую сборку Gulp. Продолжим её совершенствовать.

Подготовка к сохранению в репозиторий Git

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

Подробнее о Git и Git Bash смотрите в статьях:
Основные команды Git Bash
30 основных команд Git для управление репозиториями GitHub

Создадим в корне проекта файл README.md в котором будет описание нашей сборки:

#Современная cборка Gulp для веб-разработки

И файл .gitignore где мы укажем какие файлы и папки не нужно сохранять в репозиторий (подробнее о .gitignore) :

/node_modules
/dist
package-lock.json

Мы подготовили сборку для сохранения в репозиторий.

Cтруктура проeкта

Для удобства работы при добавлении плагинов и измененииях сборки создадим отдельные файлы под разные задачи. Для этого создаим в корне проекта папку gulp а в ней папки
config — для файлов отвечающих за конфигурацию и
tasks — для задач

Теперь структура проекта будет выглядеть так:

project                # Папка проекта
│
├── gulp                   
│   ├── config         # файлы отвечающие за конфигурацию   
│   └── tasks          # задачи
│
├───src                # ИСХОДНИКИ
│   ├─── scss
│   │    └── style.scss
│   ├─── js
│   │    └── app.js
│   └─── index.html
│
├── .gitignore         # "игнор" для Git
├── gulpfile.js        # файл с настройками Gulp
├── package.json       # файл с настройками сборки и установленными пакетами
└── README.md          # документация сборки

Настройка путей

Для удобной работы с файлами и папками запишем основные пути в переменную. Для этого создадим файл gulp/config/paths.mjs

export const paths = {  // Пути к файлам
  styles: {
   src: './src/scss/**/*.scss',
   dest: './dist/css'
  },
  scripts: {
   src: './src/js/**/*.js',
   dest: './dist/js'
  },
  html: {
   src: './src/**/*.html',
   dest: './dist'
  }
};

Импортируем переменную (paths)  с путями в основной файл настроек gulpfile.js

import { paths } from './gulp/config/paths.mjs'; // Импорт путей

(Не забудте удалить ранее прописанные «Пути к файлам»)

Для доступности этой и некоторых других переменных (которые объявим позже) в файле gulpfile.js создадим глобальную переменную:

// Глобальная переменная
global.app = {
  paths: paths,
}

Теперь мы можем настраивать пути в отдельном месте и использовать их в любом файле сборки.

Подключение плагинов

Для часто используемых плагинов подключим их в отдельном ES-модуле — файле gulp/config/plugins.mjs

import sourcemaps from 'gulp-sourcemaps';

export const plugins = {
   sourcemaps: sourcemaps,
}

Как и в предыдущем пункте импортируем переменную (plugins) в основной файл настроек gulpfile.js и добавляем к глобальной переменной:

import { plugins } from './gulp/config/plugins.mjs'; // Импорт плагинов
// Глобальная переменная 
global.app = { 
  paths: paths,
  plugins: plugins, 
}

Отредактируем файл gulpfile.js удалив импорт перенесённых плагинов (сейчас это import sourcemaps from 'gulp-sourcemaps';)
И подключив их через глобальную переменную (меняем sourcemaps на app.plugins.sourcemaps).

Должно получиться так:

import gulp from 'gulp';
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import autoprefixer from 'gulp-autoprefixer';
import cleanCSS from 'gulp-clean-css';
import uglify from 'gulp-uglify';
import concat from 'gulp-concat';

import browserSync from 'browser-sync';

import { paths } from './gulp/config/paths.mjs'; // Импорт путей
import { plugins } from './gulp/config/plugins.mjs'; // Импорт плагинов

const sass = gulpSass(dartSass);
const server = browserSync.create();

// Глобальная переменная
global.app = {
  paths: paths,
  plugins: plugins,
}

// Компиляция SCSS в CSS
export function styles() {
return gulp.src(app.paths.styles.src, { sourcemaps: true })
.pipe(app.plugins.sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(autoprefixer())
.pipe(cleanCSS())
.pipe(app.plugins.sourcemaps.write('.'))
.pipe(gulp.dest(app.paths.styles.dest))
.pipe(server.stream());
}

// Минификация и объединение JS файлов
export function scripts() {
return gulp.src(paths.scripts.src, { sourcemaps: true })
.pipe(app.plugins.sourcemaps.init())
.pipe(concat('app.min.js'))
.pipe(uglify())
.pipe(app.plugins.sourcemaps.write('.'))
.pipe(gulp.dest(app.paths.scripts.dest))
.pipe(server.stream());
}

// Копирование HTML файлов
export function html() {
return gulp.src(app.paths.html.src)
.pipe(gulp.dest(app.paths.html.dest))
.pipe(server.stream());
}

// Запуск сервера и отслеживание изменений
export function serve() {
  server.init({
    server: {
    baseDir: './dist'
  }
});
gulp.watch(app.paths.styles.src, styles);
gulp.watch(app.paths.scripts.src, scripts);
gulp.watch(app.paths.html.src, html).on('change', server.reload);
}

// Определение задач
const build = gulp.series(gulp.parallel(styles, scripts, html), serve);

// Экспорт задач
export { build };

// Задача по умолчанию
export default build;

Если плагин используется только в одном модуле, то нет необхобимости подключать его таким способом. Можно подключить непосредственно в том файле, где он нужнен.

Подключение задач с помощью ES-модулей

Похожим образом поступим с задачами, которые поместим в отдельных файлах в папке gulp/tasks. Перенося импорт плагинов в эти модули и импортируя задачи в gulpfile.js.

В результате должна получиться такая конфигурация:

project                  # Папка проекта
│
├── gulp                   
│   ├── config           # файлы отвечающие за конфигурацию
│   │   ├── paths.mjs    # переменная с путями
│   │   └── plugins.mjs  # общие плагины       
│   └── tasks            # задачи
│       ├── html.mjs     # обработка html
│       ├── scripts.mjs  # обработка js
│       ├── serve.mjs    # запуск сервера
│       └── styles.mjs   # обработка scss
│
~

В результате у нас должно получиться:

html.mjs

// Копирование HTML файлов
export function html() {
  return app.gulp.src(app.paths.html.src)
    .pipe(app.gulp.dest(app.paths.html.dest))
    .pipe(app.server.stream());
}

scripts.mjs

import uglify from 'gulp-uglify';
import concat from 'gulp-concat';
// Минификация и объединение JS файлов
export function scripts() {
  return app.gulp.src(app.paths.scripts.src, { sourcemaps: true })
    .pipe(app.plugins.sourcemaps.init())
    .pipe(concat('app.min.js'))
    .pipe(uglify())
    .pipe(app.plugins.sourcemaps.write('.'))
    .pipe(app.gulp.dest(app.paths.scripts.dest))
    .pipe(app.server.stream());
}

serve.mjs

import browserSync from 'browser-sync';

export const server = browserSync.create();
// Запуск сервера
export function serve() {
  server.init({
    server: {
      baseDir: './dist'
    }
  });
}

styles.mjs

import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import autoprefixer from 'gulp-autoprefixer';
import cleanCSS from 'gulp-clean-css';

const sass = gulpSass(dartSass);

// Компиляция SCSS в CSS
export function styles() {
  return app.gulp.src(app.paths.styles.src, { sourcemaps: true })
    .pipe(app.plugins.sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(autoprefixer())
    .pipe(cleanCSS())
    .pipe(app.plugins.sourcemaps.write('.'))
    .pipe(app.gulp.dest(app.paths.styles.dest))
    .pipe(app.server.stream());
}

Основной файл настроек gulpfile.js стал более «изящный»:

import gulp from 'gulp';

import { paths } from './gulp/config/paths.mjs'; // Импорт путей
import { plugins } from './gulp/config/plugins.mjs'; // Импорт плагинов

// Импорт задач
import { styles } from './gulp/tasks/styles.mjs'; // стили
import { scripts } from './gulp/tasks/scripts.mjs'; // скрипты
import { html } from './gulp/tasks/html.mjs'; // html
import { serve, server } from './gulp/tasks/serve.mjs'; // открытие в браузере

// Глобальная переменная
global.app = {
  gulp: gulp,
  paths: paths,
  plugins: plugins,
  server: server,
}

// Отслеживание изменений
function watch() {
  gulp.watch(paths.styles.src, styles);
  gulp.watch(paths.scripts.src, scripts);
  gulp.watch(paths.html.src, html).on('change', server.reload);
}

// Определение сценария задач
const build = gulp.series(gulp.parallel(styles, scripts, html), gulp.parallel(serve, watch));

// Экспорт сценврия
export { build };
 
// Сценарий по умолчанию
export default build;

Заключение

Мы продолжили создавать современную сборку Gulp, используя ES-модули и строгий режим. Эта сборка поможет вам автоматизировать задачи, связанные с компиляцией SCSS, минификацией JavaScript, обработкой HTML и запуском локального сервера. Такая автоматизация значительно ускоряет и упрощает процесс разработки веб-сайтов. Gulp — это мощный инструмент, который позволяет настроить рабочий процесс именно под ваши нужды, делая разработку более эффективной и приятной.

P.S.
Эта сборка осталась простой, но стала более удобной благодаря ES-модулям для дальнейшего её совершенствования, чем мы и займёмся в следующей статье:

Современная cборка Gulp 5 — удаление и копирование — 3 часть